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.
138 lines
5.7 KiB
JavaScript
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;
|
|
});
|
|
});
|