项目文件夹

文件
wehub-resource-sync 98e40dac97
CLI Smoke Test / smoke-test-linux (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-linux (24) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (24) (push) Has been cancelled
Expo App TypeScript typecheck / typecheck (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:40:49 +08:00

46 行
1.7 KiB
TypeScript

import { hmac_sha512 } from "./hmac_sha512";
export type KeyTreeState = {
key: Uint8Array,
chainCode: Uint8Array
};
export async function deriveSecretKeyTreeRoot(seed: Uint8Array, usage: string): Promise<KeyTreeState> {
const I = await hmac_sha512(new TextEncoder().encode(usage + ' Master Seed'), seed);
return {
key: I.slice(0, 32),
chainCode: I.slice(32)
};
}
export async function deriveSecretKeyTreeChild(chainCode: Uint8Array, index: string): Promise<KeyTreeState> {
// Prepare data
const data = new Uint8Array([0x0, ...new TextEncoder().encode(index)]); // prepend 0x00 for separator
// Derive key
const I = await hmac_sha512(chainCode, data);
// Use slice() not subarray() so the returned key/chainCode each own a
// fresh 32-byte ArrayBuffer. The native libsodium TurboModule on iOS
// reads the underlying ArrayBuffer length (`.length(runtime)`) when
// validating crypto_secretbox key bytes — passing a subarray view onto
// a 64-byte parent buffer makes that check see 64 and reject with
// "invalid key length", even though the view itself is the right 32
// bytes. The sibling deriveSecretKeyTreeRoot already does this; keep
// the two consistent.
return {
key: I.slice(0, 32),
chainCode: I.slice(32),
};
}
export async function deriveKey(master: Uint8Array, usage: string, path: string[]): Promise<Uint8Array> {
let state = await deriveSecretKeyTreeRoot(master, usage);
let remaining = [...path];
while (remaining.length > 0) {
let index = remaining[0];
remaining = remaining.slice(1);
state = await deriveSecretKeyTreeChild(state.chainCode, index);
}
return state.key;
}