]> git.codecow.com Git - nano25519.git/commitdiff
Generate blake hashing to unroll long loops.
authorChris Duncan <chris@codecow.com>
Thu, 24 Sep 2026 19:57:08 +0000 (12:57 -0700)
committerChris Duncan <chris@codecow.com>
Thu, 24 Sep 2026 19:57:08 +0000 (12:57 -0700)
12 files changed:
esbuild/config.mjs
package.json
scripts/blake2b-gen.mjs [new file with mode: 0644]
src/assembly/crypto_sign.ts
src/assembly/ed25519/blake2b.ts
src/assembly/ed25519/crypto_sign.ts [deleted file]
src/assembly/env.ts
src/assembly/index.ts
src/lib/errors.ts
src/lib/verify.ts
src/lib/wasm.ts
test/vectors.mjs

index e5e5f321bb075a4860a89bc4d82bd76b88061cd5..64f819847f5e8ec0e394bc4e1875f720e4fbfe62 100644 (file)
@@ -10,9 +10,9 @@ build({
        outfile: 'test/vectors.mjs',
        banner: {
                js: `/**
-* This file is automatically generated during the build process.
-* Add or modify test vectors from the files in the test/vectors directory.
-*/`
+ * This file is automatically generated during the build process.
+ * Add or modify test vectors from the files in the test/vectors directory.
+ */`
        }
 })
 
index 6119d47e25b25e020b4150c41e52f0046b3387b9..ce4c0137bb1349de24fb0e489ddd842a3c872a68 100644 (file)
@@ -34,7 +34,7 @@
                "build": "npm run clean && npm run compile && node ./esbuild/dev.mjs",
                "build:prod": "npm run clean && npm run compile && node ./esbuild/prod.mjs",
                "clean": "rm -rf {build,dist}",
-               "compile": "asc ./src/assembly/index.ts && tsc",
+               "compile": "node scripts/blake2b-gen.mjs && asc ./src/assembly/index.ts && tsc",
                "prepublishOnly": "npm run test:prod",
                "test": "npm run build && node ./test/node.mjs",
                "test:prod": "npm run build:prod && node ./test/node.mjs"
diff --git a/scripts/blake2b-gen.mjs b/scripts/blake2b-gen.mjs
new file mode 100644 (file)
index 0000000..f0bb7f4
--- /dev/null
@@ -0,0 +1,300 @@
+//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
+//! SPDX-License-Identifier: GPL-3.0-or-later
+
+/**
+ * Generate the BLAKE2b hashing algorithm for WebAssembly API. Specifically, it
+ * outputs `asm/index.ts`, an AssemblyScript file that must be compiled as part
+ * of a WASM module.
+ *
+ * Some whitespace output is removed for brevity in the final files, which
+ * should be checked separately for correctness using language-specific tools
+ * e.g. `wgsl-analyzer` or `asc`
+ */
+
+import { writeFile } from 'node:fs/promises'
+
+const blake2b_state = [
+       [0, 4, 8, 12],
+       [1, 5, 9, 13],
+       [2, 6, 10, 14],
+       [3, 7, 11, 15],
+       [0, 5, 10, 15],
+       [1, 6, 11, 12],
+       [2, 7, 8, 13],
+       [3, 4, 9, 14]
+]
+
+const blake2b_sigma = [
+       [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]
+]
+
+/**
+ * Initialization vector defined by BLAKE2.
+ *
+ * Application of each XOR is defined by BLAKE2 section 2.4 compression
+ * function. Each value represents two halves of the original u64 value from
+ * the reference implementation. They appear reversed pairwise in order to
+ * align with little-endian computation.
+ */
+const blake2b_iv = [
+       `0x6a09e667f3bcc908`,
+       `0xbb67ae8584caa73b`,
+       `0x3c6ef372fe94f82b`,
+       `0xa54ff53a5f1d36f1`,
+       `0x510e527fade682d1`,
+       `0x9b05688c2b3e6c1f`,
+       `0x1f83d9abfb41bd6b`,
+       `0x5be0cd19137e2179`
+]
+
+const B_LENGTH = 128
+const H_LENGTH = 8
+
+const DECLARATIONS = (() => {
+       let output = `
+               /**
+                * Buffers and counters
+                * - b: input buffer, filled and refilled by input data in ${B_LENGTH} byte increments
+                * - c: buffer counter, points to current index in \`b\`
+                * - h: chain buffer, updated after each compression
+                * - p: set according to BLAKE2 layout from constructor arguments
+                * - t: total byte counter, incremented by \`c\`
+                *   - Note: BLAKE2b reference supports 2¹²⁸-1, but this implementation restricts to 2⁶⁴-1 for compatibility with WASM without SIMD)
+                */
+               b: StaticArray<u8> = new StaticArray<u8>(${B_LENGTH})
+               c: i32 = 0
+               h: StaticArray<u64> = new StaticArray<u64>(${H_LENGTH})
+               p: StaticArray<u8> = new StaticArray<u8>(64)
+               t: u64 = 0
+
+               ${COMPRESS()}
+       `
+       return output
+})()
+
+function CLEAR () {
+       let output = `
+               this.b.fill(0)
+               this.c = 0
+               this.h.fill(0)
+               this.p.fill(0)
+               this.t = 0
+       `
+
+       return output
+}
+
+const INIT = (() => {
+       let output = `
+               init(): Blake2b {
+                       // reset buffers and counters
+                       ${CLEAR()}
+
+                       // initialize parameter block
+                       this.p[0] = 64 // always 64 bytes for this implementation
+                       this.p[1] = 0 // no key
+                       this.p[2] = 1 // fanout
+                       this.p[3] = 1 // depth
+       `
+
+       output += `
+               // initialize hash state
+       `
+       for (let i = 0; i < H_LENGTH; i++) {
+               output += `
+                       this.h[${i}] = ${blake2b_iv[i]}
+               `
+       }
+
+       output += `
+               for (let i = 0; i < ${H_LENGTH}; i++) {
+                       this.h[i] ^= load<u64>(changetype<usize>(this.p) + (i << 3))
+               }
+               return this
+       }
+       `
+
+       return output
+})()
+
+/**
+ * Mixing function as defined in BLAKE2.
+ *
+ * @param {number} a - G mixing index
+ * @param {number} b - G mixing index
+ * @param {number} c - G mixing index
+ * @param {number} d - G mixing index
+ * @param {number} x - SIGMA index for first message block
+ * @param {number} y - SIGMA index for second message block
+ * @returns {string} Unrolled code for a pass of columnar and diagonal mixing
+ */
+function G (a, b, c, d, x, y) {
+       return `
+               v${a} = v${a} + v${b} + m${x}
+               v${d} = rotr<u64>(v${d} ^ v${a}, 32)
+               v${c} = v${c} + v${d}
+               v${b} = rotr<u64>(v${b} ^ v${c}, 24)
+               v${a} = v${a} + v${b} + m${y}
+               v${d} = rotr<u64>(v${d} ^ v${a}, 16)
+               v${c} = v${c} + v${d}
+               v${b} = rotr<u64>(v${b} ^ v${c}, 63)
+       `
+}
+
+/**
+ * Builds string of code for calling G mixing function as defined by BLAKE2.
+ *
+ * @param {number} r
+ * @returns {string} Unrolled code for 8 passes of G
+ */
+function ROUND (r) {
+       let output = `
+               // ROUND ${r}
+       `
+       for (let i = 0; i < 8; i++) {
+               const a = blake2b_state[i][0]
+               const b = blake2b_state[i][1]
+               const c = blake2b_state[i][2]
+               const d = blake2b_state[i][3]
+               const s = blake2b_sigma[r]
+               output += G(a, b, c, d, s[i << 1], s[(i << 1) + 1])
+       }
+       return output
+}
+
+/**
+ * Builds string of code that first initializes the BLAKE2b state vectors and
+ * then compresses the input message. For Nano proof-of-work, the input is
+ * only 40 bytes, so compression only happens once.
+ *
+ * @returns {string} API-specific code executing 12 rounds of G mixing
+ */
+function COMPRESS () {
+       let output = `
+               // COMPRESS
+               // Defined in BLAKE2 section 2.4
+               compress (isFinal: u64): void {
+               // initialize compression buffers
+               // - m: message buffer, represents current state of \`b\` during compression
+               // - v: state vector, set to bytes of \`h\` and \`iv\` then modified by \`t\` during compression
+       `
+       for (let i = 0; i < H_LENGTH; i++) {
+               output += `
+                       let v${i}: u64 = this.h[${i}]
+                       let v${i + H_LENGTH}: u64 = ${blake2b_iv[i]}
+               `
+       }
+
+       output += `
+               // lo 64 bits of counter
+               v${12} ^= this.t
+
+               // hi 64 bits of counter, always 0 in this implementation
+               v${13} ^= 0
+
+               // flip bits if "last block" flag is set so that v14 = ~v14
+               v${14} ^= isFinal
+
+               // copy input buffer to message block
+               const b_ptr = changetype<usize>(this.b)
+       `
+
+       for (let i = 0; i < 16; i++) {
+               output += `
+                       let m${i}: u64 = load<u64>(b_ptr + ${i << 3})
+               `
+       }
+
+       output += `
+               // twelve rounds of mixing
+       `
+       for (let r = 0; r < 12; r++) {
+               output += ROUND(r)
+       }
+
+       output += `
+               // set new chain value
+       `
+       for (let i = 0; i < H_LENGTH; i++) {
+               output += `
+                       this.h[${i}] ^= v${i} ^ v${i + H_LENGTH}
+               `
+       }
+
+       output += `
+               }
+       `
+       return output
+}
+
+const BLAKE2b = `//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
+//! SPDX-License-Identifier: GPL-3.0-or-later
+
+export class Blake2b {
+       ${DECLARATIONS}
+       ${INIT}
+       // input: variable-length message bytes passed by user to be hashed
+       update (input: StaticArray<u8>, length: i32): Blake2b {
+               const input_ptr: usize = changetype<usize>(input)
+               const b_ptr: usize = changetype<usize>(this.b)
+
+               let i = 0;
+               while (i < length) {
+
+                       // is buffer full?
+                       if (this.c === ${B_LENGTH}) {
+
+                               // increment total byte counter
+                               this.t += ${B_LENGTH}
+
+                               // reset buffer counter to zero
+                               this.c = 0
+
+                               // compress (not final)
+                               this.compress(0)
+
+                       } else {
+                               const b_rem = ${B_LENGTH} - this.c
+                               const l_rem = length - i
+                               const n = b_rem < l_rem ? b_rem : l_rem
+                               memory.copy(b_ptr + this.c, input_ptr + i, n)
+                               this.c += n
+                               i += n
+                       }
+               }
+               return this
+       }
+
+       // output: 64-byte hash of original message input
+       digest (output: StaticArray<u8>): void {
+
+               // add final message block size to total bytes
+               this.t += this.c
+
+               // pad final block with zeros
+               this.b.fill(0, this.c)
+
+               // set final block flag and compress
+               this.compress(u64(0 - 1))
+
+               // return byte array of 64-byte chain buffer
+               memory.copy(changetype<usize>(output), changetype<usize>(this.h), 64)
+
+               // clear internal buffers and counters
+               ${CLEAR()}
+       }
+}
+`
+
+await writeFile('src/assembly/ed25519/blake2b.ts', BLAKE2b)
index 064e493e5b7a50c813b003c79638959aecd8a5b1..8ed0acc01b52eac53ed3274cdc4253b83ef4d9e8 100644 (file)
@@ -2,7 +2,6 @@
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
 import { KEY_BYTELENGTH } from './constants'
-import { crypto_derive } from './crypto_derive'
 import { Blake2b } from './ed25519/blake2b'
 import { ge_scalarmult_base_tobytes } from './ed25519/ge'
 import { sc_muladd, sc_reduce } from './ed25519/sc'
@@ -40,14 +39,15 @@ const S = new StaticArray<u8>(64)
  * @param {StaticArray<u8>} pub 32-byte public key from input buffer
  */
 export function crypto_sign (RS: StaticArray<u8>, M: StaticArray<u8>, mlen: i32, prv: StaticArray<u8>, pub: StaticArray<u8>): i32 {
-       // Derive `A` from private key
-       crypto_derive(A, prv)
-       let c = 0
-       for (let i = 0; i < KEY_BYTELENGTH; i++) {
-               c |= A[i] ^ pub[i]
-       }
-       // Return early if `A` does not match public key
-       if (c != 0) return -1
+       // // Derive `A` from private key
+       // crypto_derive(A, prv)
+       // let c = 0
+       // for (let i = 0; i < KEY_BYTELENGTH; i++) {
+       //      c |= A[i] ^ pub[i]
+       // }
+       // // Return early if `A` does not match public key
+       // if (c != 0) return c
+       memory.copy(changetype<usize>(A), changetype<usize>(pub), 32)
 
        // Hash private key to `h`
        blake2b.init().update(prv, KEY_BYTELENGTH).digest(h)
index eb380cde45c0388b68bed2c9f960587fd7c8fbef..93a707111318b03e2ae4bf5d37b5c8d49a791d03 100644 (file)
 //! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-const blake2b_state = StaticArray.fromArray([
-       StaticArray.fromArray<u8>([0, 4, 8, 12]),
-       StaticArray.fromArray<u8>([1, 5, 9, 13]),
-       StaticArray.fromArray<u8>([2, 6, 10, 14]),
-       StaticArray.fromArray<u8>([3, 7, 11, 15]),
-       StaticArray.fromArray<u8>([0, 5, 10, 15]),
-       StaticArray.fromArray<u8>([1, 6, 11, 12]),
-       StaticArray.fromArray<u8>([2, 7, 8, 13]),
-       StaticArray.fromArray<u8>([3, 4, 9, 14])
-])
-
-const blake2b_sigma = StaticArray.fromArray([
-       StaticArray.fromArray<u8>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
-       StaticArray.fromArray<u8>([14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]),
-       StaticArray.fromArray<u8>([11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4]),
-       StaticArray.fromArray<u8>([7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8]),
-       StaticArray.fromArray<u8>([9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13]),
-       StaticArray.fromArray<u8>([2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9]),
-       StaticArray.fromArray<u8>([12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11]),
-       StaticArray.fromArray<u8>([13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10]),
-       StaticArray.fromArray<u8>([6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5]),
-       StaticArray.fromArray<u8>([10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]),
-       StaticArray.fromArray<u8>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
-       StaticArray.fromArray<u8>([14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3])
-])
-
-// Initialization vector defined by BLAKE2.
-const blake2b_iv = StaticArray.fromArray<u64>([
-       0x6a09e667f3bcc908,
-       0xbb67ae8584caa73b,
-       0x3c6ef372fe94f82b,
-       0xa54ff53a5f1d36f1,
-       0x510e527fade682d1,
-       0x9b05688c2b3e6c1f,
-       0x1f83d9abfb41bd6b,
-       0x5be0cd19137e2179
-])
-
 export class Blake2b {
 
-       /**
-       * Buffers and counters
-       * - b: input buffer, filled and refilled by input data in 128 byte increments
-       * - c: buffer counter, points to current index in `b`
-       * - h: chain buffer, updated after each compression
-       * - m: message buffer, represents current state of `b` during compression
-       * - p: set according to BLAKE2 layout from constructor arguments
-       * - t: total byte counter, incremented by `c` (BLAKE2b supports 2¹²⁸-1)
-       * - v: state vector, set to bytes of `h` and `iv` then modified by `t` during compression
-       */
-       b: StaticArray<u8> = new StaticArray<u8>(128)
-       c: u8 = 0
-       h: StaticArray<u64> = new StaticArray<u64>(8)
-       m: StaticArray<u64> = new StaticArray<u64>(16)
-       p: StaticArray<u8> = new StaticArray<u8>(64)
-       t: v128 = v128.splat<u64>(0)
-       v: StaticArray<u64> = new StaticArray<u64>(16)
-
-       @inline
-       clear (): void {
+       
+               /**
+                * Buffers and counters
+                * - b: input buffer, filled and refilled by input data in 128 byte increments
+                * - c: buffer counter, points to current index in `b`
+                * - h: chain buffer, updated after each compression
+                * - p: set according to BLAKE2 layout from constructor arguments
+                * - t: total byte counter, incremented by `c`
+                *   - Note: BLAKE2b reference supports 2¹²⁸-1, but this implementation restricts to 2⁶⁴-1 for compatibility with WASM without SIMD)
+                */
+               b: StaticArray<u8> = new StaticArray<u8>(128)
+               c: i32 = 0
+               h: StaticArray<u64> = new StaticArray<u64>(8)
+               p: StaticArray<u8> = new StaticArray<u8>(64)
+               t: u64 = 0
+
+               
+               // COMPRESS
+               // Defined in BLAKE2 section 2.4
+               compress (isFinal: u64): void {
+               // initialize compression buffers
+               // - m: message buffer, represents current state of `b` during compression
+               // - v: state vector, set to bytes of `h` and `iv` then modified by `t` during compression
+       
+                       let v0: u64 = this.h[0]
+                       let v8: u64 = 0x6a09e667f3bcc908
+               
+                       let v1: u64 = this.h[1]
+                       let v9: u64 = 0xbb67ae8584caa73b
+               
+                       let v2: u64 = this.h[2]
+                       let v10: u64 = 0x3c6ef372fe94f82b
+               
+                       let v3: u64 = this.h[3]
+                       let v11: u64 = 0xa54ff53a5f1d36f1
+               
+                       let v4: u64 = this.h[4]
+                       let v12: u64 = 0x510e527fade682d1
+               
+                       let v5: u64 = this.h[5]
+                       let v13: u64 = 0x9b05688c2b3e6c1f
+               
+                       let v6: u64 = this.h[6]
+                       let v14: u64 = 0x1f83d9abfb41bd6b
+               
+                       let v7: u64 = this.h[7]
+                       let v15: u64 = 0x5be0cd19137e2179
+               
+               // lo 64 bits of counter
+               v12 ^= this.t
+
+               // hi 64 bits of counter, always 0 in this implementation
+               v13 ^= 0
+
+               // flip bits if "last block" flag is set so that v14 = ~v14
+               v14 ^= isFinal
+
+               // copy input buffer to message block
+               const b_ptr = changetype<usize>(this.b)
+       
+                       let m0: u64 = load<u64>(b_ptr + 0)
+               
+                       let m1: u64 = load<u64>(b_ptr + 8)
+               
+                       let m2: u64 = load<u64>(b_ptr + 16)
+               
+                       let m3: u64 = load<u64>(b_ptr + 24)
+               
+                       let m4: u64 = load<u64>(b_ptr + 32)
+               
+                       let m5: u64 = load<u64>(b_ptr + 40)
+               
+                       let m6: u64 = load<u64>(b_ptr + 48)
+               
+                       let m7: u64 = load<u64>(b_ptr + 56)
+               
+                       let m8: u64 = load<u64>(b_ptr + 64)
+               
+                       let m9: u64 = load<u64>(b_ptr + 72)
+               
+                       let m10: u64 = load<u64>(b_ptr + 80)
+               
+                       let m11: u64 = load<u64>(b_ptr + 88)
+               
+                       let m12: u64 = load<u64>(b_ptr + 96)
+               
+                       let m13: u64 = load<u64>(b_ptr + 104)
+               
+                       let m14: u64 = load<u64>(b_ptr + 112)
+               
+                       let m15: u64 = load<u64>(b_ptr + 120)
+               
+               // twelve rounds of mixing
+       
+               // ROUND 0
+       
+               v0 = v0 + v4 + m0
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m1
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m2
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m3
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m4
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m5
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m6
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m7
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m8
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m9
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m10
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m11
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m12
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m13
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m14
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m15
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 1
+       
+               v0 = v0 + v4 + m14
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m10
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m4
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m8
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m9
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m15
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m13
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m6
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m1
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m12
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m0
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m2
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m11
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m7
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m5
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m3
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 2
+       
+               v0 = v0 + v4 + m11
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m8
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m12
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m0
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m5
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m2
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m15
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m13
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m10
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m14
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m3
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m6
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m7
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m1
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m9
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m4
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 3
+       
+               v0 = v0 + v4 + m7
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m9
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m3
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m1
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m13
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m12
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m11
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m14
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m2
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m6
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m5
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m10
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m4
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m0
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m15
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m8
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 4
+       
+               v0 = v0 + v4 + m9
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m0
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m5
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m7
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m2
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m4
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m10
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m15
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m14
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m1
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m11
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m12
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m6
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m8
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m3
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m13
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 5
+       
+               v0 = v0 + v4 + m2
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m12
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m6
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m10
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m0
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m11
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m8
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m3
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m4
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m13
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m7
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m5
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m15
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m14
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m1
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m9
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 6
+       
+               v0 = v0 + v4 + m12
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m5
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m1
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m15
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m14
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m13
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m4
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m10
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m0
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m7
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m6
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m3
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m9
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m2
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m8
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m11
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 7
+       
+               v0 = v0 + v4 + m13
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m11
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m7
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m14
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m12
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m1
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m3
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m9
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m5
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m0
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m15
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m4
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m8
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m6
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m2
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m10
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 8
+       
+               v0 = v0 + v4 + m6
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m15
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m14
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m9
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m11
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m3
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m0
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m8
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m12
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m2
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m13
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m7
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m1
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m4
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m10
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m5
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 9
+       
+               v0 = v0 + v4 + m10
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m2
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m8
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m4
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m7
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m6
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m1
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m5
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m15
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m11
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m9
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m14
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m3
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m12
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m13
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m0
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 10
+       
+               v0 = v0 + v4 + m0
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m1
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m2
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m3
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m4
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m5
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m6
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m7
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m8
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m9
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m10
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m11
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m12
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m13
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m14
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m15
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // ROUND 11
+       
+               v0 = v0 + v4 + m14
+               v12 = rotr<u64>(v12 ^ v0, 32)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 24)
+               v0 = v0 + v4 + m10
+               v12 = rotr<u64>(v12 ^ v0, 16)
+               v8 = v8 + v12
+               v4 = rotr<u64>(v4 ^ v8, 63)
+       
+               v1 = v1 + v5 + m4
+               v13 = rotr<u64>(v13 ^ v1, 32)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 24)
+               v1 = v1 + v5 + m8
+               v13 = rotr<u64>(v13 ^ v1, 16)
+               v9 = v9 + v13
+               v5 = rotr<u64>(v5 ^ v9, 63)
+       
+               v2 = v2 + v6 + m9
+               v14 = rotr<u64>(v14 ^ v2, 32)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 24)
+               v2 = v2 + v6 + m15
+               v14 = rotr<u64>(v14 ^ v2, 16)
+               v10 = v10 + v14
+               v6 = rotr<u64>(v6 ^ v10, 63)
+       
+               v3 = v3 + v7 + m13
+               v15 = rotr<u64>(v15 ^ v3, 32)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 24)
+               v3 = v3 + v7 + m6
+               v15 = rotr<u64>(v15 ^ v3, 16)
+               v11 = v11 + v15
+               v7 = rotr<u64>(v7 ^ v11, 63)
+       
+               v0 = v0 + v5 + m1
+               v15 = rotr<u64>(v15 ^ v0, 32)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 24)
+               v0 = v0 + v5 + m12
+               v15 = rotr<u64>(v15 ^ v0, 16)
+               v10 = v10 + v15
+               v5 = rotr<u64>(v5 ^ v10, 63)
+       
+               v1 = v1 + v6 + m0
+               v12 = rotr<u64>(v12 ^ v1, 32)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 24)
+               v1 = v1 + v6 + m2
+               v12 = rotr<u64>(v12 ^ v1, 16)
+               v11 = v11 + v12
+               v6 = rotr<u64>(v6 ^ v11, 63)
+       
+               v2 = v2 + v7 + m11
+               v13 = rotr<u64>(v13 ^ v2, 32)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 24)
+               v2 = v2 + v7 + m7
+               v13 = rotr<u64>(v13 ^ v2, 16)
+               v8 = v8 + v13
+               v7 = rotr<u64>(v7 ^ v8, 63)
+       
+               v3 = v3 + v4 + m5
+               v14 = rotr<u64>(v14 ^ v3, 32)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 24)
+               v3 = v3 + v4 + m3
+               v14 = rotr<u64>(v14 ^ v3, 16)
+               v9 = v9 + v14
+               v4 = rotr<u64>(v4 ^ v9, 63)
+       
+               // set new chain value
+       
+                       this.h[0] ^= v0 ^ v8
+               
+                       this.h[1] ^= v1 ^ v9
+               
+                       this.h[2] ^= v2 ^ v10
+               
+                       this.h[3] ^= v3 ^ v11
+               
+                       this.h[4] ^= v4 ^ v12
+               
+                       this.h[5] ^= v5 ^ v13
+               
+                       this.h[6] ^= v6 ^ v14
+               
+                       this.h[7] ^= v7 ^ v15
+               
+               }
+       
+       
+
+       
+               init(): Blake2b {
+                       // reset buffers and counters
+                       
                this.b.fill(0)
                this.c = 0
                this.h.fill(0)
-               this.m.fill(0)
                this.p.fill(0)
-               this.t = v128.splat<u64>(0)
-               this.v.fill(0)
-       }
-
-       init (): Blake2b {
-               // reset buffers and counters
-               this.clear()
-
-               // initialize parameter block
-               this.p[0] = 64 // always 64 bytes for this implementation
-               this.p[1] = 0 // no key
-               this.p[2] = 1 // fanout
-               this.p[3] = 1 // depth
+               this.t = 0
+       
 
+                       // initialize parameter block
+                       this.p[0] = 64 // always 64 bytes for this implementation
+                       this.p[1] = 0 // no key
+                       this.p[2] = 1 // fanout
+                       this.p[3] = 1 // depth
+       
                // initialize hash state
-               memory.copy(changetype<usize>(this.h), changetype<usize>(blake2b_iv), 64)
+       
+                       this.h[0] = 0x6a09e667f3bcc908
+               
+                       this.h[1] = 0xbb67ae8584caa73b
+               
+                       this.h[2] = 0x3c6ef372fe94f82b
+               
+                       this.h[3] = 0xa54ff53a5f1d36f1
+               
+                       this.h[4] = 0x510e527fade682d1
+               
+                       this.h[5] = 0x9b05688c2b3e6c1f
+               
+                       this.h[6] = 0x1f83d9abfb41bd6b
+               
+                       this.h[7] = 0x5be0cd19137e2179
+               
                for (let i = 0; i < 8; i++) {
                        this.h[i] ^= load<u64>(changetype<usize>(this.p) + (i << 3))
                }
                return this
        }
+       
 
        // input: variable-length message bytes passed by user to be hashed
        update (input: StaticArray<u8>, length: i32): Blake2b {
-               for (let i = 0; i < length; i++) {
+               const input_ptr: usize = changetype<usize>(input)
+               const b_ptr: usize = changetype<usize>(this.b)
+
+               let i = 0;
+               while (i < length) {
 
                        // is buffer full?
-                       if (this.c === this.b.length) {
+                       if (this.c === 128) {
 
                                // increment total byte counter
-                               this.t = v128.add<u64>(this.t, i64x2(this.b.length, u64(v128.extract_lane<u64>(this.t, 0) + u64(this.b.length) < u64(this.b.length))))
+                               this.t += 128
 
                                // reset buffer counter to zero
                                this.c = 0
 
                                // compress (not final)
-                               this.COMPRESS(false)
-                       }
+                               this.compress(0)
 
-                       // increment buffer counter and set byte
-                       this.b[this.c++] = input[i]
+                       } else {
+                               const b_rem = 128 - this.c
+                               const l_rem = length - i
+                               const n = b_rem < l_rem ? b_rem : l_rem
+                               memory.copy(b_ptr + this.c, input_ptr + i, n)
+                               this.c += n
+                               i += n
+                       }
                }
                return this
        }
@@ -115,73 +1085,24 @@ export class Blake2b {
        digest (output: StaticArray<u8>): void {
 
                // add final message block size to total bytes
-               this.t = v128.add<u64>(this.t, i64x2(this.c, u64(v128.extract_lane<u64>(this.t, 0) + u64(this.c) < u64(this.c))))
+               this.t += this.c
 
                // pad final block with zeros
                this.b.fill(0, this.c)
 
                // set final block flag and compress
-               this.COMPRESS(true)
+               this.compress(u64(0 - 1))
 
                // return byte array of 64-byte chain buffer
                memory.copy(changetype<usize>(output), changetype<usize>(this.h), 64)
 
                // clear internal buffers and counters
-               this.clear()
-       }
-
-       // Defined in BLAKE2 section 2.4
-       @inline
-       COMPRESS (isFinal: bool): void {
-
-               // initialize state vector
-               memory.copy(changetype<usize>(this.v), changetype<usize>(this.h), 64)
-               memory.copy(changetype<usize>(this.v) + 64, changetype<usize>(blake2b_iv), 64)
-
-               // lo 64 bits of counter
-               this.v[12] ^= v128.extract_lane<u64>(this.t, 0)
-
-               // hi 64 bits of counter
-               this.v[13] ^= v128.extract_lane<u64>(this.t, 1)
-
-               // flip bits if "last block" flag is set so that v[14] = ~v[14]
-               this.v[14] ^= 0 - u64(isFinal)
-
-               // copy input buffer to message block
-               memory.copy(changetype<usize>(this.m), changetype<usize>(this.b), 128)
-
-               // twelve rounds of mixing
-               for (let r: u8 = 0; r < 12; r++) {
-                       this.ROUND(r)
-               }
-
-               // set new chain value
-               for (let i = 0; i < 8; i++) {
-                       this.h[i] ^= this.v[i] ^ this.v[i + 8]
-               }
-       }
-
-       @inline
-       ROUND (r: u8): void {
-               for (let i = 0; i < 8; i++) {
-                       const a = blake2b_state[i][0]
-                       const b = blake2b_state[i][1]
-                       const c = blake2b_state[i][2]
-                       const d = blake2b_state[i][3]
-                       const s = blake2b_sigma[r]
-                       this.G(a, b, c, d, s[i << 1], s[(i << 1) + 1])
-               }
-       }
-
-       @inline
-       G (a: u8, b: u8, c: u8, d: u8, x: u8, y: u8): void {
-               this.v[a] = this.v[a] + this.v[b] + this.m[x]
-               this.v[d] = rotr<u64>(this.v[d] ^ this.v[a], 32)
-               this.v[c] = this.v[c] + this.v[d]
-               this.v[b] = rotr<u64>(this.v[b] ^ this.v[c], 24)
-               this.v[a] = this.v[a] + this.v[b] + this.m[y]
-               this.v[d] = rotr<u64>(this.v[d] ^ this.v[a], 16)
-               this.v[c] = this.v[c] + this.v[d]
-               this.v[b] = rotr<u64>(this.v[b] ^ this.v[c], 63)
+               
+               this.b.fill(0)
+               this.c = 0
+               this.h.fill(0)
+               this.p.fill(0)
+               this.t = 0
+       
        }
 }
diff --git a/src/assembly/ed25519/crypto_sign.ts b/src/assembly/ed25519/crypto_sign.ts
deleted file mode 100644 (file)
index 7e0eb09..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
-//! SPDX-License-Identifier: GPL-3.0-or-later
-
-import { KEY_BYTELENGTH } from '../constants'
-import { crypto_derive } from '../crypto_derive'
-import { Blake2b } from './blake2b'
-import { ge_scalarmult_base_tobytes } from './ge'
-import { sc_muladd, sc_reduce } from './sc'
-import { clamp } from './utils'
-
-// crypto_hash function
-const blake2b = new Blake2b()
-
-// algorithm variables
-const A = new StaticArray<u8>(32)
-const h = new StaticArray<u8>(64)
-const s = new StaticArray<u8>(32)
-const prefix = new StaticArray<u8>(32)
-const r = new StaticArray<u8>(64)
-const R = new StaticArray<u8>(64)
-const k = new StaticArray<u8>(64)
-const S = new StaticArray<u8>(64)
-/**
- * Sign a message with a private key. The Nano specification uses BLAKE2b as the
- * hash function instead of SHA-512 specified by RFC 8032.
- *
- * In this implementation, both the private key and the public key are required.
- * This ensures the user has a full correct keypair for data integrity. It also
- * offers a small performance improvement in the case of an invalid public key
- * by returning early and avoiding expensive point multiplication; RFC 8032
- * indicates the public key should be recomputed from the private key when
- * signing anyway, so there is no penalty for checking key validity first.
- *
- * https://www.rfc-editor.org/info/rfc8032/#section-5.1.6
- *
- * @param {StaticArray<u8>} RS 64-byte output buffer for detached signature
- * @param {StaticArray<u8>} M variable-length message to be signed
- * @param {i32} mlen bytelength of `m`
- * @param {StaticArray<u8>} prv 32-byte private key from input buffer
- * @param {StaticArray<u8>} pub 32-byte public key from input buffer
- */
-export function crypto_sign (RS: StaticArray<u8>, M: StaticArray<u8>, mlen: i32, prv: StaticArray<u8>, pub: StaticArray<u8>): i32 {
-       // Derive `A` from private key
-       crypto_derive(A, prv)
-       let c = 0
-       for (let i = 0; i < KEY_BYTELENGTH; i++) {
-               c |= A[i] ^ pub[i]
-       }
-       // Return early if `A` does not match public key
-       if (c != 0) return -1
-
-       // Hash private key to `h`
-       blake2b.init().update(prv, KEY_BYTELENGTH).digest(h)
-       prv.fill(0)
-
-       // Split `h` into clamped secret scalar `s` and nonce prefix
-       memory.copy(changetype<usize>(s), changetype<usize>(h), 32)
-       clamp(s)
-       memory.copy(changetype<usize>(prefix), changetype<usize>(h) + 32, 32)
-       h.fill(0)
-
-       // Hash prefix and message `M` to nonce `r`
-       blake2b.init().update(prefix, 32).update(M, mlen).digest(r)
-       prefix.fill(0)
-
-       // Reduce `r` modulo `L`, the group order of the base point `B`
-       sc_reduce(r)
-
-       // Perform fixed-base scalar multiplication `[r]B`, output to point `R`
-       ge_scalarmult_base_tobytes(R, r)
-
-       // Compute challenge hash `blake2b(R || A || M)`, output to `k`
-       blake2b.init().update(R, 32).update(A, 32).update(M, mlen).digest(k)
-       A.fill(0)
-
-       // Reduce `k` modulo `L` for efficiency
-       sc_reduce(k)
-
-       // Compute `S = (k * s + r) mod L`
-       sc_muladd(S, k, s, r)
-       k.fill(0)
-       s.fill(0)
-       r.fill(0)
-
-       // Construct final signature `(R || S)`
-       memory.copy(changetype<usize>(RS), changetype<usize>(R), 32)
-       R.fill(0)
-       memory.copy(changetype<usize>(RS) + 32, changetype<usize>(S), 32)
-       S.fill(0)
-
-       return 0
-}
index 67d0fa93ae2c14c0e3ce59d7f1e7f76f02dae541..5f53c2f1a40c9ade0260b1f6f10a4d663d86693b 100644 (file)
@@ -45,9 +45,9 @@ export function abort (message: usize, fileName: usize, line: u32, col: u32): vo
  */
 //@ts-expect-error
 @inline
-export function raise (code: i32, a: i32 = 0, b: i32 = 0): void {
+export function raise (code: i32, detail: i32 = 0, context: i32 = 0): void {
        errorCode = code
-       errorDetail = a
-       errorContext = b
+       errorDetail = detail
+       errorContext = context
        throw new Error()
 }
index 74ad5b93ba42bb590097d4c9b91a4dfb030145d8..1da0d8aa3421f53251902b5112180d0ecbb93146 100644 (file)
@@ -43,6 +43,23 @@ export function setInputMsgByte (index: i32, v0: i32): void {
        INPUT_MSG[index] = u8(v0)
 }
 
+/** Sets 4 bytes in the static message input buffer. */
+export function setInputMsg32 (index: i32, v0: u32, v1: u32, v2: u32, v3: u32, v4: u32, v5: u32, v6: u32, v7: u32): void {
+       if (index < 0 || MAX_MESSAGE_BYTELENGTH <= index) {
+               raise(ERROR_INDEX_OUT_OF_RANGE, BUFFER_INPUT_MSG, index)
+       }
+       const v = [v0, v1, v2, v3, v4, v5, v6, v7]
+       for (let i = 0; i < 8; i++) {
+               if (v[i] < 0 || 0xffffffff < v[i]) {
+                       raise(ERROR_BYTE_OUT_OF_RANGE, BUFFER_INPUT_MSG, v[i])
+               }
+               INPUT_MSG[index + (i << 2)] = u8((v[i] >>> 24) & 255)
+               INPUT_MSG[index + (i << 2) + 1] = u8((v[i] >>> 16) & 255)
+               INPUT_MSG[index + (i << 2) + 2] = u8((v[i] >>> 8) & 255)
+               INPUT_MSG[index + (i << 2) + 3] = u8(v[i] & 255)
+       }
+}
+
 /** Sets a byte in the static private key input buffer (32 bytes). */
 export function setInputPrvByte (index: i32, value: i32): void {
        if (index < 0 || KEY_BYTELENGTH <= index) {
@@ -179,7 +196,7 @@ export function sign (mlen: i32): void {
        // Clear signature output buffer if signing failed
        if (result != 0) {
                OUTPUT_SIGN.fill(0)
-               raise(ERROR_INVALID_PUBLIC_KEY)
+               raise(ERROR_INVALID_PUBLIC_KEY, result)
        }
 }
 
index a8ce1585e1e07a9b85fbee91c8b7792c904cf271..a74d7d6151cb4e6b1cb1c2f2812ab736e267181e 100644 (file)
@@ -73,7 +73,7 @@ function selftest (code: number, v: number, detail: number, length: number): str
 function describe (code: number, line: number, detail: number, context: number): string {
        switch (code) {
                case errorCodes.ERROR_INVALID_PUBLIC_KEY:
-                       return 'Invalid public key'
+                       return `Invalid public key ${line} ${detail} ${context}`
                case errorCodes.ERROR_INVALID_MESSAGE_LENGTH:
                        return `Invalid message length: ${detail} is not in [0, ${context}]`
                case errorCodes.ERROR_INVALID_BLOCK_COUNT:
@@ -92,6 +92,6 @@ function describe (code: number, line: number, detail: number, context: number):
 }
 
 /** The module's only import. Takes four integers and never reads wasm memory. */
-export function abort (code: number, line: number, a: number, b: number): never {
-       throw new Nano25519WasmError(describe(code, line, a, b))
+export function abort (code: number, line: number, detail: number, context: number): never {
+       throw new Nano25519WasmError(describe(code, line, detail, context))
 }
index cccaac6871fe4f3eb012b6d67676aff4aacaf5a5..b87d22656337cb92389399ffdf542c6f816c1679 100644 (file)
@@ -12,8 +12,12 @@ export function verify (sig: unknown, msg: unknown, pub: unknown): boolean {
                const message = normalize('message', 0, MAX_MESSAGE_BYTELENGTH, msg)
                const publicKey = normalize('public key', KEY_BYTELENGTH, KEY_BYTELENGTH, pub)
                const signature = normalize('signature', SIGNATURE_BYTELENGTH, SIGNATURE_BYTELENGTH, sig)
-               for (let i = 0; i < message.byteLength; i++) {
-                       MemoryBuffers.INPUT_MSG(i, message[i])
+               for (let i = 0; i < message.byteLength; i += 32) {
+                       const u32: number[] = []
+                       for (let j = 0; j < 32; j += 4) {
+                               u32[j >> 2] = ((message[i + j] ?? 0) << 24) | ((message[i + j + 1] ?? 0) << 16) | ((message[i + j + 2] ?? 0) << 8) | (message[i + j + 3] ?? 0)
+                       }
+                       MemoryBuffers.INPUT_MSG_32(i, u32[0], u32[1], u32[2], u32[3], u32[4], u32[5], u32[6], u32[7])
                }
                for (let i = 0; i < KEY_BYTELENGTH; i++) {
                        MemoryBuffers.INPUT_PUB(i, publicKey[i])
index 363ff98ad0c6d0b020255bcb709af77a85e7b564..64fb24dd2cabaac487240e6f0f3e7e57628f6b51 100644 (file)
@@ -13,6 +13,7 @@ type Exports = WebAssembly.Instance['exports'] & {
        verify: (mlen: number) => void
        verify_blocks: (count: number) => void
        setInputMsgByte: (index: number, value: number) => void
+       setInputMsg32: (index: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number) => void
        setInputPrvByte: (index: number, value: number) => void
        setInputPubByte: (index: number, value: number) => void
        setInputSigByte: (index: number, value: number) => void
@@ -99,6 +100,10 @@ export class MemoryBuffers {
                this.#check()
                return exports.setInputMsgByte
        }
+       static get INPUT_MSG_32 () {
+               this.#check()
+               return exports.setInputMsg32
+       }
        static get INPUT_PRV () {
                this.#check()
                return exports.setInputPrvByte
index 698d2378dbed8171f506c2e6388527b8e718d3e2..cfe32f0af3aba0e6d74b95de3b05dd5e3ab464e1 100644 (file)
@@ -1,7 +1,7 @@
 /**
-* This file is automatically generated during the build process.
-* Add or modify test vectors from the files in the test/vectors directory.
-*/
+ * This file is automatically generated during the build process.
+ * Add or modify test vectors from the files in the test/vectors directory.
+ */
 
 // test/vectors/identity.ts
 var IDENTITY = {