1 | import { bnToU8a, stringToU8a, u8aConcat } from '@polkadot/util';
|
2 | import { BN_BE_32_OPTS } from '../../bn.js';
|
3 | import { hmacShaAsU8a } from '../../hmac/index.js';
|
4 | import { secp256k1PairFromSeed, secp256k1PrivateKeyTweakAdd } from '../../secp256k1/index.js';
|
5 | import { HARDENED, hdValidatePath } from '../validatePath.js';
|
6 | const MASTER_SECRET = stringToU8a('Bitcoin seed');
|
7 | function createCoded(secretKey, chainCode) {
|
8 | return {
|
9 | chainCode,
|
10 | publicKey: secp256k1PairFromSeed(secretKey).publicKey,
|
11 | secretKey
|
12 | };
|
13 | }
|
14 | function 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 |
|
25 | return deriveChild(hd, index + 1);
|
26 | }
|
27 | }
|
28 | export 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 | }
|