diff --git a/src/attestations/dynamic-array.ts b/src/attestations/dynamic-array.ts index eeb2dde..22b2d11 100644 --- a/src/attestations/dynamic-array.ts +++ b/src/attestations/dynamic-array.ts @@ -300,7 +300,7 @@ class DynamicArrayBase { /** * Split into a (dynamic) number of fixed-size chunks. - * Does not assumes that the max length or actual length are multiples of the chunk size. + * Does not assume that the max length or actual length are multiples of the chunk size. * * Warning: The last chunk will contain dummy values if the actual length is not a multiple of the chunk size. */ diff --git a/src/attestations/dynamic-sha256.ts b/src/attestations/dynamic-sha256.ts index a62ebb2..3e7d168 100644 --- a/src/attestations/dynamic-sha256.ts +++ b/src/attestations/dynamic-sha256.ts @@ -51,25 +51,32 @@ function createPaddedBlocks( // pack each block of 64 bytes into 32 uint16s let blocksOfUInt16 = blocksOfUInt8.map(UInt16x8, (block) => - UInt16x8.from(chunk(block.array, 2).map(UInt8x2.from).map(UInt16.pack)) + UInt16x8.from(block.chunk(2).map(UInt16, UInt16.pack)) ); // pack each block of 32 uint16s into 4 uint128s let blocksOfUInt128 = blocksOfUInt16.map(UInt128x4, (block) => - UInt128x4.from(chunk(block.array, 8).map(UInt16x8.from).map(UInt128.pack)) + UInt128x4.from(block.chunk(8).map(UInt128, UInt128.pack)) ); - throw Error('todo'); + // splice the length in the same way + // length = l0 + 2*(l10 + 8*l11) + 64*blocks.length + let { rest: l0, quotient: l1 } = + UInt32.Unsafe.fromField(innerLength).divMod(2); + let { rest: l10, quotient: l11 } = l1.divMod(8); - // // apply padding: - // // 1. get the last block - // let lastIndex = blocksOfBytes.length.sub(1); - // let last = blocksOfBytes.getOrUnconstrained(lastIndex); + // get the last block, and correct sub-blocks within that + let lastIndex = blocksOfUInt128.length.sub(1); + let lastBlock = blocksOfUInt128.getOrUnconstrained(lastIndex); + let lastUint128 = lastBlock.getOrUnconstrained(l11.value).unpack(); + let lastUint16 = lastUint128.getOrUnconstrained(l10.value).unpack(); - // // 2. apply padding and update block again (no-op if there are zero blocks) - // blocksOfBytes.setOrDoNothing(lastIndex, padLastBlock(last)); + // set 0x1 byte at `length` + lastUint16.setOrDoNothing(l0.value, UInt8.from(0x1)); + lastUint128.setOrDoNothing(l11.value, UInt16.pack(lastUint16)); + lastBlock.setOrDoNothing(l10.value, UInt128.pack(lastUint128)); - // return blocksOfBytes; + throw Error('todo'); } function padLastBlock(lastBlock: UInt32[]): UInt32[] { diff --git a/src/attestations/static-array.ts b/src/attestations/static-array.ts index 54dda35..968bf2c 100644 --- a/src/attestations/static-array.ts +++ b/src/attestations/static-array.ts @@ -10,7 +10,7 @@ import { Gadgets, ProvableHashable, } from 'o1js'; -import { assert, zip } from '../util.ts'; +import { assert, chunk, zip } from '../util.ts'; import { ProvableType } from '../o1js-missing.ts'; import { assertLessThan16, lessThan16 } from './gadgets.ts'; @@ -50,7 +50,7 @@ function StaticArray< * * Note: Both the actual length and the values beyond the original ones will be constant. */ - from(v: (T | V)[]): StaticArrayBase; + from(v: (T | V)[] | StaticArrayBase): StaticArrayBase; } { let innerType: ProvableHashable = ProvableType.get(type) as any; @@ -219,6 +219,18 @@ class StaticArrayBase { return state; } + /** + * Split into a static number of fixed-size chunks. + * Requires that the length is a multiple of the chunk size. + */ + chunk(chunkSize: number) { + let chunked = chunk(this.array, chunkSize); + let newLength = this.length / chunkSize; + const Chunk = StaticArray(this.innerType, chunkSize); + const Chunked = StaticArray(Chunk, newLength); + return new Chunked(chunked.map(Chunk.from)); + } + // cached variables to not duplicate constraints if we do something like array.get(i), array.set(i, ..) on the same index _indexMasks: Map = new Map(); _indicesInRange: Set = new Set();