mirror of
https://github.com/zkemail/zk-email-verify.git
synced 2026-01-08 21:18:09 -05:00
Merge pull request #234 from zkemail/test/poseidon-modular
Feat: Added Poseidon Modular Tests
This commit is contained in:
37
packages/circuits/tests/poseidon-modular.test.ts
Normal file
37
packages/circuits/tests/poseidon-modular.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import path from "path";
|
||||
import { wasm as wasm_tester } from "circom_tester";
|
||||
import { poseidonModular } from "@zk-email/helpers/src/hash";
|
||||
|
||||
describe("PoseidonModular", () => {
|
||||
jest.setTimeout(30 * 60 * 1000); // 30 minutes
|
||||
|
||||
let circuit: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
circuit = await wasm_tester(
|
||||
path.join(
|
||||
__dirname,
|
||||
"./test-circuits/poseidon-modular-test.circom"
|
||||
),
|
||||
{
|
||||
recompile: true,
|
||||
include: path.join(__dirname, "../../../node_modules"),
|
||||
output: path.join(__dirname, "./compiled-test-circuits"),
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it("should hash correctly", async function () {
|
||||
const inputs = Array.from({ length: 37 }, () =>
|
||||
BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))
|
||||
);
|
||||
const hash = await poseidonModular(inputs);
|
||||
|
||||
const witness = await circuit.calculateWitness({
|
||||
in: inputs,
|
||||
});
|
||||
await circuit.checkConstraints(witness);
|
||||
|
||||
expect(witness[1]).toEqual(hash);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
pragma circom 2.1.6;
|
||||
|
||||
include "../../utils/hash.circom";
|
||||
|
||||
component main = PoseidonModular(37);
|
||||
@@ -8,3 +8,47 @@ export async function poseidonLarge(input: bigint, numChunks: number, bitsPerChu
|
||||
|
||||
return poseidon.F.toObject(hash) as Promise<bigint>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates Poseidon hash of an arbitrary number of inputs
|
||||
* Mimics the behavior of PoseidonModular circuit
|
||||
* @param inputs Array of bigints to be hashed
|
||||
* @returns Promise<bigint> The final hash
|
||||
*/
|
||||
export async function poseidonModular(inputs: bigint[]): Promise<bigint> {
|
||||
const poseidon = await buildPoseidon();
|
||||
const CHUNK_SIZE = 16;
|
||||
|
||||
// Calculate number of chunks
|
||||
const numElements = inputs.length;
|
||||
let chunks = Math.floor(numElements / CHUNK_SIZE);
|
||||
const lastChunkSize = numElements % CHUNK_SIZE;
|
||||
if (lastChunkSize !== 0) {
|
||||
chunks += 1;
|
||||
}
|
||||
|
||||
let out: bigint | null = null;
|
||||
|
||||
// Process each chunk
|
||||
for (let i = 0; i < chunks; i++) {
|
||||
const start = i * CHUNK_SIZE;
|
||||
let end = start + CHUNK_SIZE;
|
||||
if (end > numElements) {
|
||||
end = numElements;
|
||||
}
|
||||
const chunk = inputs.slice(start, end);
|
||||
const chunkHash = poseidon.F.toObject(poseidon(chunk));
|
||||
|
||||
if (i === 0) {
|
||||
out = chunkHash;
|
||||
} else {
|
||||
out = poseidon.F.toObject(poseidon([out as bigint, chunkHash]));
|
||||
}
|
||||
}
|
||||
|
||||
if (out === null) {
|
||||
throw new Error("No inputs provided");
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user