// halo2-cubic-verifier.test.js // // Real Halo2 (bn254/KZG, Bdfg21/SHPLONK) verifier generated by // privacy-scaling-explorations/halo2-solidity-verifier on the AERE build // server, for a genuine 4-row standard-PLONK circuit proving knowledge of a // private x with x^3 + x + 5 == out (witness x = 3, public instance out = 35). // // The proof in the fixture is a REAL halo2 proof: natively verified by // halo2_proofs (VerifierSHPLONK) and re-verified in revm before it was // exported. These tests re-verify it a third time inside the hardhat EVM. const { expect } = require("chai"); const { ethers } = require("hardhat"); const fixture = require("./fixtures/aere-halo2-cubic-proof.json"); const EIP7825_TX_GAS_CAP = 16777216; describe("AereHalo2CubicVerifier + AereHalo2ProofAnchor", function () { let verifier, anchor, user; const instances = fixture.instances.map(BigInt); // [35n] before(async function () { [user] = await ethers.getSigners(); const V = await ethers.getContractFactory("AereHalo2CubicVerifier"); verifier = await V.deploy(); await verifier.waitForDeployment(); const A = await ethers.getContractFactory("AereHalo2ProofAnchor"); anchor = await A.deploy(await verifier.getAddress()); await anchor.waitForDeployment(); }); it("verifies the real proof via the exact exported calldata", async function () { const raw = await ethers.provider.call({ to: await verifier.getAddress(), data: fixture.calldata, }); expect(raw).to.equal( "0x0000000000000000000000000000000000000000000000000000000000000001" ); }); it("verifies the real proof via the typed ABI", async function () { expect( await verifier.verifyProof.staticCall(fixture.proof, instances) ).to.equal(true); }); it("verification gas fits comfortably under the EIP-7825 per-tx cap", async function () { const gas = await verifier.verifyProof.estimateGas(fixture.proof, instances); expect(gas).to.be.lt(BigInt(EIP7825_TX_GAS_CAP)); }); it("rejects a corrupted proof (byte flipped)", async function () { const bad = ethers.getBytes(fixture.proof); bad[100] ^= 0x01; await expect( verifier.verifyProof.staticCall(ethers.hexlify(bad), instances) ).to.be.reverted; }); it("rejects a truncated proof", async function () { const bad = ethers.getBytes(fixture.proof).slice(0, 64); await expect( verifier.verifyProof.staticCall(ethers.hexlify(bad), instances) ).to.be.reverted; }); it("rejects the right proof against the wrong public instance", async function () { await expect( verifier.verifyProof.staticCall(fixture.proof, [34n]) ).to.be.reverted; await expect( verifier.verifyProof.staticCall(fixture.proof, [36n]) ).to.be.reverted; }); it("anchor records a successful verification and emits the event", async function () { const proofHash = ethers.keccak256(fixture.proof); const instancesHash = ethers.solidityPackedKeccak256( ["uint256[]"], [instances] ); await expect(anchor.verifyAndRecord(fixture.proof, instances)) .to.emit(anchor, "Halo2ProofVerified") .withArgs(user.address, proofHash, instancesHash, 0n); expect(await anchor.recordCount()).to.equal(1n); const rec = await anchor.getRecord(0); expect(rec.sender).to.equal(user.address); expect(rec.proofHash).to.equal(proofHash); expect(rec.instancesHash).to.equal(instancesHash); expect(await anchor.verificationCountByProofHash(proofHash)).to.equal(1n); }); it("anchor rejects an invalid proof (verifier revert bubbles up)", async function () { const bad = ethers.getBytes(fixture.proof); bad[200] ^= 0x01; await expect(anchor.verifyAndRecord(ethers.hexlify(bad), instances)).to.be .reverted; expect(await anchor.recordCount()).to.equal(1n); }); it("anchor refuses a zero verifier address", async function () { const A = await ethers.getContractFactory("AereHalo2ProofAnchor"); await expect(A.deploy(ethers.ZeroAddress)).to.be.revertedWithCustomError( A, "ZeroVerifier" ); }); });