diff --git a/src/verifier/Verifier.sol b/src/verifier/Verifier.sol index 8bf328f..3ec3981 100644 --- a/src/verifier/Verifier.sol +++ b/src/verifier/Verifier.sol @@ -395,7 +395,7 @@ contract Verifier { res = BN254.add(res, permTerm); // Add in the quotient polynomial contribution - BN254.G1Point memory quotientTerm = plonkStep9QuotientTerm(vk.n, challenges.zeta, vanishingEval, proof); + BN254.G1Point memory quotientTerm = plonkStep9QuotientTerm(challenges.zeta, vanishingEval, proof); res = BN254.add(res, quotientTerm); return res; } @@ -491,7 +491,6 @@ contract Verifier { /// @notice Compute the quotient polynomial contribution to the linearized polynomial relation function plonkStep9QuotientTerm( - uint256 n, BN254.ScalarField zeta, BN254.ScalarField vanishingEval, PlonkProof memory proof diff --git a/test/Verifier.t.sol b/test/Verifier.t.sol index 6a156b5..2b15d44 100644 --- a/test/Verifier.t.sol +++ b/test/Verifier.t.sol @@ -312,6 +312,96 @@ contract VerifierTest is VerifierTestUtils { require(res, "Original proof verification should have succeeded"); } + /// @notice Test that batch verification fails if any proof in the batch is invalid + function testInvalidBatchVerification() public { + // First generate the verification keys for the circuits + compileRustBinary("test/rust-reference-impls/verifier/Cargo.toml"); + + // Generate batch test data + (PlonkProof[] memory proofs, BN254.ScalarField[][] memory publicInputs, VerificationKey[] memory vks) = + generateBatchProofData(); + + // Randomly select a proof to modify + uint256 proofToModify = randomUint(proofs.length); + PlonkProof memory invalidProof = clonePlonkProof(proofs[proofToModify]); + + // Randomly select which part of the proof to modify + uint256 modType = randomUint(8); + BN254.G1Point memory dummyG1Point = BN254.P1(); + BN254.ScalarField dummyScalar = BN254.ScalarField.wrap(1); + + if (modType == 0) { + // Modify a wire commitment + uint256 randomIdx = randomUint(NUM_WIRE_TYPES); + invalidProof.wire_comms[randomIdx] = dummyG1Point; + } else if (modType == 1) { + // Modify z_comm + invalidProof.z_comm = dummyG1Point; + } else if (modType == 2) { + // Modify a quotient commitment + uint256 randomIdx = randomUint(NUM_WIRE_TYPES); + invalidProof.quotient_comms[randomIdx] = dummyG1Point; + } else if (modType == 3) { + // Modify w_zeta + invalidProof.w_zeta = dummyG1Point; + } else if (modType == 4) { + // Modify w_zeta_omega + invalidProof.w_zeta_omega = dummyG1Point; + } else if (modType == 5) { + // Modify a wire evaluation + uint256 randomIdx = randomUint(NUM_WIRE_TYPES); + invalidProof.wire_evals[randomIdx] = dummyScalar; + } else if (modType == 6) { + // Modify a sigma evaluation + uint256 randomIdx = randomUint(NUM_WIRE_TYPES - 1); + invalidProof.sigma_evals[randomIdx] = dummyScalar; + } else { + // Modify z_bar + invalidProof.z_bar = dummyScalar; + } + + // Replace the selected proof with the invalid one + proofs[proofToModify] = invalidProof; + + // Verify the batch - should fail + bool res = verifier.batchVerify(proofs, publicInputs, vks); + require(!res, "Proof verification should have failed"); + } + + /// @notice Test the case in which a public input is modified + function testModifiedPublicInput() public { + // First generate the verification keys for the circuits + compileRustBinary("test/rust-reference-impls/verifier/Cargo.toml"); + VerificationKey memory vkey = getPermutationVkey(); + + // Generate data for the permutation circuit + uint256 randomChallenge = randomFelt(); + uint256[5] memory statement; + uint256[5] memory witness; + for (uint256 i = 0; i < 5; i++) { + statement[i] = randomFelt(); + witness[5 - i - 1] = statement[i]; + } + + // Get the proof and public input + PlonkProof memory proof = getPermutationProof(randomChallenge, statement, witness); + + // Verify the proof + BN254.ScalarField[] memory publicInputs = new BN254.ScalarField[](6); + publicInputs[0] = BN254.ScalarField.wrap(randomChallenge); + for (uint256 i = 0; i < 5; i++) { + publicInputs[i + 1] = BN254.ScalarField.wrap(statement[i]); + } + + // Modify the public input + uint256 randomIdx = randomUint(publicInputs.length); + publicInputs[randomIdx] = BN254.ScalarField.wrap(randomFelt()); + + // Verify the proof + bool res = verifier.verify(proof, publicInputs, vkey); + require(!res, "Proof verification should have failed"); + } + // --- Valid Test Cases --- // /// @notice Test the verifier against a reference implementation on the mul-two circuit @@ -386,4 +476,18 @@ contract VerifierTest is VerifierTestUtils { bool res = verifier.verify(proof, publicInputs, vkey); require(res, "Proof verification should have succeeded"); } + + /// @notice Test batch verification against all three circuits + function testBatchVerification() public { + // First generate the verification keys for the circuits + compileRustBinary("test/rust-reference-impls/verifier/Cargo.toml"); + + // Generate batch test data + (PlonkProof[] memory proofs, BN254.ScalarField[][] memory publicInputs, VerificationKey[] memory vks) = + generateBatchProofData(); + + // Verify the batch + bool res = verifier.batchVerify(proofs, publicInputs, vks); + require(res, "Proof verification should have succeeded"); + } } diff --git a/test/utils/VerifierTestUtils.sol b/test/utils/VerifierTestUtils.sol index dc11c3e..ea63471 100644 --- a/test/utils/VerifierTestUtils.sol +++ b/test/utils/VerifierTestUtils.sol @@ -177,4 +177,53 @@ contract VerifierTestUtils is TestUtils { z_bar: original.z_bar }); } + + /// @dev Helper function to generate a batch of proofs, verification keys, and public inputs + function generateBatchProofData() + internal + returns (PlonkProof[] memory proofs, BN254.ScalarField[][] memory publicInputs, VerificationKey[] memory vks) + { + proofs = new PlonkProof[](3); + vks = new VerificationKey[](3); + publicInputs = new BN254.ScalarField[][](3); + + // Generate mul-two proof and data + uint256 a = randomFelt(); + uint256 b = randomFelt(); + (uint256 c, PlonkProof memory mulTwoProof) = getMulTwoProof(a, b); + proofs[0] = mulTwoProof; + vks[0] = getMulTwoVkey(); + publicInputs[0] = new BN254.ScalarField[](1); + publicInputs[0][0] = BN254.ScalarField.wrap(c); + + // Generate sum-pow proof and data + uint256[10] memory inputs; + for (uint256 i = 0; i < 10; i++) { + inputs[i] = randomFelt(); + } + (BN254.ScalarField sumPow, PlonkProof memory sumPowProof) = getSumPowProof(inputs); + proofs[1] = sumPowProof; + vks[1] = getSumPowVkey(); + publicInputs[1] = new BN254.ScalarField[](1); + publicInputs[1][0] = sumPow; + + // Generate permutation proof and data + uint256 randomChallenge = randomFelt(); + uint256[5] memory statement; + uint256[5] memory witness; + for (uint256 i = 0; i < 5; i++) { + statement[i] = randomFelt(); + witness[5 - i - 1] = statement[i]; + } + PlonkProof memory permutationProof = getPermutationProof(randomChallenge, statement, witness); + proofs[2] = permutationProof; + vks[2] = getPermutationVkey(); + publicInputs[2] = new BN254.ScalarField[](6); + publicInputs[2][0] = BN254.ScalarField.wrap(randomChallenge); + for (uint256 i = 0; i < 5; i++) { + publicInputs[2][i + 1] = BN254.ScalarField.wrap(statement[i]); + } + + return (proofs, publicInputs, vks); + } }