diff --git a/packages/circuits/tests/splitBytesToWords.test.ts b/packages/circuits/tests/splitBytesToWords.test.ts new file mode 100644 index 000000000..93019abd7 --- /dev/null +++ b/packages/circuits/tests/splitBytesToWords.test.ts @@ -0,0 +1,33 @@ +import { wasm as wasm_tester } from "circom_tester"; +import path from "path"; +import { bigIntToChunkedBytes, Uint8ArrayToCharArray } from "@zk-email/helpers/src/binary-format"; + + +describe("SplitBytesToWords Helper unit test", () => { + jest.setTimeout(0.1 * 60 * 1000); + let circuit: any; + + beforeAll(async () => { + circuit = await wasm_tester( + path.join(__dirname, "./test-circuits/splitBytesToWords-test.circom"), + { + recompile: true, + include: path.join(__dirname, "../../../node_modules"), + // output: path.join(__dirname, "./compiled-test-circuits"), + } + ); + + }); + + it("should split correctly according to bigIntToChunkedBytes function", async function () { + const bytes = new Uint8Array(256).map(() => Math.floor(Math.random() * 256)); + const bytesBigInt = bytes.reduce((acc, val) => (acc << 8n) | BigInt(val), 0n); + const ts_split_to_words = bigIntToChunkedBytes(bytesBigInt, 121, 17); + const ts_split_to_words_bigint = ts_split_to_words.map((word) => BigInt(word)); + const witness = await circuit.calculateWitness({ + in: Uint8ArrayToCharArray(bytes) + }); + await circuit.assertOut(witness, { out: ts_split_to_words_bigint }); + }); + +}); diff --git a/packages/circuits/tests/test-circuits/splitBytesToWords-test.circom b/packages/circuits/tests/test-circuits/splitBytesToWords-test.circom new file mode 100644 index 000000000..c0c65a5d9 --- /dev/null +++ b/packages/circuits/tests/test-circuits/splitBytesToWords-test.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.6; + +include "../../utils/bytes.circom"; + +component main = SplitBytesToWords(256,121,17); + diff --git a/packages/circuits/utils/bytes.circom b/packages/circuits/utils/bytes.circom index 2091d076e..d4d96027b 100644 --- a/packages/circuits/utils/bytes.circom +++ b/packages/circuits/utils/bytes.circom @@ -111,3 +111,39 @@ template DigitBytesToInt(n) { out <== sums[n]; } + + +// NOTE: this circuit is unaudited and should not be used in production +/// @title SplitBytesToWords +/// @notice split an array of bytes into an array of words +/// @notice useful for casting a message or modulus before RSA verification +/// @param l: number of bytes in the input array +/// @param n: number of bits in a word +/// @param k: number of words +/// @input in: array of bytes +/// @output out: array of words +template SplitBytesToWords (l,n,k) { + signal input in[l]; + signal output out[k]; + + component num2bits[l]; + for (var i = 0 ; i < l ; i++){ + num2bits[i] = Num2Bits(8); + num2bits[i].in <== in[i]; + } + component bits2num[k]; + for (var i = 0 ; i < k ; i++){ + bits2num[i] = Bits2Num(n); + for(var j = 0 ; j < n ; j++){ + if(i*n + j >= 8 * l){ + bits2num[i].in[j] <== 0; + } + else{ + bits2num[i].in[j] <== num2bits[l - (( i * n + j) \ 8) - 1].out[ ((i * n + j) % 8)]; + } + } + } + for( var i = 0 ; i< k ; i++){ + out[i] <== bits2num[i].out; + } +}