UNPKG

ed25519-hd-key

Version:

BIP-0032 like derivation for ed25519 curve

60 lines (59 loc) 1.93 kB
import { sha512 } from '@noble/hashes/sha2.js'; import { hmac } from '@noble/hashes/hmac.js'; import { concatBytes, hexToBytes } from '@noble/hashes/utils.js'; import * as ed from '@noble/ed25519'; import { replaceDerive, pathRegex } from './utils.js'; ed.hashes.sha512 = sha512; const ED25519_CURVE = new TextEncoder().encode('ed25519 seed'); const HARDENED_OFFSET = 0x80000000; export const getMasterKeyFromSeed = (seed) => { const I = hmac(sha512, ED25519_CURVE, hexToBytes(seed)); const IL = I.slice(0, 32); const IR = I.slice(32); return { key: IL, chainCode: IR, }; }; export const CKDPriv = ({ key, chainCode }, index) => { const indexBuffer = new Uint8Array(4); const view = new DataView(indexBuffer.buffer); view.setUint32(0, index, false); const data = concatBytes(new Uint8Array([0]), key, indexBuffer); const I = hmac(sha512, chainCode, data); const IL = I.slice(0, 32); const IR = I.slice(32); return { key: IL, chainCode: IR, }; }; export const getPublicKey = (privateKey, withZeroByte = true) => { const { publicKey } = ed.keygen(privateKey); return withZeroByte ? concatBytes(new Uint8Array([0]), publicKey) : publicKey; }; export const isValidPath = (path) => { if (!pathRegex.test(path)) { return false; } return !path .split('/') .slice(1) .map(replaceDerive) .some(isNaN); }; export const derivePath = (path, seed, offset = HARDENED_OFFSET) => { if (!isValidPath(path)) { throw new Error('Invalid derivation path'); } const { key, chainCode } = getMasterKeyFromSeed(seed); const segments = path .split('/') .slice(1) .map(replaceDerive) .map((el) => parseInt(el, 10)); return segments.reduce((parentKeys, segment) => CKDPriv(parentKeys, segment + offset), { key, chainCode, }); };