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.
114 lines
4.0 KiB
JavaScript
114 lines
4.0 KiB
JavaScript
// 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"
|
|
);
|
|
});
|
|
});
|