Additional hdLedger tests (#863)
This commit is contained in:
@@ -1,34 +1,29 @@
|
||||
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import BN from 'bn.js';
|
||||
|
||||
import { bnToU8a, u8aConcat } from '@polkadot/util';
|
||||
import { bnToU8a, u8aConcat, u8aToBn } from '@polkadot/util';
|
||||
|
||||
import { hmacSha512 } from '../../hmac';
|
||||
|
||||
// performs hard-only derivation on the xprv
|
||||
export function ledgerDerivePrivate (xprv: Uint8Array, index: number): Uint8Array {
|
||||
const kl = xprv.slice(0, 32);
|
||||
const kr = xprv.slice(32, 64);
|
||||
const cc = xprv.slice(64, 96);
|
||||
|
||||
const data = new Uint8Array(1 + 64 + 4);
|
||||
|
||||
data.set(bnToU8a(index, { bitLength: 32, isLe: true }), 1 + 64);
|
||||
data.set(kl, 1);
|
||||
data.set(kr, 1 + 32);
|
||||
data[0] = 0x00;
|
||||
|
||||
const kl = xprv.subarray(0, 32);
|
||||
const kr = xprv.subarray(32, 64);
|
||||
const cc = xprv.subarray(64, 96);
|
||||
const data = u8aConcat([0], kl, kr, bnToU8a(index, { bitLength: 32, isLe: true }));
|
||||
const z = hmacSha512(cc, data);
|
||||
|
||||
data[0] = 0x01;
|
||||
|
||||
const chainCode = hmacSha512(cc, data).slice(32, 64);
|
||||
const zl = z.slice(0, 32);
|
||||
const zr = z.slice(32, 64);
|
||||
const left = bnToU8a(new BN(kl, 16, 'le').add(new BN(zl.slice(0, 28), 16, 'le').mul(new BN(8))), { bitLength: 512, isLe: true }).slice(0, 32);
|
||||
const right = bnToU8a(new BN(kr, 16, 'le').add(new BN(zr, 16, 'le')), { bitLength: 512, isLe: true }).slice(0, 32);
|
||||
|
||||
return u8aConcat(left, right, chainCode);
|
||||
return u8aConcat(
|
||||
bnToU8a(
|
||||
u8aToBn(kl, { isLe: true }).iadd(u8aToBn(z.subarray(0, 28), { isLe: true }).muln(8)),
|
||||
{ bitLength: 512, isLe: true }
|
||||
).subarray(0, 32),
|
||||
bnToU8a(
|
||||
u8aToBn(kr, { isLe: true }).iadd(u8aToBn(z.subarray(32, 64), { isLe: true })),
|
||||
{ bitLength: 512, isLe: true }
|
||||
).subarray(0, 32),
|
||||
hmacSha512(cc, data).subarray(32, 64)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,20 +5,52 @@ import { u8aToHex } from '@polkadot/util';
|
||||
|
||||
import { hdLedger } from '..';
|
||||
|
||||
describe('ledgerDerive', (): void => {
|
||||
it('derives a known private key for Kusama', (): void => {
|
||||
expect(u8aToHex(
|
||||
hdLedger('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', `m/44'/${0x01b2}'/0'/0'/0'`)
|
||||
.secretKey
|
||||
.slice(0, 32)
|
||||
)).toEqual('0x98cb4e14e0e08ea876f88d728545ea7572dc07dbbe69f1731c418fb827e69d41');
|
||||
});
|
||||
const MNE_0 = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
|
||||
const MNE_1 = 'open jelly jeans corn ketchup supreme brief element armed lens vault weather original scissors rug priority vicious lesson raven spot gossip powder person volcano';
|
||||
|
||||
it('derives a known private key for Polkadot', (): void => {
|
||||
expect(u8aToHex(
|
||||
hdLedger('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', `m/44'/${0x80000162}/0'/0'/0'`)
|
||||
.secretKey
|
||||
.slice(0, 32)
|
||||
)).toEqual('0xe8c68348586d53e4e8d1a864b0e4e17c75e4eb06e0c63c1432bef2ba29e69d41');
|
||||
const TESTS = {
|
||||
Kusama: {
|
||||
slip44: 0x01b2,
|
||||
tests: [
|
||||
{
|
||||
ed25519: '0x98cb4e14e0e08ea876f88d728545ea7572dc07dbbe69f1731c418fb827e69d41',
|
||||
index: [0, 0],
|
||||
mnemonic: MNE_0
|
||||
},
|
||||
{
|
||||
ed25519: '0x70e9010e84c81095aaa5f63b1c5a6a66a1dcbec017a23c2f3b7a1b08fe5ea65a',
|
||||
index: [0, 0],
|
||||
mnemonic: MNE_1
|
||||
},
|
||||
{
|
||||
ed25519: '0xf06730efb1e6ea59ac752a7c3620fade3909062fb88597856cc3af72045fa65a',
|
||||
index: [5, 7],
|
||||
mnemonic: MNE_1
|
||||
}
|
||||
]
|
||||
},
|
||||
Polkadot: {
|
||||
slip44: 0x80000162,
|
||||
tests: [
|
||||
{
|
||||
ed25519: '0xe8c68348586d53e4e8d1a864b0e4e17c75e4eb06e0c63c1432bef2ba29e69d41',
|
||||
index: [0, 0],
|
||||
mnemonic: MNE_0
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
describe('ledgerDerive', (): void => {
|
||||
Object.entries(TESTS).forEach(([network, { slip44, tests }]): void => {
|
||||
tests.forEach(({ ed25519, index: [account, address], mnemonic }, index): void => {
|
||||
it(`derives a known ed25519 seed for ${network} (${index})`, (): void => {
|
||||
expect(u8aToHex(
|
||||
hdLedger(mnemonic, `m/44'/${slip44}'/${account}'/0'/${address}'`)
|
||||
.secretKey
|
||||
.slice(0, 32)
|
||||
)).toEqual(ed25519);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user