]> git.codecow.com Git - nano25519.git/commitdiff
Reduce load calls and eliminate loop in blake gen. Formatting.
authorChris Duncan <chris@codecow.com>
Thu, 1 Oct 2026 20:57:51 +0000 (13:57 -0700)
committerChris Duncan <chris@codecow.com>
Thu, 1 Oct 2026 20:57:51 +0000 (13:57 -0700)
scripts/blake2b-gen.mjs
src/assembly/ed25519/blake2b.ts

index 815c55515adc0e879f8748173f824e95e0691dc4..1cf31c831e789df5eaf175e21cc2858588d95830 100644 (file)
@@ -62,68 +62,59 @@ 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: u8 = 0
-               h: StaticArray<u64> = new StaticArray<u64>(${H_LENGTH})
-               p: StaticArray<u8> = new StaticArray<u8>(64)
-               t: u64 = 0
-
-               ${COMPRESS()}
-       `
+       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: u8 = 0
+       h: StaticArray<u64> = new StaticArray<u64>(${H_LENGTH})
+       p: StaticArray<u8> = new StaticArray<u8>(64)
+       t: u64 = 0
+`
        return output
 })()
 
 function CLEAR () {
-       let output = `
-               this.b.fill(0)
+       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
-       `
+       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
-       `
+               const p_ptr = changetype<usize>(this.p)
+`
        for (let i = 0; i < H_LENGTH; i++) {
                output += `
-                       this.h[${i}] = ${blake2b_iv[i]}
-               `
+               this.h[${i}] = ${blake2b_iv[i]} ^ load<u64>(p_ptr, ${i << 3})`
        }
 
        output += `
-               for (let i = 0; i < ${H_LENGTH}; i++) {
-                       this.h[i] ^= load<u64>(changetype<usize>(this.p) + (i << 3))
-               }
+
                return this
-       }
-       `
+       }`
 
        return output
 })()
@@ -149,7 +140,7 @@ function G (a, b, c, d, x, 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)
-       `
+`
 }
 
 /**
@@ -160,8 +151,7 @@ function G (a, b, c, d, x, y) {
  */
 function ROUND (r) {
        let output = `
-               // ROUND ${r}
-       `
+               // ROUND ${r}`
        for (let i = 0; i < 8; i++) {
                const a = blake2b_state[i][0]
                const b = blake2b_state[i][1]
@@ -178,25 +168,25 @@ function ROUND (r) {
  * 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
+ * @type {string} API-specific code executing 12 rounds of G mixing
  */
-function COMPRESS () {
+const COMPRESS = (() => {
        let output = `
-               // COMPRESS
-               // Defined in BLAKE2 section 2.4
-               compress (src: usize, isFinal: u64): void {
+       // COMPRESS
+       // Defined in BLAKE2 section 2.4
+       compress (src: usize, 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
-       `
+               // - 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]}
-               `
+               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
 
@@ -206,43 +196,41 @@ function COMPRESS () {
                // flip bits if "last block" flag is set so that v14 = ~v14
                v${14} ^= isFinal
 
-               // copy input buffer to message block
-       `
+               // copy input buffer to message block`
 
        for (let i = 0; i < 16; i++) {
                output += `
-                       let m${i}: u64 = load<u64>(src + ${i << 3})
-               `
+               let m${i}: u64 = load<u64>(src + ${i << 3})`
        }
 
        output += `
+
                // twelve rounds of mixing
-       `
+`
        for (let r = 0; r < 12; r++) {
                output += ROUND(r)
        }
 
        output += `
-               // set new chain value
-       `
+               // set new chain value`
        for (let i = 0; i < H_LENGTH; i++) {
                output += `
-                       this.h[${i}] ^= v${i} ^ v${i + H_LENGTH}
-               `
+               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}
+${DECLARATIONS}
+${INIT}
+${COMPRESS}
        // 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)
@@ -294,7 +282,8 @@ export class Blake2b {
                memory.copy(changetype<usize>(output), changetype<usize>(this.h), 64)
 
                // clear internal buffers and counters
-               ${CLEAR()}
+${CLEAR()}
+               return
        }
 }
 `
index 2edcdeef80009f284f968163a1539753524c859f..3efa08e007dd1a2396bfcea100138bdd89f3442e 100644 (file)
@@ -2,7 +2,6 @@
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
 export class Blake2b {
-
        /**
         * Buffers and counters
         * - b: input buffer, filled and refilled by input data in 128 byte increments
@@ -18,6 +17,34 @@ export class Blake2b {
        p: StaticArray<u8> = new StaticArray<u8>(64)
        t: u64 = 0
 
+       init (): Blake2b {
+               // reset buffers and counters
+               this.b.fill(0)
+               this.c = 0
+               this.h.fill(0)
+               this.p.fill(0)
+               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
+               const p_ptr = changetype<usize>(this.p)
+
+               this.h[0] = 0x6a09e667f3bcc908 ^ load<u64>(p_ptr, 0)
+               this.h[1] = 0xbb67ae8584caa73b ^ load<u64>(p_ptr, 8)
+               this.h[2] = 0x3c6ef372fe94f82b ^ load<u64>(p_ptr, 16)
+               this.h[3] = 0xa54ff53a5f1d36f1 ^ load<u64>(p_ptr, 24)
+               this.h[4] = 0x510e527fade682d1 ^ load<u64>(p_ptr, 32)
+               this.h[5] = 0x9b05688c2b3e6c1f ^ load<u64>(p_ptr, 40)
+               this.h[6] = 0x1f83d9abfb41bd6b ^ load<u64>(p_ptr, 48)
+               this.h[7] = 0x5be0cd19137e2179 ^ load<u64>(p_ptr, 56)
+
+               return this
+       }
 
        // COMPRESS
        // Defined in BLAKE2 section 2.4
@@ -25,28 +52,20 @@ export class Blake2b {
                // 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
 
@@ -60,43 +79,26 @@ export class Blake2b {
                v14 ^= isFinal
 
                // copy input buffer to message block
-
                let m0: u64 = load<u64>(src + 0)
-
                let m1: u64 = load<u64>(src + 8)
-
                let m2: u64 = load<u64>(src + 16)
-
                let m3: u64 = load<u64>(src + 24)
-
                let m4: u64 = load<u64>(src + 32)
-
                let m5: u64 = load<u64>(src + 40)
-
                let m6: u64 = load<u64>(src + 48)
-
                let m7: u64 = load<u64>(src + 56)
-
                let m8: u64 = load<u64>(src + 64)
-
                let m9: u64 = load<u64>(src + 72)
-
                let m10: u64 = load<u64>(src + 80)
-
                let m11: u64 = load<u64>(src + 88)
-
                let m12: u64 = load<u64>(src + 96)
-
                let m13: u64 = load<u64>(src + 104)
-
                let m14: u64 = load<u64>(src + 112)
-
                let m15: u64 = load<u64>(src + 120)
 
                // twelve rounds of mixing
 
                // ROUND 0
-
                v0 = v0 + v4 + m0
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -170,7 +172,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 1
-
                v0 = v0 + v4 + m14
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -244,7 +245,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 2
-
                v0 = v0 + v4 + m11
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -318,7 +318,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 3
-
                v0 = v0 + v4 + m7
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -392,7 +391,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 4
-
                v0 = v0 + v4 + m9
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -466,7 +464,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 5
-
                v0 = v0 + v4 + m2
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -540,7 +537,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 6
-
                v0 = v0 + v4 + m12
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -614,7 +610,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 7
-
                v0 = v0 + v4 + m13
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -688,7 +683,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 8
-
                v0 = v0 + v4 + m6
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -762,7 +756,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 9
-
                v0 = v0 + v4 + m10
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -836,7 +829,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 10
-
                v0 = v0 + v4 + m0
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -910,7 +902,6 @@ export class Blake2b {
                v4 = rotr<u64>(v4 ^ v9, 63)
 
                // ROUND 11
-
                v0 = v0 + v4 + m14
                v12 = rotr<u64>(v12 ^ v0, 32)
                v8 = v8 + v12
@@ -984,65 +975,14 @@ export class Blake2b {
                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.p.fill(0)
-               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
-
-               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
@@ -1096,12 +1036,12 @@ export class Blake2b {
                memory.copy(changetype<usize>(output), changetype<usize>(this.h), 64)
 
                // clear internal buffers and counters
-
                this.b.fill(0)
                this.c = 0
                this.h.fill(0)
                this.p.fill(0)
                this.t = 0
 
+               return
        }
 }