-
Notifications
You must be signed in to change notification settings - Fork 0
/
generatePublicKey.js
115 lines (102 loc) · 3.02 KB
/
generatePublicKey.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
var Ed25519KeyIdentity = require("@dfinity/identity").Ed25519KeyIdentity;
var mnemonicToEntropy = require("bip39").mnemonicToEntropy;
var mnemonicToSeedSync = require("bip39").mnemonicToSeedSync;
var validateMnemonic = require("bip39").validateMnemonic;
const IC_DERIVATION_PATH = [44, 223, 0, 0, 0];
const HARDENED = 0x80000000;
async function generateMasterKey(seed) {
const data = new TextEncoder().encode("ed25519 seed");
const key = await window.crypto.subtle.importKey(
"raw",
data,
{
name: "HMAC",
hash: { name: "SHA-512" },
},
false,
["sign"]
);
const h = await window.crypto.subtle.sign("HMAC", key, seed);
const slipSeed = new Uint8Array(h.slice(0, 32));
const chainCode = new Uint8Array(h.slice(32));
return [slipSeed, chainCode];
}
async function derive(parentKey, parentChaincode, i) {
// From the spec: Data = 0x00 || ser256(kpar) || ser32(i)
const data = new Uint8Array([0, ...parentKey, ...toBigEndianArray(i)]);
const key = await window.crypto.subtle.importKey(
"raw",
parentChaincode,
{
name: "HMAC",
hash: { name: "SHA-512" },
},
false,
["sign"]
);
const h = await window.crypto.subtle.sign("HMAC", key, data.buffer);
const slipSeed = new Uint8Array(h.slice(0, 32));
const chainCode = new Uint8Array(h.slice(32));
return [slipSeed, chainCode];
}
// Converts a 32-bit unsigned integer to a big endian byte array.
function toBigEndianArray(n) {
const byteArray = new Uint8Array([0, 0, 0, 0]);
for (let i = byteArray.length - 1; i >= 0; i--) {
const byte = n & 0xff;
byteArray[i] = byte;
n = (n - byte) / 256;
}
return byteArray;
}
async function fromSeedWithSlip0010(masterSeed, derivationPath = []) {
let [slipSeed, chainCode] = await generateMasterKey(masterSeed);
for (let i = 0; i < derivationPath.length; i++) {
[slipSeed, chainCode] = await derive(
slipSeed,
chainCode,
derivationPath[i] | HARDENED
);
}
return Ed25519KeyIdentity.generate(slipSeed);
}
const parseUserNumber = (s) => {
if (/^\d+$/.test(s)) {
try {
return Number(s);
} catch (err) {
return null;
}
} else {
return null;
}
};
const dropLeadingUserNumber = (s) => {
const i = s.indexOf(" ");
if (i !== -1 && parseUserNumber(s.slice(0, i)) !== null) {
return s.slice(i + 1);
} else {
return s;
}
};
async function calculatePublicKey(seedphrase) {
const bipWords = dropLeadingUserNumber(seedphrase).trim();
if (!validateMnemonic(bipWords)) {
try {
mnemonicToEntropy(bipWords);
return "validateMnemonic failed but mnemonicToEntropy didn't give an error";
} catch (e) {
return "validateMnemonic failed" + e;
}
} else {
const seed = mnemonicToSeedSync(bipWords);
const identity = await fromSeedWithSlip0010(seed, IC_DERIVATION_PATH);
let values = identity.getKeyPair().publicKey.derKey.values();
let result = "";
for (const value of values) {
result += value + ",";
}
return result;
}
}
module.exports = calculatePublicKey;