// kzg-verifier.test.js // // AereKZGVerifier over the EIP-4844 point-evaluation precompile (0x0A). // // The local hardhat network (EDR/revm, hardfork cancun) implements the REAL // KZG point-evaluation precompile with the official ceremony trusted setup, // so these tests exercise genuine KZG verification, not a mock. The KAT is // the official go-ethereum precompile test vector (pointEvaluation1), which // was also confirmed live against AERE chain 2800 via eth_call on 2026-07-10. const { expect } = require("chai"); const { ethers } = require("hardhat"); const kat = require("./fixtures/kzg-point-evaluation-kat.json"); const PRECOMPILE = "0x000000000000000000000000000000000000000A"; const BLS_MODULUS = "52435875175126190479447740508185965837690552500527637822603658699938581184513"; describe("AereKZGVerifier (EIP-4844 point-evaluation)", function () { let verifier, user, user2; before(async function () { [user, user2] = await ethers.getSigners(); // Sanity: the local EVM must actually have the precompile, otherwise // every test below would be meaningless. const raw = await ethers.provider.call({ to: PRECOMPILE, data: kat.input }); expect(raw).to.equal(kat.expected); const F = await ethers.getContractFactory("AereKZGVerifier"); verifier = await F.deploy(); await verifier.waitForDeployment(); }); it("exposes the canonical EIP-4844 constants", async function () { expect(await verifier.POINT_EVALUATION()).to.equal(PRECOMPILE); expect(await verifier.INPUT_LENGTH()).to.equal(192n); expect(await verifier.FIELD_ELEMENTS_PER_BLOB()).to.equal(4096n); expect(await verifier.BLS_MODULUS()).to.equal(BigInt(BLS_MODULUS)); }); it("checkPointEvaluation returns true for the official KAT", async function () { expect(await verifier.checkPointEvaluation(kat.input)).to.equal(true); }); it("verifyPointEvaluation records the KAT and emits the event", async function () { await expect(verifier.connect(user).verifyPointEvaluation(kat.input)) .to.emit(verifier, "PointEvaluationVerified") .withArgs(user.address, kat.versionedHash, kat.z, kat.y, 0n); expect(await verifier.verificationCount()).to.equal(1n); const rec = await verifier.getVerification(0); expect(rec.sender).to.equal(user.address); expect(rec.versionedHash).to.equal(kat.versionedHash); expect(rec.z).to.equal(kat.z); expect(rec.y).to.equal(kat.y); expect(rec.blockNumber).to.be.gt(0n); expect(rec.timestamp).to.be.gt(0n); expect(await verifier.verificationCountByHash(kat.versionedHash)).to.equal(1n); }); it("records repeat verifications and tracks the latest per hash", async function () { await expect(verifier.connect(user2).verifyPointEvaluation(kat.input)) .to.emit(verifier, "PointEvaluationVerified") .withArgs(user2.address, kat.versionedHash, kat.z, kat.y, 1n); expect(await verifier.verificationCount()).to.equal(2n); expect(await verifier.verificationCountByHash(kat.versionedHash)).to.equal(2n); const latest = await verifier.getLatestVerificationForHash(kat.versionedHash); expect(latest.sender).to.equal(user2.address); }); it("rejects a corrupted proof (last byte flipped)", async function () { const bad = ethers.getBytes(kat.input); bad[bad.length - 1] ^= 0x01; await expect( verifier.checkPointEvaluation(ethers.hexlify(bad)) ).to.be.revertedWithCustomError(verifier, "PrecompileCallFailed"); await expect( verifier.verifyPointEvaluation(ethers.hexlify(bad)) ).to.be.revertedWithCustomError(verifier, "PrecompileCallFailed"); }); it("rejects a corrupted commitment", async function () { const bad = ethers.getBytes(kat.input); bad[100] ^= 0x01; // inside the 48-byte commitment (bytes 96..143) await expect( verifier.checkPointEvaluation(ethers.hexlify(bad)) ).to.be.revertedWithCustomError(verifier, "PrecompileCallFailed"); }); it("rejects a mismatched versioned hash", async function () { const bad = ethers.getBytes(kat.input); bad[31] ^= 0x01; // versioned hash no longer sha256(commitment)|0x01 await expect( verifier.checkPointEvaluation(ethers.hexlify(bad)) ).to.be.revertedWithCustomError(verifier, "PrecompileCallFailed"); }); it("rejects a wrong-version versioned hash (0x02 prefix)", async function () { const bad = ethers.getBytes(kat.input); bad[0] = 0x02; await expect( verifier.checkPointEvaluation(ethers.hexlify(bad)) ).to.be.revertedWithCustomError(verifier, "PrecompileCallFailed"); }); it("rejects wrong-length input without touching the precompile", async function () { await expect(verifier.checkPointEvaluation("0x1234")) .to.be.revertedWithCustomError(verifier, "InvalidInputLength") .withArgs(2n); await expect(verifier.checkPointEvaluation(kat.input + "00")) .to.be.revertedWithCustomError(verifier, "InvalidInputLength") .withArgs(193n); }); it("rejects an out-of-field z (z >= BLS_MODULUS)", async function () { const bad = ethers.getBytes(kat.input); // set z (bytes 32..63) to BLS_MODULUS itself, which is out of range const mod = ethers.toBeHex(BigInt(BLS_MODULUS), 32); ethers.getBytes(mod).forEach((b, i) => { bad[32 + i] = b; }); await expect( verifier.checkPointEvaluation(ethers.hexlify(bad)) ).to.be.revertedWithCustomError(verifier, "PrecompileCallFailed"); }); it("getLatestVerificationForHash reverts for a never-verified hash", async function () { await expect( verifier.getLatestVerificationForHash(ethers.ZeroHash) ).to.be.revertedWith("AereKZGVerifier: hash never verified"); }); it("getVerification reverts out of range", async function () { await expect(verifier.getVerification(999)).to.be.reverted; }); });