--- /dev/null
+//! 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)
//! 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
}
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
+
}
}