]> git.codecow.com Git - libnemo.git/commitdiff
Perform validation in exported function and use it to call private ckd.
authorChris Duncan <chris@codecow.com>
Thu, 14 May 2026 19:19:26 +0000 (12:19 -0700)
committerChris Duncan <chris@codecow.com>
Thu, 14 May 2026 19:19:26 +0000 (12:19 -0700)
src/lib/crypto/bip44.ts
src/lib/vault/vault-worker.ts

index aea3ad81237e6f636194c84c285463cf930a71d3..135bae75caed3df80beb49e5da76bd3c4b1dd484 100644 (file)
@@ -3,14 +3,12 @@
 
 import { Point, getPublicKey as secp256k1_getPublicKey } from '@noble/secp256k1'
 
+type Curve = 'Bitcoin seed' | 'ed25519 seed'
 type ExtendedKey = {
        privateKey: ArrayBuffer
        chainCode: ArrayBuffer
        publicKey?: ArrayBuffer
 }
-
-type Curve = 'Bitcoin seed' | 'ed25519 seed'
-
 const BIP44_PURPOSE: 44 = 44
 const HARDENED_OFFSET: 0x80000000 = 0x80000000
 
@@ -27,25 +25,45 @@ const HARDENED_OFFSET: 0x80000000 = 0x80000000
  * @param {number} [address] - Sequentially increasing index of addresses to use for each account
  * @returns {Promise<ArrayBuffer>} Private child key for the account
  */
-export function ckd (curve: Curve, seed: ArrayBuffer, coin: number, account: number, change?: number, address?: number): Promise<ArrayBuffer> {
+export function Bip44 (curve: Curve, seed: ArrayBuffer, coin: number, account: number, change?: number, address?: number): Promise<ArrayBuffer>
+export function Bip44 (curve: unknown, seed: unknown, coin: unknown, account: unknown, change?: unknown, address?: unknown): Promise<ArrayBuffer> {
        if (curve !== 'Bitcoin seed' && curve !== 'ed25519 seed') {
                throw new TypeError(`Unsupported curve ${curve}`)
        }
+       if (!(seed instanceof ArrayBuffer)) {
+               throw new RangeError(`Invalid seed buffer ${seed}`)
+       }
        if (seed.byteLength < 16 || seed.byteLength > 64) {
                throw new RangeError(`Invalid seed byte length ${seed.byteLength}`)
        }
+       if (typeof coin !== 'number') {
+               throw new RangeError(`Invalid coin ${coin}`)
+       }
        if (!Number.isSafeInteger(coin) || coin < 0 || coin > 0x7fffffff) {
                throw new RangeError(`Invalid coin 0x${coin.toString(16)}`)
        }
+       if (typeof account !== 'number') {
+               throw new RangeError(`Invalid account index ${account}`)
+       }
        if (!Number.isSafeInteger(account) || account < 0 || account > 0x7fffffff) {
                throw new RangeError(`Invalid account index 0x${account.toString(16)}`)
        }
+       if (change !== undefined && typeof change !== 'number') {
+               throw new RangeError(`Invalid change index ${change}`)
+       }
        if (change !== undefined && (!Number.isSafeInteger(change) || change < 0 || change > 1)) {
                throw new RangeError(`Invalid change index 0x${account.toString(16)}`)
        }
+       if (address !== undefined && typeof address !== 'number') {
+               throw new RangeError(`Invalid address index ${address}`)
+       }
        if (address !== undefined && (!Number.isSafeInteger(address) || address < 0 || address > 0x7fffffff)) {
                throw new RangeError(`Invalid address index 0x${account.toString(16)}`)
        }
+       return ckd(curve, seed, coin, account, change, address)
+}
+
+function ckd (curve: Curve, seed: ArrayBuffer, coin: number, account: number, change?: number, address?: number): Promise<ArrayBuffer> {
        return slip10(curve, seed)
                .then(masterKey => CKDpriv(curve, masterKey, BIP44_PURPOSE + HARDENED_OFFSET))
                .then(purposeKey => CKDpriv(curve, purposeKey, coin + HARDENED_OFFSET))
@@ -128,8 +146,7 @@ function parse256 (integer: Uint8Array<ArrayBuffer>): bigint {
 }
 
 function hmac (key: Uint8Array<ArrayBuffer>, data: Uint8Array<ArrayBuffer>): Promise<ArrayBuffer> {
-       return crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-512' }, false, ['sign'])
-               .then(pk => {
-                       return crypto.subtle.sign('HMAC', pk, data)
-               })
+       return crypto.subtle
+               .importKey('raw', key, { name: 'HMAC', hash: 'SHA-512' }, false, ['sign'])
+               .then(pk => crypto.subtle.sign('HMAC', pk, data))
 }
index 4ff5e96766cc316e969eab389787a3cfcabda4dd..4028cf4fe463af190e2c87703b7439f4ebe55df2 100644 (file)
@@ -387,10 +387,10 @@ function _ckd (index: number): Promise<ArrayBuffer> {
        }
        switch (_type) {
                case ('BIP-44'): {
-                       return Bip44.ckd('ed25519 seed', _seed, BIP44_COIN_NANO, index)
+                       return Bip44('ed25519 seed', _seed, BIP44_COIN_NANO, index)
                }
                case ('Exodus'): {
-                       return Bip44.ckd('Bitcoin seed', _seed, 0x100, index, 0, 0)
+                       return Bip44('Bitcoin seed', _seed, 0x100, index, 0, 0)
                }
                default: {
                        return Blake2b.ckd(_seed, index)