Skip to content

Commit

Permalink
Update tests to always pass curve
Browse files Browse the repository at this point in the history
  • Loading branch information
Mrtenz committed Mar 7, 2023
1 parent bd4ce9b commit 764c7e9
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 14 deletions.
7 changes: 6 additions & 1 deletion src/BIP44Node.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { bytesToHex } from '@metamask/utils';

import { BIP44Node, BIP44PurposeNodeToken } from '.';
import { BIP44Node, BIP44PurposeNodeToken, secp256k1 } from '.';
import fixtures from '../test/fixtures';
import { compressPublicKey } from './curves/secp256k1';
import { createBip39KeyFromSeed, deriveChildKey } from './derivers/bip39';
Expand All @@ -19,6 +19,7 @@ describe('BIP44Node', () => {
it('initializes a new node from a private key', async () => {
const { privateKey, chainCode } = await deriveChildKey({
path: fixtures.local.mnemonic,
curve: secp256k1,
});

// Ethereum coin type node
Expand All @@ -45,6 +46,7 @@ describe('BIP44Node', () => {
it('initializes a new node from JSON', async () => {
const { privateKey, chainCode } = await deriveChildKey({
path: fixtures.local.mnemonic,
curve: secp256k1,
});

// Ethereum coin type node
Expand Down Expand Up @@ -84,6 +86,7 @@ describe('BIP44Node', () => {
it('throws if the depth is invalid', async () => {
const { privateKey, chainCode } = await deriveChildKey({
path: fixtures.local.mnemonic,
curve: secp256k1,
});

await expect(
Expand Down Expand Up @@ -405,6 +408,7 @@ describe('BIP44Node', () => {
async ({ index, publicKey }) => {
const { privateKey, chainCode } = await createBip39KeyFromSeed(
hexStringToBytes(hexSeed),
secp256k1,
);

const node = await BIP44Node.fromExtendedKey({
Expand Down Expand Up @@ -434,6 +438,7 @@ describe('BIP44Node', () => {
async ({ index, address }) => {
const { privateKey, chainCode } = await createBip39KeyFromSeed(
hexStringToBytes(hexSeed),
secp256k1,
);

const node = await BIP44Node.fromExtendedKey({
Expand Down
7 changes: 7 additions & 0 deletions src/SLIP10Node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ describe('SLIP10Node', () => {
it('initializes a new node from a private key', async () => {
const { privateKey, chainCode } = await deriveChildKey({
path: fixtures.local.mnemonic,
curve: secp256k1,
});

const node = await SLIP10Node.fromExtendedKey({
Expand All @@ -35,6 +36,7 @@ describe('SLIP10Node', () => {
it('initializes a new node from a hexadecimal private key and chain code', async () => {
const { privateKey, chainCode } = await deriveChildKey({
path: fixtures.local.mnemonic,
curve: secp256k1,
});

const node = await SLIP10Node.fromExtendedKey({
Expand All @@ -54,6 +56,7 @@ describe('SLIP10Node', () => {
it('initializes a new ed25519 node from a private key', async () => {
const { privateKey, chainCode } = await deriveChildKey({
path: fixtures.local.mnemonic,
curve: ed25519,
});

const node = await SLIP10Node.fromExtendedKey({
Expand Down Expand Up @@ -88,6 +91,7 @@ describe('SLIP10Node', () => {
it('initializes a new node from a public key', async () => {
const { publicKeyBytes, chainCodeBytes } = await deriveChildKey({
path: fixtures.local.mnemonic,
curve: secp256k1,
});

const node = await SLIP10Node.fromExtendedKey({
Expand Down Expand Up @@ -127,6 +131,7 @@ describe('SLIP10Node', () => {
it('initializes a new node from a hexadecimal public key and chain code', async () => {
const { publicKey, chainCode } = await deriveChildKey({
path: fixtures.local.mnemonic,
curve: secp256k1,
});

const node = await SLIP10Node.fromExtendedKey({
Expand All @@ -146,6 +151,7 @@ describe('SLIP10Node', () => {
it('initializes a new node from JSON', async () => {
const node = await deriveChildKey({
path: fixtures.local.mnemonic,
curve: secp256k1,
});

expect(await SLIP10Node.fromJSON(node.toJSON())).toStrictEqual(node);
Expand All @@ -154,6 +160,7 @@ describe('SLIP10Node', () => {
it('initializes a new node from JSON with a public key', async () => {
const { privateKey, chainCode } = await deriveChildKey({
path: fixtures.local.mnemonic,
curve: secp256k1,
});

const node = await SLIP10Node.fromExtendedKey({
Expand Down
16 changes: 12 additions & 4 deletions src/derivation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { bytesToHex } from '@metamask/utils';

import fixtures from '../test/fixtures';
import { HDPathTuple } from './constants';
import { secp256k1 } from './curves';
import { deriveKeyFromPath, validatePathSegment } from './derivation';
import { derivers } from './derivers';
import { privateKeyToEthAddress } from './derivers/bip32';
Expand Down Expand Up @@ -223,31 +224,35 @@ describe('derivation', () => {
let node: SLIP10Node;

/* eslint-disable require-atomic-updates */
node = await bip39Derive({ path: mnemonic });
node = await bip39Derive({ path: mnemonic, curve: secp256k1 });
node = await bip32Derive({
path: `44'`,
node,
curve: secp256k1,
});

node = await bip32Derive({
path: `60'`,
node,
curve: secp256k1,
});

node = await bip32Derive({
path: `0'`,
node,
curve: secp256k1,
});

node = await bip32Derive({
path: `0`,
node,
curve: secp256k1,
});
/* eslint-enable require-atomic-updates */

const keys = await Promise.all(
expectedAddresses.map(async (_, index) => {
return bip32Derive({ path: `${index}`, node });
return bip32Derive({ path: `${index}`, node, curve: secp256k1 });
}),
);

Expand All @@ -258,7 +263,7 @@ describe('derivation', () => {
});

it('throws for invalid inputs', async () => {
const node = await bip39Derive({ path: mnemonic });
const node = await bip39Derive({ path: mnemonic, curve: secp256k1 });
const inputs = [
String(-1),
String(1.1),
Expand All @@ -274,6 +279,7 @@ describe('derivation', () => {
bip32Derive({
path: input,
node,
curve: secp256k1,
}),
).rejects.toThrow(
'Invalid BIP-32 index: The index must be a non-negative decimal integer less than 2147483648.',
Expand All @@ -285,20 +291,22 @@ describe('derivation', () => {
await expect(
bip32Derive({
path: '0',
curve: secp256k1,
}),
).rejects.toThrow(
'Invalid parameters: Must specify a node to derive from.',
);
});

it('throws when trying to derive from a public key node', async () => {
const node = await bip39Derive({ path: mnemonic });
const node = await bip39Derive({ path: mnemonic, curve: secp256k1 });
const publicNode = node.neuter();

await expect(
bip32Derive({
path: `0'`,
node: publicNode,
curve: secp256k1,
}),
).rejects.toThrow(
'Invalid parameters: Cannot derive hardened child keys without a private key.',
Expand Down
22 changes: 19 additions & 3 deletions src/derivers/bip39.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,38 @@ describe('createBip39KeyFromSeed', () => {
'0xea82e6ee9d319c083007d0b011a37b0e480ae02417a988ac90355abd53cd04fc',
);

it('throws if the seed is less than 16 bytes', async () => {
await expect(
createBip39KeyFromSeed(new Uint8Array(15), secp256k1),
).rejects.toThrow(
'Invalid seed: The seed must be between 16 and 64 bytes long.',
);
});

it('throws if the seed is greater than 64 bytes', async () => {
await expect(
createBip39KeyFromSeed(new Uint8Array(65), secp256k1),
).rejects.toThrow(
'Invalid seed: The seed must be between 16 and 64 bytes long.',
);
});

it('throws if the private key is zero', async () => {
// Mock the hmac function to return a zero private key.
jest.spyOn(hmacModule, 'hmac').mockImplementation(() => new Uint8Array(64));

await expect(
createBip39KeyFromSeed(RANDOM_SEED, secp256k1),
).rejects.toThrow(
'Invalid private key: The private key must larger than 0 and less than the curve order.',
'Invalid private key: The private key must greater than 0 and less than the curve order.',
);
});

it.each([
bigIntToBytes(secp256k1.curve.n),
concatBytes([secp256k1.curve.n + BigInt(1)]),
])(
'throws if the private key is larger than or equal to the curve order',
'throws if the private key is greater than or equal to the curve order',
async (privateKey) => {
// For this test to be effective, the private key must be 32 bytes.
assert(privateKey.length === 32);
Expand All @@ -44,7 +60,7 @@ describe('createBip39KeyFromSeed', () => {
await expect(
createBip39KeyFromSeed(RANDOM_SEED, secp256k1),
).rejects.toThrow(
'Invalid private key: The private key must larger than 0 and less than the curve order.',
'Invalid private key: The private key must greater than 0 and less than the curve order.',
);
},
);
Expand Down
2 changes: 1 addition & 1 deletion src/derivers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type DerivedKeys = {

export type DeriveChildKeyArgs = {
path: Uint8Array | string;
curve?: Curve;
curve: Curve;
node?: SLIP10Node;
};

Expand Down
10 changes: 5 additions & 5 deletions test/reference-implementations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
BIP44PurposeNodeToken,
HDPathTuple,
} from '../src';
import { ed25519 } from '../src/curves';
import { ed25519, secp256k1 } from '../src/curves';
import { deriveKeyFromPath } from '../src/derivation';
import { createBip39KeyFromSeed } from '../src/derivers/bip39';
import {
Expand Down Expand Up @@ -145,7 +145,7 @@ describe('reference implementation tests', () => {

describe('BIP44Node', () => {
it('derives the same keys as the reference implementation', async () => {
const parentNode = await createBip39KeyFromSeed(seed);
const parentNode = await createBip39KeyFromSeed(seed, secp256k1);
const node = await parentNode.derive(path.ours.tuple);

expect(node.privateKey).toStrictEqual(privateKey);
Expand All @@ -161,7 +161,7 @@ describe('reference implementation tests', () => {
});

it('derives the same keys as the reference implementation using public key derivation', async () => {
const parentNode = await createBip39KeyFromSeed(seed);
const parentNode = await createBip39KeyFromSeed(seed, secp256k1);
const node = await parentNode.derive(path.ours.tuple);

expect(node.privateKey).toStrictEqual(privateKey);
Expand All @@ -180,7 +180,7 @@ describe('reference implementation tests', () => {

describe('deriveKeyFromPath', () => {
it('derives the same keys as the reference implementation', async () => {
const node = await createBip39KeyFromSeed(seed);
const node = await createBip39KeyFromSeed(seed, secp256k1);
const childNode = await deriveKeyFromPath({
path: path.ours.tuple,
node,
Expand Down Expand Up @@ -210,7 +210,7 @@ describe('reference implementation tests', () => {
it('derives the test vector keys', async () => {
for (const vector of vectors) {
const seed = hexStringToBytes(vector.hexSeed);
const node = await createBip39KeyFromSeed(seed);
const node = await createBip39KeyFromSeed(seed, secp256k1);

for (const keyObj of vector.keys) {
const { path, privateKey } = keyObj;
Expand Down

0 comments on commit 764c7e9

Please sign in to comment.