Skip to content

Commit

Permalink
Merge pull request #234 from zkemail/test/poseidon-modular
Browse files Browse the repository at this point in the history
Feat: Added Poseidon Modular Tests
  • Loading branch information
Divide-By-0 authored Nov 22, 2024
2 parents 9ed3769 + ff0094a commit d0e6f7f
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
37 changes: 37 additions & 0 deletions packages/circuits/tests/poseidon-modular.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma circom 2.1.6;

include "../../utils/hash.circom";

component main = PoseidonModular(37);
44 changes: 44 additions & 0 deletions packages/helpers/src/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit d0e6f7f

Please sign in to comment.