import { Point, getPublicKey as secp256k1_getPublicKey } from '@noble/secp256k1'
+type Bytes = Uint8Array<ArrayBuffer>
type Curve = 'Bitcoin seed' | 'ed25519 seed'
type ExtendedKey = {
privateKey: ArrayBuffer
}
const BIP44_PURPOSE: 44 = 44
const HARDENED_OFFSET: 0x80000000 = 0x80000000
+const ENCODER: TextEncoder = new TextEncoder()
/**
* Derives a private child key for a coin by following the specified BIP-32 and
}
function slip10 (curve: string, S: ArrayBuffer): Promise<ExtendedKey> {
- const key = new Uint8Array(new TextEncoder().encode(curve))
- const data = new Uint8Array(S)
+ const key = ENCODER.encode(curve).buffer
+ const data = S
return hmac(key, data)
.then(I => {
const IL = I.slice(0, I.byteLength / 2)
return Promise.resolve({ privateKey, chainCode })
}
const pk = new Uint8Array(privateKey)
- const key = new Uint8Array(chainCode)
- const data = new Uint8Array(37)
+ const t = new Uint8Array(37)
if (index >= HARDENED_OFFSET) {
- data.set([0])
- data.set(pk, 1)
- data.set(ser32(index), 33)
+ t.set(pk, 1)
} else if (curve === 'ed25519 seed') {
throw new RangeError('Only hardened child keys are supported for ed25519')
} else {
- data.set(secp256k1_getPublicKey(pk))
- data.set(ser32(index), 33)
+ t.set(secp256k1_getPublicKey(pk))
}
+ t.set(ser32(index), 33)
+ const key = chainCode
+ const data = t.buffer
return hmac(key, data)
.then(I => {
const IL = I.slice(0, I.byteLength / 2)
})
}
-function ser32 (integer: number): Uint8Array<ArrayBuffer> {
+function ser32 (integer: number): Bytes {
const view = new DataView(new ArrayBuffer(4))
view.setUint32(0, integer, false)
return new Uint8Array(view.buffer)
}
-function ser256 (integer: bigint): Uint8Array<ArrayBuffer> {
+function ser256 (integer: bigint): Bytes {
let bytes = new Uint8Array(32)
for (let i = bytes.byteLength - 1; i >= 0; i--) {
bytes[i] = Number(integer & 0xffn)
return bytes
}
-function parse256 (integer: Uint8Array<ArrayBuffer>): bigint {
+function parse256 (integer: Bytes): bigint {
let result = 0n
for (let i = 0; i < integer.byteLength; i++) {
result = (result << 8n) | BigInt(integer[i])
return result
}
-function hmac (key: Uint8Array<ArrayBuffer>, data: Uint8Array<ArrayBuffer>): Promise<ArrayBuffer> {
+function hmac (key: ArrayBuffer, data: ArrayBuffer): Promise<ArrayBuffer> {
return crypto.subtle
.importKey('raw', key, { name: 'HMAC', hash: 'SHA-512' }, false, ['sign'])
.then(pk => crypto.subtle.sign('HMAC', pk, data))