Skip to content

Commit

Permalink
fix: correct MAX_NONCE
Browse files Browse the repository at this point in the history
  • Loading branch information
70nyIT committed Feb 19, 2024
1 parent 3341ea0 commit a9e564a
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 14 deletions.
19 changes: 11 additions & 8 deletions src/generateEphemeralPrivateKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function generateEphemeralPrivateKey({
coinType,
}: {
viewingPrivateKeyNode: HDKey;
nonce: number;
nonce: bigint;
chainId?: number;
coinType?: number;
}): { ephemeralPrivateKey: `0x${string}` } {
Expand Down Expand Up @@ -55,16 +55,19 @@ export function generateEphemeralPrivateKey({
// the server then generates pseudo-random addresses by incrementing n
// since each value cannot be larger than 2^31 - 1 (see HARDENED_OFFSET - 0x7FFFFFF)
// we therefore introduce a parent nonce p to allow for more addresses to be generated.
// If the nonce is bigger than n, we put the overflow part into a parentNonce. To simplify
// the creation of parentNonce, we set MAX_N to be 0xFFFFFFF. With this schema the combination of nonce
// and parent nonce has a max value of 0x7FFFFFFFFFFFFFF = 576460752303423487₁₀
// If the nonce is bigger than MAX_NONCE, we put the overflow part into a parentNonce. To simplify
// the creation of parentNonce, we set MAX_NONCE to be 0xFFFFFFF. With this schema the combination of nonce
// and parent nonce has a max value of 0x7FFFFFFFFFFFFFF-1 = 576460752303423486₁₀

// Split the nonce into two parts to ensure no number above 0x80000000 is used in the derivation path
const MAX_NONCE = 0xfffffff;
let parentNonce = 0;
if (nonce >= BigInt(0x7FFFFFFFFFFFFFF)) {
throw new Error('Nonce is too large. Max value is 0x7FFFFFFFFFFFFFF.');
}
const MAX_NONCE = BigInt(0xfffffff);
let parentNonce = BigInt(0);
if (nonce > MAX_NONCE) {
parentNonce = Math.floor(nonce / (MAX_NONCE + 1));
nonce = nonce % (MAX_NONCE + 1);
parentNonce = nonce / (MAX_NONCE + BigInt(1));
nonce = nonce % (MAX_NONCE + BigInt(1));
}

// Create the derivation path
Expand Down
2 changes: 2 additions & 0 deletions src/predictStealthSafeAddress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { SafeVersion } from './predictStealthSafeAddressTypes';
* @param useDefaultAddress {boolean} (optional) if true, the Safe default address will be used - see DefaultAddress inside https://github.com/safe-global/safe-deployments
* @param chainId {number} (optional) the chainId of the network where the Safe will be deployed
* @param transport (optional) a custom viem transport to use for the simulation
* @param safeVersion {SafeVersion} the Safe version to use
* @return Promise<{ stealthSafeAddress }> the predicted Safe address (not deployed)
*/
export async function predictStealthSafeAddressWithClient({
Expand Down Expand Up @@ -175,6 +176,7 @@ export function predictStealthSafeAddressWithBytecode({
* @param stealthAddresses {string[]} the stealth addresses controlling the Safe
* @param chainId {number} (optional) the chainId of the network where the Safe will be deployed
* @param useDefaultAddress {boolean} (optional) if true, the Safe default address will be used - see DefaultAddress inside https://github.com/safe-global/safe-deployments
* @param safeVersion {SafeVersion} the Safe version to use
*/
function getSafeInitializerData ({
chainId,
Expand Down
22 changes: 16 additions & 6 deletions test/generateEphemeralPrivateKey.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('generateEphemeralPrivateKey', () => {

const { ephemeralPrivateKey } = generateEphemeralPrivateKey({
viewingPrivateKeyNode,
nonce: 0,
nonce: BigInt(0),
chainId: 10,
});

Expand All @@ -23,7 +23,7 @@ describe('generateEphemeralPrivateKey', () => {

const { ephemeralPrivateKey } = generateEphemeralPrivateKey({
viewingPrivateKeyNode,
nonce: 2147483649,
nonce: BigInt(2147483649),
chainId: 10,
});

Expand All @@ -37,7 +37,7 @@ describe('generateEphemeralPrivateKey', () => {

const { ephemeralPrivateKey } = generateEphemeralPrivateKey({
viewingPrivateKeyNode,
nonce: 0,
nonce: BigInt(0),
coinType: 2147483658,
});

Expand All @@ -46,15 +46,25 @@ describe('generateEphemeralPrivateKey', () => {
);
});

// TO-DO throw an error if the nonce is too high
it('should throw an error if the nonce is too high', () => {
const viewingPrivateKeyNode = extractViewingPrivateKeyNode(privateViewingKey);

expect(() =>
generateEphemeralPrivateKey({
viewingPrivateKeyNode,
nonce: BigInt('576460752303423488'),
chainId: 10,
}),
).toThrow('Nonce is too large. Max value is 0x7FFFFFFFFFFFFFF.');
});

it('should throw an error if no coinType or chainId is provided', () => {
const viewingPrivateKeyNode = extractViewingPrivateKeyNode(privateViewingKey);

expect(() =>
generateEphemeralPrivateKey({
viewingPrivateKeyNode,
nonce: 0,
nonce: BigInt(0),
}),
).toThrow('coinType or chainId must be defined.');
});
Expand All @@ -65,7 +75,7 @@ describe('generateEphemeralPrivateKey', () => {
const viewingPrivateKeyNode = extractViewingPrivateKeyNode(randomPrivateViewingKey);
const { ephemeralPrivateKey } = generateEphemeralPrivateKey({
viewingPrivateKeyNode,
nonce,
nonce: BigInt(nonce),
chainId: 10,
});
expect(ephemeralPrivateKey).toMatch(/^0x[0-9a-fA-F]{64}$/);
Expand Down

0 comments on commit a9e564a

Please sign in to comment.