aere-contracts/test/mldsa44Verifier.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

59 lines
2.6 KiB
JavaScript

const { expect } = require("chai");
const { ethers } = require("hardhat");
const kat = require("./fixtures/mldsa44-acvp-tg8.json");
// ---------------------------------------------------------------------------
// AereMLDSA44Verifier — validated bit-for-bit against the OFFICIAL NIST ACVP
// ML-DSA-sigVer-FIPS204 test vectors, test group 8 (ML-DSA-44, internal
// interface, externalMu=false).
//
// A single ML-DSA-44 verify is heavy (~52.9M gas) and viaIR-compiled; the
// in-process EVM needs a larger JS stack and leaks memory across many heavy
// calls, so run this suite (and the exhaustive all-15 validator) with:
//
// node --stack-size=8000 --max-old-space-size=8192 \
// ./node_modules/hardhat/internal/cli/bootstrap.js test test/mldsa44Verifier.test.js
//
// This suite runs a curated subset (a few heavy + the cheap early-reject paths)
// to stay under the interpreter's per-process ceiling. The FULL 15/15 ACVP
// validation is in scripts/test-mldsa-local.js (batched per process) and was
// also demonstrated live on AERE mainnet via eth_call — see
// deployments/mldsa-44-verifier.json.
// ---------------------------------------------------------------------------
describe("AereMLDSA44Verifier (FIPS 204, NIST ACVP KAT)", function () {
this.timeout(600000);
let v;
const byId = (id) => kat.tests.find((t) => t.tcId === id);
before(async () => {
const F = await ethers.getContractFactory("AereMLDSA44Verifier");
v = await F.deploy();
await v.waitForDeployment();
});
it("accepts the official valid vector (tc108)", async () => {
const t = byId(108);
expect(await v.verify(t.pk, t.message, t.signature)).to.equal(true);
});
it("rejects official crafted-invalid vectors (message / z / commitment / hint)", async () => {
for (const id of [106 /*message*/, 110 /*z*/, 109 /*commitment*/, 113 /*hint*/]) {
const t = byId(id);
expect(await v.verify(t.pk, t.message, t.signature), `tc${id} (${t.reason})`).to.equal(false);
}
});
it("rejects explicit byte-flips inside c~ and in the message of a valid vector", async () => {
const t = byId(108);
const flip = (hex, i) => { const b = ethers.getBytes(hex); b[i] ^= 0x01; return ethers.hexlify(b); };
expect(await v.verify(t.pk, t.message, flip(t.signature, 5))).to.equal(false); // c~
expect(await v.verify(t.pk, flip(t.message, 0), t.signature)).to.equal(false); // message
});
it("rejects malformed lengths (cheap early-return)", async () => {
const t = byId(108);
expect(await v.verify(t.pk + "00", t.message, t.signature)).to.equal(false);
expect(await v.verify(t.pk, t.message, t.signature + "00")).to.equal(false);
});
});