Skip to content

Commit

Permalink
Validate BIP-32-Ed25519 private keys
Browse files Browse the repository at this point in the history
  • Loading branch information
Mrtenz committed May 14, 2024
1 parent ead9845 commit b014de7
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 9 deletions.
13 changes: 11 additions & 2 deletions src/curves/ed25519Bip32.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,18 @@ describe('publicAdd', () => {
});

describe('isValidPrivateKey', () => {
it('returns true for bigint input', () => {
it('returns true for a valid private key', () => {
const { privateKey } = fixtures.cip3[0].nodes.bip39Node;
expect(isValidPrivateKey(privateKey)).toBe(true);
expect(isValidPrivateKey(hexToBytes(privateKey))).toBe(true);
});

it.each([
'0x07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'0x00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000',
'0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000',
])('returns false for an invalid private key', (privateKey) => {
expect(isValidPrivateKey(hexToBytes(privateKey))).toBe(false);
});
});

Expand Down
46 changes: 39 additions & 7 deletions src/curves/ed25519Bip32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
bytesToHex,
hexToBigInt,
remove0x,
assert,
} from '@metamask/utils';
import { mod } from '@noble/curves/abstract/modular';
import { ed25519 } from '@noble/curves/ed25519';
Expand All @@ -21,15 +22,46 @@ export const name = 'ed25519Bip32';
export const secret = stringToBytes('');

/**
* Always returns true.
* For root node derivation, https://github.com/cardano-foundation/CIPs/blob/09d7d8ee1bd64f7e6b20b5a6cae088039dce00cb/CIP-0003/Icarus.md does not mention any cases when the private key is invalid.
* For child node derivation, https://input-output-hk.github.io/adrestia/static/Ed25519_BIP.pdf does not mention any cases when the private key is invalid.
* Get a byte from a private key at a given index.
*
* @param _privateKey - The private key to check.
* @returns True.
* @param privateKey - The private key.
* @param index - The index of the byte to get.
* @returns The byte at the given index.
* @throws If the private key is too short.
*/
function getByte(privateKey: Uint8Array, index: number): number {
const byte = privateKey[index];
assert(byte !== undefined, 'Private key is too short.');

return byte;
}

/**
* Check if a private key is valid.
*
* @param privateKey - The private key to check.
* @returns Whether the private key is valid.
*/
export const isValidPrivateKey = (_privateKey: Uint8Array | string | bigint) =>
true;
export const isValidPrivateKey = (privateKey: Uint8Array) => {
/* eslint-disable no-bitwise */
// Lowest 3 bits of the first byte must be zero
if (getByte(privateKey, 0) & 0b00000111) {
return false;
}

// The highest bit of the last byte must be zero
if (getByte(privateKey, 31) & 0b10000000) {
return false;
}

// The second highest bit of the last byte must be one
if (!(getByte(privateKey, 31) & 0b01000000)) {
return false;
}
/* eslint-enable no-bitwise */

return true;
};

export const deriveUnhardenedKeys = true;

Expand Down

0 comments on commit b014de7

Please sign in to comment.