]> zoso.dev Git - libnemo.git/commitdiff
Hot damn it worked.
authorChris Duncan <chris@zoso.dev>
Wed, 27 Nov 2024 08:15:43 +0000 (00:15 -0800)
committerChris Duncan <chris@zoso.dev>
Wed, 27 Nov 2024 08:15:43 +0000 (00:15 -0800)
package.json
src/lib/account.ts
src/lib/blake2b.ts
src/lib/wallet.ts
src/lib/workers/ckdBlake2b.ts

index 1d6f1e55a5500be6322ff3f42672846b3c2752c2..c8fc31cba80f20aa51ffd163c32381d2aaadbe5e 100644 (file)
@@ -42,7 +42,7 @@
                "url": "git+https://zoso.dev/libnemo.git"
        },
        "scripts": {
-               "build": "rm -rf dist && tsc && esbuild main.min=dist/main.js global.min=dist/global.js --outdir=dist --target=es2022 --format=esm --platform=browser --bundle --minify --sourcemap",
+               "build": "rm -rf dist && tsc && esbuild main.min=dist/main.js global.min=dist/global.js --outdir=dist --target=es2022 --format=esm --platform=browser --bundle --sourcemap",
                "test": "npm run build -- --platform=node && node --test --test-force-exit --env-file .env",
                "test:coverage": "npm run test -- --experimental-test-coverage",
                "test:coverage:report": "npm run test:coverage -- --test-reporter=lcov --test-reporter-destination=coverage.info && genhtml coverage.info --output-directory test/coverage && rm coverage.info && xdg-open test/coverage/index.html",
index 143543db562af14b2488c1e4bd61dd7d4b9397a6..bfe16ec94c0429e352006e5f7dbb9b7dd9d552ed 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>\r
 // SPDX-License-Identifier: GPL-3.0-or-later\r
 \r
-import blake2b from './blake2b.js'\r
+import { blake2b } from './blake2b.js'\r
 import { ACCOUNT_KEY_LENGTH, ALPHABET, PREFIX, PREFIX_LEGACY } from './constants.js'\r
 import { base32, bytes, hex } from './convert.js'\r
 import { Rpc } from './rpc.js'\r
index e63ae2706eedcbf3e757f64384d83904f8bac3f0..bfcde1f0861663155f0d74d23eccb6b9434c6e67 100644 (file)
@@ -4,16 +4,15 @@
 'use strict'
 
 /**
-* Implementation derived from blake2b@2.1.4
-* Copyright 2017 Emil Bay <github@tixz.dk>
-* Used with permission. See LICENSES/ISC.txt
-* See for details: https://github.com/emilbayes/blake2b
+* Implementation derived from blake2b@2.1.4. Copyright 2017 Emil Bay
+* <github@tixz.dk> (https://github.com/emilbayes/blake2b). See LICENSES/ISC.txt
+*
+* Modified to eliminate dependencies, port to TypeScript, and bundle into web
+* workers.
 *
-* Modified in 2024 by Chris Duncan to eliminate dependencies, port to
-* TypeScript, and bundle into web workers.
 * Original source commit: https://github.com/emilbayes/blake2b/blob/1f63e02e3f226642959506cdaa67c8819ff145cd/index.js
 */
-export default class Blake2b {
+function blake2b (outlen: number, key?: Uint8Array, salt?: Uint8Array, personal?: Uint8Array, noAssert?: boolean) {
        const BYTES_MIN = 16
        const BYTES_MAX = 64
        const KEYBYTES_MIN = 16
@@ -21,323 +20,328 @@ export default class Blake2b {
        const SALTBYTES = 16
        const PERSONALBYTES = 16
 
-       constructor (outlen: number, key?: Uint8Array, salt?: Uint8Array, personal?: Uint8Array, noAssert?: boolean) {
-               if (noAssert !== true) {
-                       if (outlen < BYTES_MIN)
-                               throw new RangeError(`outlen must be at least ${BYTES_MIN}, was given ${outlen}`)
-                       if (outlen > BYTES_MAX)
-                               throw new RangeError(`outlen must be at most ${BYTES_MAX}, was given ${outlen}`)
-                       if (key != null) {
-                               if (!(key instanceof Uint8Array))
-                                       throw new TypeError(`key must be Uint8Array or Buffer`)
-                               if (key.length < KEYBYTES_MIN)
-                                       throw new RangeError(`key must be at least ${KEYBYTES_MIN}, was given ${key.length}`)
-                               if (key.length > KEYBYTES_MAX)
-                                       throw new RangeError(`key must be at most ${KEYBYTES_MAX}, was given ${key.length}`)
-                       }
-                       if (salt != null) {
-                               if (!(salt instanceof Uint8Array))
-                                       throw new TypeError(`salt must be Uint8Array or Buffer`)
-                               if (salt.length !== SALTBYTES)
-                                       throw new RangeError(`salt must be exactly ${SALTBYTES}, was given ${salt.length}`)
-                       }
-                       if (personal != null) {
-                               if (!(personal instanceof Uint8Array))
-                                       throw new TypeError(`personal must be Uint8Array or Buffer`)
-                               if (personal.length !== PERSONALBYTES)
-                                       throw new RangeError(`personal must be exactly ${PERSONALBYTES}, was given ${personal.length}`)
-                       }
+       // reusable parameter_block
+       const parameter_block = new Uint8Array([
+               0, 0, 0, 0,      //  0: outlen, keylen, fanout, depth
+               0, 0, 0, 0,      //  4: leaf length, sequential mode
+               0, 0, 0, 0,      //  8: node offset
+               0, 0, 0, 0,      // 12: node offset
+               0, 0, 0, 0,      // 16: node depth, inner length, rfu
+               0, 0, 0, 0,      // 20: rfu
+               0, 0, 0, 0,      // 24: rfu
+               0, 0, 0, 0,      // 28: rfu
+               0, 0, 0, 0,      // 32: salt
+               0, 0, 0, 0,      // 36: salt
+               0, 0, 0, 0,      // 40: salt
+               0, 0, 0, 0,      // 44: salt
+               0, 0, 0, 0,      // 48: personal
+               0, 0, 0, 0,      // 52: personal
+               0, 0, 0, 0,      // 56: personal
+               0, 0, 0, 0       // 60: personal
+       ])
+
+       // Initialization Vector
+       const BLAKE2B_IV32 = new Uint32Array([
+               0xF3BCC908, 0x6A09E667, 0x84CAA73B, 0xBB67AE85,
+               0xFE94F82B, 0x3C6EF372, 0x5F1D36F1, 0xA54FF53A,
+               0xADE682D1, 0x510E527F, 0x2B3E6C1F, 0x9B05688C,
+               0xFB41BD6B, 0x1F83D9AB, 0x137E2179, 0x5BE0CD19
+       ])
+
+       const SIGMA8 = [
+               0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+               14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
+               11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
+               7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
+               9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
+               2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
+               12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
+               13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
+               6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
+               10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
+               0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+               14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3
+       ]
+
+       /**
+       * These are offsets into a uint64 buffer.
+       * Multiply them all by 2 to make them offsets into a uint32 buffer,
+       * because this is Javascript and we don't have uint64s
+       */
+       const SIGMA82 = new Uint8Array(SIGMA8.map(x => x * 2))
+
+       let v = new Uint32Array(32)
+       let m = new Uint32Array(32)
+
+       /**
+       * 64-bit unsigned addition
+       * Sets v[a,a+1] += v[b,b+1]
+       * v should be a Uint32Array
+       */
+       const ADD64AA = function (v: Uint32Array, a, b) {
+               var o0 = v[a] + v[b]
+               var o1 = v[a + 1] + v[b + 1]
+               if (o0 >= 0x100000000) {
+                       o1++
                }
-
-               return this.create(outlen, key, salt, personal)
+               v[a] = o0
+               v[a + 1] = o1
        }
 
-/**
-* Creates a BLAKE2b hashing context
-* Requires an output length between 1 and 64 bytes
-* Takes an optional Uint8Array key
-*/
-function create (this: typeof Blake2b, outlen: number, key?: Uint8Array, salt?: Uint8Array, personal?: Uint8Array) {
-       // zero out parameter_block before usage
-       parameter_block.fill(0)
-       // state, 'param block'
-
-       this.b = new Uint8Array(128)
-       this.h = new Uint32Array(16)
-       this.t = 0 // input count
-       this.c = 0 // pointer within buffer
-       this.outlen = outlen // output length in bytes
-
-       parameter_block[0] = outlen
-       if (key) parameter_block[1] = key.length
-       parameter_block[2] = 1 // fanout
-       parameter_block[3] = 1 // depth
-
-       if (salt) parameter_block.set(salt, 32)
-       if (personal) parameter_block.set(personal, 48)
-
-       // initialize hash state
-       for (var i = 0; i < 16; i++) {
-               this.h[i] = BLAKE2B_IV32[i] ^ B2B_GET32(parameter_block, i * 4)
+       /**
+       * 64-bit unsigned addition
+       * Sets v[a,a+1] += b
+       * b0 is the low 32 bits of b, b1 represents the high 32 bits
+       */
+       const ADD64AC = function (v, a, b0, b1) {
+               var o0 = v[a] + b0
+               if (b0 < 0) {
+                       o0 += 0x100000000
+               }
+               var o1 = v[a + 1] + b1
+               if (o0 >= 0x100000000) {
+                       o1++
+               }
+               v[a] = o0
+               v[a + 1] = o1
        }
 
-       // key the hash, if applicable
-       if (key) {
-               blake2bUpdate(this, key)
-               // at the end
-               this.c = 128
+       // Little-endian byte access
+       const B2B_GET32 = function (arr, i) {
+               return (arr[i] ^
+                       (arr[i + 1] << 8) ^
+                       (arr[i + 2] << 16) ^
+                       (arr[i + 3] << 24))
        }
-       return new this
-}
 
-/**
-* 64-bit unsigned addition
-* Sets v[a,a+1] += v[b,b+1]
-* v should be a Uint32Array
-*/
-function ADD64AA (v: Uint32Array, a, b) {
-       var o0 = v[a] + v[b]
-       var o1 = v[a + 1] + v[b + 1]
-       if (o0 >= 0x100000000) {
-               o1++
+       /**
+       * G Mixing function
+       * The ROTRs are inlined for speed
+       */
+       const B2B_G = function (a, b, c, d, ix, iy) {
+               var x0 = m[ix]
+               var x1 = m[ix + 1]
+               var y0 = m[iy]
+               var y1 = m[iy + 1]
+
+               ADD64AA(v, a, b) // v[a,a+1] += v[b,b+1] ... in JS we must store a uint64 as two uint32s
+               ADD64AC(v, a, x0, x1) // v[a, a+1] += x ... x0 is the low 32 bits of x, x1 is the high 32 bits
+
+               // v[d,d+1] = (v[d,d+1] xor v[a,a+1]) rotated to the right by 32 bits
+               var xor0 = v[d] ^ v[a]
+               var xor1 = v[d + 1] ^ v[a + 1]
+               v[d] = xor1
+               v[d + 1] = xor0
+
+               ADD64AA(v, c, d)
+
+               // v[b,b+1] = (v[b,b+1] xor v[c,c+1]) rotated right by 24 bits
+               xor0 = v[b] ^ v[c]
+               xor1 = v[b + 1] ^ v[c + 1]
+               v[b] = (xor0 >>> 24) ^ (xor1 << 8)
+               v[b + 1] = (xor1 >>> 24) ^ (xor0 << 8)
+
+               ADD64AA(v, a, b)
+               ADD64AC(v, a, y0, y1)
+
+               // v[d,d+1] = (v[d,d+1] xor v[a,a+1]) rotated right by 16 bits
+               xor0 = v[d] ^ v[a]
+               xor1 = v[d + 1] ^ v[a + 1]
+               v[d] = (xor0 >>> 16) ^ (xor1 << 16)
+               v[d + 1] = (xor1 >>> 16) ^ (xor0 << 16)
+
+               ADD64AA(v, c, d)
+
+               // v[b,b+1] = (v[b,b+1] xor v[c,c+1]) rotated right by 63 bits
+               xor0 = v[b] ^ v[c]
+               xor1 = v[b + 1] ^ v[c + 1]
+               v[b] = (xor1 >>> 31) ^ (xor0 << 1)
+               v[b + 1] = (xor0 >>> 31) ^ (xor1 << 1)
        }
-       v[a] = o0
-       v[a + 1] = o1
-}
 
-/**
-* 64-bit unsigned addition
-* Sets v[a,a+1] += b
-* b0 is the low 32 bits of b, b1 represents the high 32 bits
-*/
-function ADD64AC (v, a, b0, b1) {
-       var o0 = v[a] + b0
-       if (b0 < 0) {
-               o0 += 0x100000000
-       }
-       var o1 = v[a + 1] + b1
-       if (o0 >= 0x100000000) {
-               o1++
-       }
-       v[a] = o0
-       v[a + 1] = o1
-}
+       /**
+       * Compression function. 'last' flag indicates last block.
+       * Note we're representing 16 uint64s as 32 uint32s
+       */
+       const blake2bCompress = function (ctx, last) {
+               var i = 0
+
+               // init work variables
+               for (i = 0; i < 16; i++) {
+                       v[i] = ctx.h[i]
+                       v[i + 16] = BLAKE2B_IV32[i]
+               }
 
-// Little-endian byte access
-function B2B_GET32 (arr, i) {
-       return (arr[i] ^
-               (arr[i + 1] << 8) ^
-               (arr[i + 2] << 16) ^
-               (arr[i + 3] << 24))
-}
+               // low 64 bits of offset
+               v[24] = v[24] ^ ctx.t
+               v[25] = v[25] ^ (ctx.t / 0x100000000)
+               // high 64 bits not supported, offset may not be higher than 2**53-1
 
-/**
-* G Mixing function
-* The ROTRs are inlined for speed
-*/
-function B2B_G (a, b, c, d, ix, iy) {
-       var x0 = m[ix]
-       var x1 = m[ix + 1]
-       var y0 = m[iy]
-       var y1 = m[iy + 1]
-
-       ADD64AA(v, a, b) // v[a,a+1] += v[b,b+1] ... in JS we must store a uint64 as two uint32s
-       ADD64AC(v, a, x0, x1) // v[a, a+1] += x ... x0 is the low 32 bits of x, x1 is the high 32 bits
-
-       // v[d,d+1] = (v[d,d+1] xor v[a,a+1]) rotated to the right by 32 bits
-       var xor0 = v[d] ^ v[a]
-       var xor1 = v[d + 1] ^ v[a + 1]
-       v[d] = xor1
-       v[d + 1] = xor0
-
-       ADD64AA(v, c, d)
-
-       // v[b,b+1] = (v[b,b+1] xor v[c,c+1]) rotated right by 24 bits
-       xor0 = v[b] ^ v[c]
-       xor1 = v[b + 1] ^ v[c + 1]
-       v[b] = (xor0 >>> 24) ^ (xor1 << 8)
-       v[b + 1] = (xor1 >>> 24) ^ (xor0 << 8)
-
-       ADD64AA(v, a, b)
-       ADD64AC(v, a, y0, y1)
-
-       // v[d,d+1] = (v[d,d+1] xor v[a,a+1]) rotated right by 16 bits
-       xor0 = v[d] ^ v[a]
-       xor1 = v[d + 1] ^ v[a + 1]
-       v[d] = (xor0 >>> 16) ^ (xor1 << 16)
-       v[d + 1] = (xor1 >>> 16) ^ (xor0 << 16)
-
-       ADD64AA(v, c, d)
-
-       // v[b,b+1] = (v[b,b+1] xor v[c,c+1]) rotated right by 63 bits
-       xor0 = v[b] ^ v[c]
-       xor1 = v[b + 1] ^ v[c + 1]
-       v[b] = (xor1 >>> 31) ^ (xor0 << 1)
-       v[b + 1] = (xor0 >>> 31) ^ (xor1 << 1)
-}
+               // last block flag set ?
+               if (last) {
+                       v[28] = ~v[28]
+                       v[29] = ~v[29]
+               }
 
-// Initialization Vector
-var BLAKE2B_IV32 = new Uint32Array([
-       0xF3BCC908, 0x6A09E667, 0x84CAA73B, 0xBB67AE85,
-       0xFE94F82B, 0x3C6EF372, 0x5F1D36F1, 0xA54FF53A,
-       0xADE682D1, 0x510E527F, 0x2B3E6C1F, 0x9B05688C,
-       0xFB41BD6B, 0x1F83D9AB, 0x137E2179, 0x5BE0CD19
-])
-
-var SIGMA8 = [
-       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
-       14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
-       11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
-       7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
-       9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
-       2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
-       12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
-       13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
-       6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
-       10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
-       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
-       14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3
-]
+               // get little-endian words
+               for (i = 0; i < 32; i++) {
+                       m[i] = B2B_GET32(ctx.b, 4 * i)
+               }
 
-/**
-* These are offsets into a uint64 buffer.
-* Multiply them all by 2 to make them offsets into a uint32 buffer,
-* because this is Javascript and we don't have uint64s
-*/
-var SIGMA82 = new Uint8Array(SIGMA8.map(function (x) { return x * 2 }))
+               // twelve rounds of mixing
+               for (i = 0; i < 12; i++) {
+                       B2B_G(0, 8, 16, 24, SIGMA82[i * 16 + 0], SIGMA82[i * 16 + 1])
+                       B2B_G(2, 10, 18, 26, SIGMA82[i * 16 + 2], SIGMA82[i * 16 + 3])
+                       B2B_G(4, 12, 20, 28, SIGMA82[i * 16 + 4], SIGMA82[i * 16 + 5])
+                       B2B_G(6, 14, 22, 30, SIGMA82[i * 16 + 6], SIGMA82[i * 16 + 7])
+                       B2B_G(0, 10, 20, 30, SIGMA82[i * 16 + 8], SIGMA82[i * 16 + 9])
+                       B2B_G(2, 12, 22, 24, SIGMA82[i * 16 + 10], SIGMA82[i * 16 + 11])
+                       B2B_G(4, 14, 16, 26, SIGMA82[i * 16 + 12], SIGMA82[i * 16 + 13])
+                       B2B_G(6, 8, 18, 28, SIGMA82[i * 16 + 14], SIGMA82[i * 16 + 15])
+               }
 
-/**
-* Compression function. 'last' flag indicates last block.
-* Note we're representing 16 uint64s as 32 uint32s
-*/
-var v = new Uint32Array(32)
-var m = new Uint32Array(32)
-function blake2bCompress (ctx, last) {
-       var i = 0
-
-       // init work variables
-       for (i = 0; i < 16; i++) {
-               v[i] = ctx.h[i]
-               v[i + 16] = BLAKE2B_IV32[i]
+               for (i = 0; i < 16; i++) {
+                       ctx.h[i] = ctx.h[i] ^ v[i] ^ v[i + 16]
+               }
        }
 
-       // low 64 bits of offset
-       v[24] = v[24] ^ ctx.t
-       v[25] = v[25] ^ (ctx.t / 0x100000000)
-       // high 64 bits not supported, offset may not be higher than 2**53-1
-
-       // last block flag set ?
-       if (last) {
-               v[28] = ~v[28]
-               v[29] = ~v[29]
+       const update = function (input: Uint8Array) {
+               console.log(`this: ${this}`)
+               console.dir(this)
+               if (!(input instanceof Uint8Array))
+                       throw new TypeError(`input must be Uint8Array or Buffer`)
+               blake2bUpdate(this, input)
+               return { "update": update.bind(this), "digest": digest.bind(this) }
        }
 
-       // get little-endian words
-       for (i = 0; i < 32; i++) {
-               m[i] = B2B_GET32(ctx.b, 4 * i)
+       function digest (out: 'hex'): string
+       function digest (out?: 'binary' | Uint8Array): Uint8Array
+       function digest (out?: 'binary' | 'hex' | Uint8Array): string | Uint8Array {
+               var buf = (!out || out === 'binary' || out === 'hex') ? new Uint8Array(outlen) : out
+               if (!(buf instanceof Uint8Array))
+                       throw new TypeError(`out must be "binary", "hex", Uint8Array, or Buffer`)
+               if (buf.length < outlen)
+                       throw new RangeError(`out must have at least outlen bytes of space`)
+               blake2bFinal(this, buf)
+               if (out === 'hex') return hexSlice(buf)
+               return buf
        }
 
-       // twelve rounds of mixing
-       for (i = 0; i < 12; i++) {
-               B2B_G(0, 8, 16, 24, SIGMA82[i * 16 + 0], SIGMA82[i * 16 + 1])
-               B2B_G(2, 10, 18, 26, SIGMA82[i * 16 + 2], SIGMA82[i * 16 + 3])
-               B2B_G(4, 12, 20, 28, SIGMA82[i * 16 + 4], SIGMA82[i * 16 + 5])
-               B2B_G(6, 14, 22, 30, SIGMA82[i * 16 + 6], SIGMA82[i * 16 + 7])
-               B2B_G(0, 10, 20, 30, SIGMA82[i * 16 + 8], SIGMA82[i * 16 + 9])
-               B2B_G(2, 12, 22, 24, SIGMA82[i * 16 + 10], SIGMA82[i * 16 + 11])
-               B2B_G(4, 14, 16, 26, SIGMA82[i * 16 + 12], SIGMA82[i * 16 + 13])
-               B2B_G(6, 8, 18, 28, SIGMA82[i * 16 + 14], SIGMA82[i * 16 + 15])
+       /**
+       * Updates a BLAKE2b streaming hash
+       * Requires hash context and Uint8Array (byte array)
+       */
+       const blake2bUpdate = function (ctx, input: Uint8Array) {
+               for (var i = 0; i < input.length; i++) {
+                       if (ctx.c === 128) { // buffer full ?
+                               ctx.t += ctx.c // add counters
+                               blake2bCompress(ctx, false) // compress (not last)
+                               ctx.c = 0 // counter to zero
+                       }
+                       ctx.b[ctx.c++] = input[i]
+               }
        }
 
-       for (i = 0; i < 16; i++) {
-               ctx.h[i] = ctx.h[i] ^ v[i] ^ v[i + 16]
-       }
-}
+       /**
+       * Completes a BLAKE2b streaming hash
+       * Returns a Uint8Array containing the message digest
+       */
+       const blake2bFinal = function (ctx, out: Uint8Array) {
+               ctx.t += ctx.c // mark last block offset
 
-// reusable parameter_block
-var parameter_block = new Uint8Array([
-       0, 0, 0, 0,      //  0: outlen, keylen, fanout, depth
-       0, 0, 0, 0,      //  4: leaf length, sequential mode
-       0, 0, 0, 0,      //  8: node offset
-       0, 0, 0, 0,      // 12: node offset
-       0, 0, 0, 0,      // 16: node depth, inner length, rfu
-       0, 0, 0, 0,      // 20: rfu
-       0, 0, 0, 0,      // 24: rfu
-       0, 0, 0, 0,      // 28: rfu
-       0, 0, 0, 0,      // 32: salt
-       0, 0, 0, 0,      // 36: salt
-       0, 0, 0, 0,      // 40: salt
-       0, 0, 0, 0,      // 44: salt
-       0, 0, 0, 0,      // 48: personal
-       0, 0, 0, 0,      // 52: personal
-       0, 0, 0, 0,      // 56: personal
-       0, 0, 0, 0       // 60: personal
-])
-
-static function update (input: Uint8Array) {
-       if (!(input instanceof Uint8Array))
-               throw new TypeError(`input must be Uint8Array or Buffer`)
-       blake2bUpdate(this, input)
-       return this
-}
+               while (ctx.c < 128) { // fill up with zeros
+                       ctx.b[ctx.c++] = 0
+               }
+               blake2bCompress(ctx, true) // final block flag = 1
 
-Blake2b.prototype.digest = function (out?: 'binary' | 'hex' | Uint8Array) {
-       var buf = (!out || out === 'binary' || out === 'hex') ? new Uint8Array(this.outlen) : out
-       if (!(buf instanceof Uint8Array))
-               throw new TypeError(`out must be "binary", "hex", Uint8Array, or Buffer`)
-       if (buf.length < this.outlen)
-               throw new RangeError(`out must have at least outlen bytes of space`)
-       blake2bFinal(this, buf)
-       if (out === 'hex') return hexSlice(buf)
-       return buf
-}
+               for (var i = 0; i < ctx.outlen; i++) {
+                       out[i] = ctx.h[i >> 2] >> (8 * (i & 3))
+               }
+               return out
+       }
 
-Blake2b.prototype.final = Blake2b.prototype.digest
+       const hexSlice = function (buf: Uint8Array) {
+               var str = ''
+               for (var i = 0; i < buf.length; i++) str += toHex(buf[i])
+               return str
+       }
 
-/**
-* Updates a BLAKE2b streaming hash
-* Requires hash context and Uint8Array (byte array)
-*/
-function blake2bUpdate (ctx, input: Uint8Array) {
-       for (var i = 0; i < input.length; i++) {
-               if (ctx.c === 128) { // buffer full ?
-                       ctx.t += ctx.c // add counters
-                       blake2bCompress(ctx, false) // compress (not last)
-                       ctx.c = 0 // counter to zero
-               }
-               ctx.b[ctx.c++] = input[i]
+       const toHex = function (n: number) {
+               if (typeof n !== 'number')
+                       throw new TypeError(`expected number to convert to hex, received convert ${typeof n}`)
+               if (n < 0 || n > 255)
+                       throw new RangeError(`expected byte value 0-255, received ${n}`)
+               return n.toString(16).padStart(2, '0')
        }
-}
 
-/**
-* Completes a BLAKE2b streaming hash
-* Returns a Uint8Array containing the message digest
-*/
-function blake2bFinal (ctx, out: Uint8Array) {
-       ctx.t += ctx.c // mark last block offset
+       /**
+       * Creates a BLAKE2b hashing context
+       * Requires an output length between 1 and 64 bytes
+       * Takes an optional Uint8Array key
+       */
+       const Blake2b = function (outlen: number, key?: Uint8Array, salt?: Uint8Array, personal?: Uint8Array) {
+               // zero out parameter_block before usage
+               parameter_block.fill(0)
+               // state, 'param block'
+
+               let b = new Uint8Array(128)
+               let h = new Uint32Array(16)
+               let t = 0 // input count
+               let c = 0 // pointer within buffer
+               // let outlen = outlen // output length in bytes
+
+               parameter_block[0] = outlen
+               if (key) parameter_block[1] = key.length
+               parameter_block[2] = 1 // fanout
+               parameter_block[3] = 1 // depth
+
+               if (salt) parameter_block.set(salt, 32)
+               if (personal) parameter_block.set(personal, 48)
+
+               // initialize hash state
+               for (var i = 0; i < 16; i++) {
+                       h[i] = BLAKE2B_IV32[i] ^ B2B_GET32(parameter_block, i * 4)
+               }
 
-       while (ctx.c < 128) { // fill up with zeros
-               ctx.b[ctx.c++] = 0
+               // key the hash, if applicable
+               if (key) {
+                       blake2bUpdate({ b, h, t, c, outlen }, key)
+                       // at the end
+                       c = 128
+               }
+               return { "update": update.bind({ b, h, t, c, outlen }), "digest": digest.bind({ b, h, t, c, outlen }) }
        }
-       blake2bCompress(ctx, true) // final block flag = 1
 
-       for (var i = 0; i < ctx.outlen; i++) {
-               out[i] = ctx.h[i >> 2] >> (8 * (i & 3))
+       // finally execute the original function call
+       if (noAssert !== true) {
+               if (outlen < BYTES_MIN)
+                       throw new RangeError(`outlen must be at least ${BYTES_MIN}, was given ${outlen}`)
+               if (outlen > BYTES_MAX)
+                       throw new RangeError(`outlen must be at most ${BYTES_MAX}, was given ${outlen}`)
+               if (key != null) {
+                       if (!(key instanceof Uint8Array))
+                               throw new TypeError(`key must be Uint8Array or Buffer`)
+                       if (key.length < KEYBYTES_MIN)
+                               throw new RangeError(`key must be at least ${KEYBYTES_MIN}, was given ${key.length}`)
+                       if (key.length > KEYBYTES_MAX)
+                               throw new RangeError(`key must be at most ${KEYBYTES_MAX}, was given ${key.length}`)
+               }
+               if (salt != null) {
+                       if (!(salt instanceof Uint8Array))
+                               throw new TypeError(`salt must be Uint8Array or Buffer`)
+                       if (salt.length !== SALTBYTES)
+                               throw new RangeError(`salt must be exactly ${SALTBYTES}, was given ${salt.length}`)
+               }
+               if (personal != null) {
+                       if (!(personal instanceof Uint8Array))
+                               throw new TypeError(`personal must be Uint8Array or Buffer`)
+                       if (personal.length !== PERSONALBYTES)
+                               throw new RangeError(`personal must be exactly ${PERSONALBYTES}, was given ${personal.length}`)
+               }
        }
-       return out
-}
 
-function hexSlice (buf: Uint8Array) {
-       var str = ''
-       for (var i = 0; i < buf.length; i++) str += toHex(buf[i])
-       return str
+       return Blake2b(outlen, key, salt, personal)
 }
 
-function toHex (n: number) {
-       if (typeof n !== 'number')
-               throw new TypeError(`expected number to convert to hex, received convert ${typeof n}`)
-       if (n < 0 || n > 255)
-               throw new RangeError(`expected byte value 0-255, received ${n}`)
-       return n.toString(16).padStart(2, '0')
-}
-}
+export { blake2b }
+export default blake2b.toString()
index 5a69f6b5b4ce7471699eaa1b50930b49dccde931..950cf88b4cb6a00d3b1d74f399c951ad9185804a 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>\r
 // SPDX-License-Identifier: GPL-3.0-or-later\r
 \r
-import { fn } from './blake2b.js'\r
+import blake2b from './blake2b.js'\r
 import { ckdBip44, ckdBlake2b } from './workers.js'\r
 import { Account } from './account.js'\r
 import { Bip39Mnemonic } from './bip39-mnemonic.js'\r
@@ -576,7 +576,7 @@ export class Blake2bWallet extends Wallet {
        async ckd (index: number | number[]): Promise<Account[]> {\r
                if (!Array.isArray(index)) index = [index]\r
                const data: any = []\r
-               index.forEach(i => data.push({ seed: this.seed, index: i, b2b: fn }))\r
+               index.forEach(i => data.push({ seed: this.seed, index: i, blake2b }))\r
                let now = performance.now()\r
                const results: [{ index: number, key: string }] = await this.#pool.work(data)\r
                console.log(`ckd: ${-now + (now = performance.now())} ms`)\r
index ff5174d08c421ad86d47ec624fa312493ee83006..c8e277b6dec34e7c6bff33d254b6417ea38f3f02 100644 (file)
@@ -6,8 +6,9 @@ async function fn () {
        * Listens for messages from a calling function.
        */
        addEventListener('message', (message) => {
-               const { seed, index, b2b } = message.data ?? message
-               ckdBlake2b(seed, index, b2b).then(key => postMessage({ index, key }))
+               console.log('message received')
+               const { seed, index, blake2b } = message.data ?? message
+               ckdBlake2b(seed, index, blake2b).then(key => postMessage({ index, key }))
        })
 
        /**
@@ -16,8 +17,9 @@ async function fn () {
        * @param {number} index - Index of the account
        * @returns {Promise<string>}
        */
-       async function ckdBlake2b (seed: string, index: number, b2b: string): Promise<string> {
-               const blake2b = Function(b2b)
+       async function ckdBlake2b (seed: string, index: number, b2b: any): Promise<string> {
+               const blake2b = Function(`return ${b2b}`)()
+               console.log(blake2b)
                const indexHex = index.toString(16).padStart(8, '0').toUpperCase()
                const inputHex = `${seed}${indexHex}`.padStart(72, '0')
                const inputArray = (inputHex.match(/.{1,2}/g) ?? []).map(h => parseInt(h, 16))