chore: update tests with new cases

This commit is contained in:
moebius
2025-02-19 12:02:49 +01:00
parent 684d08bfd0
commit bfaab94ecf
4 changed files with 144 additions and 34 deletions

View File

@@ -4,10 +4,7 @@ import { poseidon } from "../../../node_modules/maci-crypto/build/ts/hashing.js"
import { parseEther, hexToBigInt, getAddress } from "viem";
describe("CommitmentHasher Circuit", () => {
let circuit: WitnessTester<
["value", "label", "nullifier", "secret"],
["commitment", "precommitmentHash", "nullifierHash"]
>;
let circuit: WitnessTester<["value", "label", "nullifier", "secret"], ["commitment", "nullifierHash"]>;
const depositor = getAddress("0x9F2db792a6F2dAdf25D894cEd791080950bDE56f");
const NONCE = BigInt(1);
@@ -29,7 +26,7 @@ describe("CommitmentHasher Circuit", () => {
secret: randomBigInt(),
};
const [commitmentHash, precommitmentHash, nullifierHash] = hashCommitment(input);
const [commitmentHash, nullifierHash] = hashCommitment(input);
await circuit.expectPass(
{
@@ -38,7 +35,7 @@ describe("CommitmentHasher Circuit", () => {
nullifier: input.nullifier,
secret: input.secret,
},
{ commitment: commitmentHash, precommitmentHash, nullifierHash },
{ commitment: commitmentHash, nullifierHash },
);
});
@@ -59,7 +56,7 @@ describe("CommitmentHasher Circuit", () => {
secret: randomBigInt(),
};
const [commitmentHash, precommitmentHash, nullifierHash] = hashCommitment(childInput);
const [commitmentHash, nullifierHash] = hashCommitment(childInput);
await circuit.expectPass(
{
@@ -68,7 +65,7 @@ describe("CommitmentHasher Circuit", () => {
nullifier: childInput.nullifier,
secret: childInput.secret,
},
{ commitment: commitmentHash, precommitmentHash, nullifierHash },
{ commitment: commitmentHash, nullifierHash },
);
});
@@ -81,7 +78,7 @@ describe("CommitmentHasher Circuit", () => {
secret: BigInt(0),
};
const [commitmentHash, precommitmentHash, nullifierHash] = hashCommitment(input);
const [commitmentHash, nullifierHash] = hashCommitment(input);
await circuit.expectPass(
{
@@ -90,7 +87,7 @@ describe("CommitmentHasher Circuit", () => {
nullifier: input.nullifier,
secret: input.secret,
},
{ commitment: commitmentHash, precommitmentHash, nullifierHash },
{ commitment: commitmentHash, nullifierHash },
);
});
@@ -105,7 +102,7 @@ describe("CommitmentHasher Circuit", () => {
secret: P - BigInt(1),
};
const [commitmentHash, precommitmentHash, nullifierHash] = hashCommitment(input);
const [commitmentHash, nullifierHash] = hashCommitment(input);
await circuit.expectPass(
{
@@ -114,7 +111,7 @@ describe("CommitmentHasher Circuit", () => {
nullifier: input.nullifier,
secret: input.secret,
},
{ commitment: commitmentHash, precommitmentHash, nullifierHash },
{ commitment: commitmentHash, nullifierHash },
);
});
@@ -128,8 +125,8 @@ describe("CommitmentHasher Circuit", () => {
const modified = { ...base, value: parseEther("2"), label: randomBigInt(), secret: randomBigInt() };
const [_, __, nullifierHash1] = hashCommitment(base);
const [___, ____, nullifierHash2] = hashCommitment(modified);
const [_, nullifierHash1] = hashCommitment(base);
const [___, nullifierHash2] = hashCommitment(modified);
if (nullifierHash1 != nullifierHash2) {
throw new Error("Nullifier hashes don't match");
@@ -166,18 +163,14 @@ describe("CommitmentHasher Circuit", () => {
secret: randomBigInt(),
};
const [hash1, pre1, null1] = hashCommitment(input);
const [hash2, pre2, null2] = hashCommitment(input);
const [hash3, pre3, null3] = hashCommitment(input);
const [hash1, null1] = hashCommitment(input);
const [hash2, null2] = hashCommitment(input);
const [hash3, null3] = hashCommitment(input);
if (hash1 != hash2 || hash2 != hash3) {
throw new Error("Commitment hashes don't match");
}
if (pre1 != pre2 || pre2 != pre3) {
throw new Error("Precommitment hashes don't match");
}
if (null1 != null2 || null2 != null3) {
throw new Error("Nullifier hashes don't match");
}

View File

@@ -14,11 +14,11 @@ export const circomkit = new Circomkit({
include: ["../../node_modules/circomlib/circuits", "../../node_modules/maci-circuits/circom"],
});
export function hashCommitment(input: Commitment): [bigint, bigint, bigint] {
export function hashCommitment(input: Commitment): [bigint, bigint] {
const precommitment = poseidon([BigInt(input.nullifier), BigInt(input.secret)]);
const nullifierHash = poseidon([BigInt(input.nullifier)]);
const commitmentHash = poseidon([BigInt(input.value), BigInt(input.label), precommitment]);
return [commitmentHash, precommitment, nullifierHash];
return [commitmentHash, nullifierHash];
}
export function randomBigInt(): bigint {

View File

@@ -49,8 +49,33 @@ describe("LeanIMTInclusionProof Circuit", () => {
siblings: padSiblings(stateProof.siblings, maxDepth),
actualDepth: tree.depth,
},
{ out: tree.root }
{ out: tree.root },
);
}
});
it("Should fail when passing a tree depth greater than the max depth", async () => {
const LEAVES = 16;
let leavesIndexes = [];
// insert leaves
for (let i = 0; i < LEAVES; ++i) {
let leafValue = randomBigInt();
tree!.insert(leafValue);
leavesIndexes.push(tree.indexOf(leafValue));
}
for (let i = 0; i < LEAVES; ++i) {
let stateProof = tree.generateProof(i);
await circuit.expectFail({
leaf: stateProof.leaf,
leafIndex: stateProof.index,
siblings: padSiblings(stateProof.siblings, maxDepth),
actualDepth: maxDepth + 1,
});
}
});
});

View File

@@ -24,7 +24,7 @@ describe("Withdraw Circuit", () => {
"stateSiblings",
"stateIndex",
"ASPSiblings",
"ASPIndex"
"ASPIndex",
],
["newCommitmentHash", "existingNullifierHash"]
>;
@@ -43,7 +43,7 @@ describe("Withdraw Circuit", () => {
};
// Get deposit commitment hash
const [depositHash, , depositNullifierHash] = hashCommitment(deposit);
const [depositHash, depositNullifierHash] = hashCommitment(deposit);
// Using Poseidon for hashing the tree nodes
const hash = (a: bigint, b: bigint) => poseidon([a, b]);
@@ -119,7 +119,7 @@ describe("Withdraw Circuit", () => {
{
newCommitmentHash: commitmentHash,
existingNullifierHash: depositNullifierHash,
}
},
);
});
@@ -146,7 +146,7 @@ describe("Withdraw Circuit", () => {
};
// Hash first withdrawal commitment
const [firstChildCommitmentHash, , firstChildNullifierHash] = hashCommitment(firstChild);
const [firstChildCommitmentHash, firstChildNullifierHash] = hashCommitment(firstChild);
// Generate merkle proofs to spend deposit
let stateProof = stateTree.generateProof(2);
@@ -175,7 +175,7 @@ describe("Withdraw Circuit", () => {
{
newCommitmentHash: firstChildCommitmentHash,
existingNullifierHash: depositNullifierHash,
}
},
);
// Insert the new child commitment in the state tree
@@ -190,7 +190,7 @@ describe("Withdraw Circuit", () => {
};
// Hash the second child commitment
const [secondChildComitmentHash, ,] = hashCommitment(secondChild);
const [secondChildComitmentHash] = hashCommitment(secondChild);
// Regenerate state merkle proof
let newStateProof = stateTree.generateProof(3);
@@ -218,7 +218,7 @@ describe("Withdraw Circuit", () => {
{
newCommitmentHash: secondChildComitmentHash,
existingNullifierHash: firstChildNullifierHash,
}
},
);
});
@@ -246,7 +246,7 @@ describe("Withdraw Circuit", () => {
};
// Hash new commitment of zero value
const [commitmentHash, ,] = hashCommitment(fullWithdrawal);
const [commitmentHash] = hashCommitment(fullWithdrawal);
// generate merkle proofs
let stateProof = stateTree.generateProof(1);
@@ -275,7 +275,7 @@ describe("Withdraw Circuit", () => {
{
newCommitmentHash: commitmentHash,
existingNullifierHash: depositNullifierHash,
}
},
);
});
@@ -423,7 +423,7 @@ describe("Withdraw Circuit", () => {
{
newCommitmentHash: firstWithdrawalHash,
existingNullifierHash: depositNullifierHash,
}
},
);
// Insert new commitment in tree
@@ -464,4 +464,96 @@ describe("Withdraw Circuit", () => {
ASPIndex: ASPProof.index,
});
});
it("Withdrawal should fail if reusing a nullifier", async () => {
// Insert deposit commitment in state tree
stateTree!.insert(randomBigInt());
stateTree!.insert(randomBigInt());
stateTree!.insert(randomBigInt());
stateTree!.insert(depositHash);
// Insert deposit label in ASP tree (deposit is now validated)
ASPTree!.insert(randomBigInt());
ASPTree!.insert(randomBigInt());
ASPTree!.insert(randomBigInt());
ASPTree!.insert(LABEL);
// Withrdaw 1 ETH from deposit
const withdrawal = {
value: parseEther("4"), // New value after withdrawal
label: LABEL,
nullifier: deposit.nullifier, // Reusing same nullifier as deposit commitment
secret: randomBigInt(),
};
// Generate merkle proofs for commitment and label
let stateProof = stateTree.generateProof(3);
let ASPProof = ASPTree.generateProof(3);
// Fail to withdraw because using the same nullifier
await circuit.expectFail({
withdrawnValue: parseEther("1"),
stateRoot: stateProof.root,
stateTreeDepth: stateTree.depth,
ASPRoot: ASPProof.root,
ASPTreeDepth: ASPTree.depth,
context: randomBigInt(),
label: LABEL,
existingValue: deposit.value,
existingNullifier: deposit.nullifier,
existingSecret: deposit.secret,
newNullifier: withdrawal.nullifier,
newSecret: withdrawal.secret,
stateSiblings: padSiblings(stateProof.siblings, maxTreeDepth),
stateIndex: stateProof.index,
ASPSiblings: padSiblings(ASPProof.siblings, maxTreeDepth),
ASPIndex: ASPProof.index,
});
});
it("Withdrawal should fail if passing an invalid tree depth", async () => {
// Insert deposit commitment in state tree
stateTree!.insert(randomBigInt());
stateTree!.insert(randomBigInt());
stateTree!.insert(randomBigInt());
stateTree!.insert(depositHash);
// Insert deposit label in ASP tree (deposit is now validated)
ASPTree!.insert(randomBigInt());
ASPTree!.insert(randomBigInt());
ASPTree!.insert(randomBigInt());
ASPTree!.insert(LABEL);
// Withrdaw 1 ETH from deposit
const withdrawal = {
value: parseEther("4"), // New value after withdrawal
label: LABEL,
nullifier: randomBigInt(),
secret: randomBigInt(),
};
// Generate merkle proofs for commitment and label
let stateProof = stateTree.generateProof(3);
let ASPProof = ASPTree.generateProof(3);
// Fail to withdraw because using the same nullifier
await circuit.expectFail({
withdrawnValue: parseEther("1"),
stateRoot: stateProof.root,
stateTreeDepth: 33,
ASPRoot: ASPProof.root,
ASPTreeDepth: ASPTree.depth,
context: randomBigInt(),
label: LABEL,
existingValue: deposit.value,
existingNullifier: deposit.nullifier,
existingSecret: deposit.secret,
newNullifier: withdrawal.nullifier,
newSecret: withdrawal.secret,
stateSiblings: padSiblings(stateProof.siblings, maxTreeDepth),
stateIndex: stateProof.index,
ASPSiblings: padSiblings(ASPProof.siblings, maxTreeDepth),
ASPIndex: ASPProof.index,
});
});
});