aere-contracts/test/kzg-verifier.test.js
Aere Network a13a649b77
Some checks are pending
contracts-ci / Install (lockfile) → compile → full test suite (push) Waiting to run
contracts-ci / PQC known-answer tests (NIST vectors) (push) Waiting to run
contracts-ci / Coverage (scoped, with artifacts) (push) Waiting to run
Initial public release
Aere Network public source. Everything here can be checked against the live
chain (chain id 2800, https://rpc.aere.network).

Scope note, stated up front rather than buried: consensus on chain 2800 is
classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at
the signature, precompile, account and transport layers. Nothing here makes the
consensus post-quantum, and no document in it should be read as claiming so.
2026-07-20 01:02:37 +03:00

138 lines
5.7 KiB
JavaScript

// 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;
});
});