Skip to content

Commit a2551db

Browse files
committed
Add deriveSlip21Node
1 parent 5865c91 commit a2551db

4 files changed

Lines changed: 951 additions & 932 deletions

File tree

.changeset/small-lights-go.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@evolu/common": patch
3+
---
4+
5+
Add deriveSlip21Node

eslint.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export default tseslint.config(
9494
"@typescript-eslint/no-non-null-assertion": "off",
9595
"no-console": "error",
9696
"@typescript-eslint/restrict-template-expressions": "off",
97+
"@typescript-eslint/triple-slash-reference": "off",
9798
"react-hooks/rules-of-hooks": "error",
9899
"react-hooks/exhaustive-deps": "error",
99100
"jsdoc/require-jsdoc": "off",

packages/common/src/Crypto.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
} from "./Type.js";
2323
import { Brand } from "./Brand.js";
2424
import { assert } from "./Assert.js";
25+
import { utf8ToBytes } from "./Buffer.js";
2526

2627
/** `Uint8Array` created by {@link createRandomBytes}. */
2728
export type RandomBytes = Uint8Array & Brand<"RandomBytes">;
@@ -56,25 +57,37 @@ export const mnemonicToMnemonicSeed = (mnemonic: Mnemonic): MnemonicSeed =>
5657
* https://github.com/satoshilabs/slips/blob/master/slip-0021.md
5758
*/
5859
export const createSlip21 = (
59-
seed: MnemonicSeed,
60+
seed: Uint8Array,
6061
path: ReadonlyArray<string>,
6162
): Uint8Array => {
6263
assert(
6364
seed.length >= 16 && seed.length <= 64,
6465
`Unusual SLIP-0021 seed length: ${seed.length} bytes`,
6566
);
6667

67-
let m = hmac(sha512, "Symmetric key seed", seed);
68+
let m = hmac(sha512, utf8ToBytes("Symmetric key seed"), seed);
6869
for (const component of path) {
69-
const p = new TextEncoder().encode(component);
70-
const e = new globalThis.Uint8Array(p.byteLength + 1);
71-
e[0] = 0;
72-
e.set(p, 1);
73-
m = hmac(sha512, m.slice(0, 32), e);
70+
m = deriveSlip21Node(component, m);
7471
}
7572
return m.slice(32, 64);
7673
};
7774

75+
/**
76+
* Derives a single node in the SLIP-21 hierarchical key derivation.
77+
*
78+
* @see {@link createSlip21}
79+
*/
80+
export const deriveSlip21Node = (
81+
component: string,
82+
m: Uint8Array,
83+
): Uint8Array => {
84+
const p = utf8ToBytes(component);
85+
const e = new globalThis.Uint8Array(p.byteLength + 1);
86+
e[0] = 0;
87+
e.set(p, 1);
88+
return hmac(sha512, m.slice(0, 32), e);
89+
};
90+
7891
/**
7992
* Creates a 21-character Base64URL ID (also known as nanoid) from a SLIP-21
8093
* derived key.

0 commit comments

Comments
 (0)