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