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