UNPKG

1.67 kBJavaScriptView Raw
1import { bnToU8a, stringToU8a, u8aConcat } from '@polkadot/util';
2import { BN_BE_32_OPTS } from '../../bn.js';
3import { hmacShaAsU8a } from '../../hmac/index.js';
4import { secp256k1PairFromSeed, secp256k1PrivateKeyTweakAdd } from '../../secp256k1/index.js';
5import { HARDENED, hdValidatePath } from '../validatePath.js';
6const MASTER_SECRET = stringToU8a('Bitcoin seed');
7function createCoded(secretKey, chainCode) {
8 return {
9 chainCode,
10 publicKey: secp256k1PairFromSeed(secretKey).publicKey,
11 secretKey
12 };
13}
14function deriveChild(hd, index) {
15 const indexBuffer = bnToU8a(index, BN_BE_32_OPTS);
16 const data = index >= HARDENED
17 ? u8aConcat(new Uint8Array(1), hd.secretKey, indexBuffer)
18 : u8aConcat(hd.publicKey, indexBuffer);
19 try {
20 const I = hmacShaAsU8a(hd.chainCode, data, 512);
21 return createCoded(secp256k1PrivateKeyTweakAdd(hd.secretKey, I.slice(0, 32)), I.slice(32));
22 }
23 catch {
24 // In case parse256(IL) >= n or ki == 0, proceed with the next value for i
25 return deriveChild(hd, index + 1);
26 }
27}
28export function hdEthereum(seed, path = '') {
29 const I = hmacShaAsU8a(MASTER_SECRET, seed, 512);
30 let hd = createCoded(I.slice(0, 32), I.slice(32));
31 if (!path || path === 'm' || path === 'M' || path === "m'" || path === "M'") {
32 return hd;
33 }
34 if (!hdValidatePath(path)) {
35 throw new Error('Invalid derivation path');
36 }
37 const parts = path.split('/').slice(1);
38 for (const p of parts) {
39 hd = deriveChild(hd, parseInt(p, 10) + ((p.length > 1) && p.endsWith("'")
40 ? HARDENED
41 : 0));
42 }
43 return hd;
44}