Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: fuzz testing for circuits #1506

Merged
merged 1 commit into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion circuits/circom/utils/calculateTotal.circom
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ template CalculateTotal(n) {
signal sums[n];
sums[0] <== nums[0];

for (var i=1; i < n; i++) {
for (var i = 1; i < n; i++) {
sums[i] <== sums[i - 1] + nums[i];
}

Expand Down
8 changes: 8 additions & 0 deletions circuits/circom/utils/privToPubKey.circom
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pragma circom 2.0.0;

// circomlib imports
include "./bitify.circom";
include "./comparators.circom";
include "./escalarmulfix.circom";

/**
Expand All @@ -15,9 +16,16 @@ template PrivToPubKey() {
16950150798460657717958625567821834550301663161624707787222815936182638968203
];

// Prime subgroup order 'l'.
var l = 2736030358979909402780800718157159386076813972158567259200215660948447373041;

signal input privKey;
signal output pubKey[2];

// Check if private key is in the prime subgroup order 'l'
0xmad marked this conversation as resolved.
Show resolved Hide resolved
var isLessThan = LessThan(251)([privKey, l]);
isLessThan === 1;

// Convert the private key to bits.
var computedPrivBits[253] = Num2Bits(253)(privKey);

Expand Down
30 changes: 17 additions & 13 deletions circuits/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,21 @@
"circom:build": "NODE_OPTIONS=--max-old-space-size=4096 circomkit compile",
"circom:setup": "NODE_OPTIONS=--max-old-space-size=4096 circomkit setup",
"types": "tsc -p tsconfig.json --noEmit",
"test": "ts-mocha --exit ts/__tests__/*.test.ts",
"test:hasher": "ts-mocha --exit ts/__tests__/Hasher.test.ts",
"test:slAndBallotTransformer": "ts-mocha --exit ts/__tests__/StateLeafAndBallotTransformer.test.ts",
"test:messageToCommand": "ts-mocha --exit ts/__tests__/MessageToCommand.test.ts",
"test:messageValidator": "ts-mocha --exit ts/__tests__/MessageValidator.test.ts",
"test:verifySignature": "ts-mocha --exit ts/__tests__/VerifySignature.test.ts",
"test:splicer": "ts-mocha --exit ts/__tests__/Splicer.test.ts",
"test:privToPubKey": "ts-mocha --exit ts/__tests__/PrivToPubKey.test.ts",
"test:calculateTotal": "ts-mocha --exit ts/__tests__/CalculateTotal.test.ts",
"test:processMessages": "NODE_OPTIONS=--max-old-space-size=4096 ts-mocha --exit ts/__tests__/ProcessMessages.test.ts",
"test:tallyVotes": "NODE_OPTIONS=--max-old-space-size=4096 ts-mocha --exit ts/__tests__/TallyVotes.test.ts",
"test:ceremonyParams": "ts-mocha --exit ts/__tests__/CeremonyParams.test.ts",
"test:incrementalQuinaryTree": "ts-mocha --exit ts/__tests__/IncrementalQuinaryTree.test.ts"
"mocha-test": "NODE_OPTIONS=--max-old-space-size=4096 ts-mocha --exit -g '^(?!.*\\[fuzz\\]).*$'",
"test": "pnpm run mocha-test ts/__tests__/*.test.ts",
"test:fuzz": "NODE_OPTIONS=--max-old-space-size=4096 ts-mocha --exit -g '\\[fuzz\\]' ./ts/__tests__/*.test.ts",
"test:hasher": "pnpm run mocha-test ts/__tests__/Hasher.test.ts",
"test:slAndBallotTransformer": "pnpm run mocha-test ts/__tests__/StateLeafAndBallotTransformer.test.ts",
"test:messageToCommand": "pnpm run mocha-test ts/__tests__/MessageToCommand.test.ts",
"test:messageValidator": "pnpm run mocha-test ts/__tests__/MessageValidator.test.ts",
"test:verifySignature": "pnpm run mocha-test ts/__tests__/VerifySignature.test.ts",
"test:splicer": "pnpm run mocha-test ts/__tests__/Splicer.test.ts",
"test:privToPubKey": "pnpm run mocha-test ts/__tests__/PrivToPubKey.test.ts",
"test:calculateTotal": "pnpm run mocha-test ts/__tests__/CalculateTotal.test.ts",
"test:processMessages": "pnpm run mocha-test ts/__tests__/ProcessMessages.test.ts",
"test:tallyVotes": "pnpm run mocha-test ts/__tests__/TallyVotes.test.ts",
"test:ceremonyParams": "pnpm run mocha-test ts/__tests__/CeremonyParams.test.ts",
"test:incrementalQuinaryTree": "pnpm run mocha-test ts/__tests__/IncrementalQuinaryTree.test.ts"
},
"dependencies": {
"@zk-kit/circuits": "^0.4.0",
Expand All @@ -48,8 +50,10 @@
"@types/chai-as-promised": "^7.1.8",
"@types/mocha": "^10.0.6",
"@types/node": "^20.12.12",
"@zk-kit/baby-jubjub": "^1.0.1",
"chai": "^4.3.10",
"chai-as-promised": "^7.1.2",
"fast-check": "^3.18.0",
"mocha": "^10.4.0",
"ts-mocha": "^10.0.0",
"ts-node": "^10.9.1",
Expand Down
49 changes: 47 additions & 2 deletions circuits/ts/__tests__/CalculateTotal.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { r } from "@zk-kit/baby-jubjub";
import { type WitnessTester } from "circomkit";
import fc from "fast-check";

import { circomkitInstance } from "./utils/utils";
import { circomkitInstance, getSignal } from "./utils/utils";

describe("CalculateTotal circuit", function test() {
this.timeout(900000);

describe("CalculateTotal circuit", () => {
let circuit: WitnessTester<["nums"], ["sum"]>;

before(async () => {
Expand All @@ -15,6 +19,7 @@ describe("CalculateTotal circuit", () => {

it("should correctly sum a list of values", async () => {
const nums: number[] = [];

for (let i = 0; i < 6; i += 1) {
nums.push(Math.floor(Math.random() * 100));
}
Expand All @@ -27,4 +32,44 @@ describe("CalculateTotal circuit", () => {

await circuit.expectPass(circuitInputs, { sum });
});

it("should sum max value and loop back", async () => {
const nums: bigint[] = [r, r, r, r, r, r];

await circuit.expectPass({ nums }, { sum: 0n });
});

it("should sum max negative value and loop back", async () => {
const nums: bigint[] = [-r, -r, -r, -r, -r, -r];

await circuit.expectPass({ nums }, { sum: 0n });
});

it("should sum max positive and negative values without looping", async () => {
const nums: bigint[] = [-r, r, -r, r, 1n, 2n];

await circuit.expectPass({ nums }, { sum: 3n });
});

it("should correctly sum a list of values [fuzz]", async () => {
await fc.assert(
fc.asyncProperty(fc.array(fc.bigInt({ min: 0n, max: r - 1n }), { minLength: 1 }), async (nums: bigint[]) => {
const sum = nums.reduce((a, b) => a + b, 0n);
fc.pre(sum <= r - 1n);

const testCircuit = await circomkitInstance.WitnessTester("calculateTotal", {
file: "./utils/calculateTotal",
template: "CalculateTotal",
params: [nums.length],
});

const witness = await testCircuit.calculateWitness({ nums });
await testCircuit.expectConstraintPass(witness);
const total = await getSignal(testCircuit, witness, "sum");

return total === sum;
}),
{ numRuns: 10_000 },
);
});
});
Loading
Loading