From 5ebc99a6b87d93cdeb1353e8c007f4b25a33df63 Mon Sep 17 00:00:00 2001 From: Gregor Date: Fri, 11 Oct 2024 13:29:44 +0200 Subject: [PATCH] split up impl and test --- src/attestations/dynamic-sha256.test.ts | 43 ++++++++++++++++++ src/attestations/dynamic-sha256.ts | 60 +++++++------------------ 2 files changed, 60 insertions(+), 43 deletions(-) create mode 100644 src/attestations/dynamic-sha256.test.ts diff --git a/src/attestations/dynamic-sha256.test.ts b/src/attestations/dynamic-sha256.test.ts new file mode 100644 index 0000000..d7796ea --- /dev/null +++ b/src/attestations/dynamic-sha256.test.ts @@ -0,0 +1,43 @@ +import { Bytes, Gadgets, UInt32, UInt8 } from 'o1js'; +import { DynamicArray } from './dynamic-array.ts'; +import { StaticArray } from './static-array.ts'; +import * as nodeAssert from 'node:assert'; +import { DynamicSHA256 } from './dynamic-sha256.ts'; + +const { SHA256 } = Gadgets; + +class DynamicBytes extends DynamicArray(UInt8, { maxLength: 500 }) { + static fromString(s: string) { + return DynamicBytes.from( + [...new TextEncoder().encode(s)].map((t) => UInt8.from(t)) + ); + } +} + +let bytes = DynamicBytes.fromString(longString()); +let staticBytes = Bytes.fromString(longString()); + +nodeAssert.deepStrictEqual( + DynamicSHA256.padding(bytes).toValue().map(blockToHexBytes), + SHA256.padding(staticBytes).map(blockToHexBytes) +); +nodeAssert.deepStrictEqual( + DynamicSHA256.hash(bytes).toBytes(), + SHA256.hash(staticBytes).toBytes() +); + +function toHexBytes(uint32: bigint | UInt32) { + return UInt32.from(uint32).toBigint().toString(16).padStart(8, '0'); +} +function blockToHexBytes(block: (bigint | UInt32)[] | StaticArray) { + if (Array.isArray(block)) return block.map((uint32) => toHexBytes(uint32)); + return blockToHexBytes((block as StaticArray).array); +} + +function longString(): string { + return ` +Symbol.iterator + +The Symbol.iterator static data property represents the well-known symbol Symbol.iterator. The iterable protocol looks up this symbol for the method that returns the iterator for an object. In order for an object to be iterable, it must have an [Symbol.iterator] key. +`; +} diff --git a/src/attestations/dynamic-sha256.ts b/src/attestations/dynamic-sha256.ts index 73d7c99..6579293 100644 --- a/src/attestations/dynamic-sha256.ts +++ b/src/attestations/dynamic-sha256.ts @@ -2,17 +2,16 @@ import { Bytes, Field, Gadgets, Packed, Provable, UInt32, UInt8 } from 'o1js'; import { DynamicArray } from './dynamic-array.ts'; import { StaticArray } from './static-array.ts'; import { assert, chunk, pad } from '../util.ts'; -import * as nodeAssert from 'node:assert'; + +export { DynamicSHA256 }; const { SHA256 } = Gadgets; -class DynamicBytes extends DynamicArray(UInt8, { maxLength: 500 }) { - static fromString(s: string) { - return DynamicBytes.from( - [...new TextEncoder().encode(s)].map((t) => UInt8.from(t)) - ); - } -} +const DynamicSHA256 = { + hash, + padding, +}; + // hierarchy of packed types to do make array ops more efficient class UInt8x64 extends StaticArray(UInt8, 64) {} class Block extends StaticArray(UInt32, 16) {} @@ -22,29 +21,20 @@ class UInt128x4 extends StaticArray(UInt128, 4) {} class State extends StaticArray(UInt32, 8) {} -let bytes = DynamicBytes.fromString(longString()); -let blocks = padding(bytes); -let state = blocks.reduce(State, State.from(SHA256.initialState), hashBlock); - -const StateBytes = Bytes(32); -let result = StateBytes.from( - state.array.flatMap((x) => uint32ToBytesBE(x).array) -); - -let staticBytes = Bytes.fromString(longString()); -nodeAssert.deepStrictEqual( - blocks.toValue().map(blockToHexBytes), - SHA256.padding(staticBytes).map(blockToHexBytes) -); -nodeAssert.deepStrictEqual( - result.toBytes(), - SHA256.hash(staticBytes).toBytes() -); +const Bytes32 = Bytes(32); + +function hash(bytes: DynamicArray): Bytes { + let blocks = padding(bytes); + let state = blocks.reduce(State, State.from(SHA256.initialState), hashBlock); + return Bytes32.from(state.array.flatMap((x) => uint32ToBytesBE(x).array)); +} /** * Apply padding to dynamic-length input bytes and convert them to 64-byte blocks */ -function padding(message: DynamicArray) { +function padding( + message: DynamicArray +): DynamicArray> { /* padded message looks like this: M ... M 0x1 0x0 ... 0x0 L L L L L L L L @@ -164,19 +154,3 @@ function uint32ToBytesBE(word: UInt32) { function encodeLength(lengthInBytes: Field): UInt32 { return UInt32.Unsafe.fromField(lengthInBytes.mul(8)); } - -function toHexBytes(uint32: bigint | UInt32) { - return UInt32.from(uint32).toBigint().toString(16).padStart(8, '0'); -} -function blockToHexBytes(block: (bigint | UInt32)[] | StaticArray) { - if (Array.isArray(block)) return block.map((uint32) => toHexBytes(uint32)); - return blockToHexBytes((block as StaticArray).array); -} - -function longString(): string { - return ` -Symbol.iterator - -The Symbol.iterator static data property represents the well-known symbol Symbol.iterator. The iterable protocol looks up this symbol for the method that returns the iterator for an object. In order for an object to be iterable, it must have an [Symbol.iterator] key. -`; -}