Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate BIP-32-Ed25519 private keys #172

Merged
merged 2 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) !== 0) {
return false;
}

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

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

return true;
};

export const deriveUnhardenedKeys = true;

Expand Down
Loading