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.
59 lines
2.6 KiB
JavaScript
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);
|
|
});
|
|
});
|