-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathkeyDerivation.ts
89 lines (79 loc) · 2.68 KB
/
keyDerivation.ts
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
import { BigNumber, BigNumberish, utils } from "ethers";
import { isNumber } from "lodash";
import { KeyPair, ec, number } from "starknet-410";
export function getStarkPair<T extends number | string>(
indexOrPath: T,
secret: BigNumberish,
...[baseDerivationPath]: T extends string ? [] : [string]
): KeyPair {
const masterNode = utils.HDNode.fromSeed(
BigNumber.from(secret).toHexString()
);
// baseDerivationPath will never be undefined because of the extends statement below,
// but somehow TS doesnt get this. As this will be removed in the near future I didnt bother
const path: string = isNumber(indexOrPath)
? getPathForIndex(indexOrPath, baseDerivationPath ?? "")
: indexOrPath;
const childNode = masterNode.derivePath(path);
const groundKey = grindKey(childNode.privateKey);
const starkPair = ec.getKeyPair(groundKey);
return starkPair;
}
export function getPathForIndex(
index: number,
baseDerivationPath: string
): string {
return `${baseDerivationPath}/${index}`;
}
export function getIndexForPath(path: string, baseDerivationPath: string) {
if (!path.startsWith(baseDerivationPath)) {
throw "path should begin with baseDerivationPath";
}
const index = path.substring(path.lastIndexOf("/") + 1);
return parseInt(index);
}
export function getNextPathIndex(
paths: string[],
baseDerivationPath: string
): number {
for (let index = 0; index < paths.length; index++) {
if (!paths.includes(getPathForIndex(index, baseDerivationPath))) {
return index;
}
}
return paths.length;
}
// inspired/copied from https://github.com/authereum/starkware-monorepo/blob/51c5df19e7f98399a2f7e63d564210d761d138d1/packages/starkware-crypto/src/keyDerivation.ts#L85
export function grindKey(keySeed: string): string {
const keyValueLimit = ec.ec.n;
if (!keyValueLimit) {
return keySeed;
}
const sha256EcMaxDigest = number.toBN(
"1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000",
16
);
const maxAllowedVal = sha256EcMaxDigest.sub(
sha256EcMaxDigest.mod(keyValueLimit)
);
// Make sure the produced key is devided by the Stark EC order,
// and falls within the range [0, maxAllowedVal).
let i = 0;
let key;
do {
key = hashKeyWithIndex(keySeed, i);
i++;
} while (!key.lt(maxAllowedVal));
return "0x" + key.umod(keyValueLimit).toString("hex");
}
function hashKeyWithIndex(key: string, index: number) {
const payload = utils.concat([utils.arrayify(key), utils.arrayify(index)]);
const hash = utils.sha256(payload);
return number.toBN(hash);
}
export function pathHash(name: string): number {
return number
.toBN(utils.sha256(utils.toUtf8Bytes(name)))
.maskn(31)
.toNumber();
}