const { expect } = require("chai");
const { ethers } = require("hardhat");
const kat = require("./fixtures/sphincs-sha2-128s-acvp-tg31.json");

// ---------------------------------------------------------------------------
// AereSphincsVerifier - validated bit-for-bit against the OFFICIAL NIST FIPS 205
// ACVP SLH-DSA-sigVer vectors, test group 31 (SLH-DSA-SHA2-128s, internal
// interface, preHash none). A full verify is ~1.8M gas (assembly SHA-256
// tweakable hash), so the whole 14-vector suite runs comfortably in-process.
//
// KAT source: NIST ACVP-Server gen-val/json-files/SLH-DSA-sigVer-FIPS205
//   prompt.json sha256          4e7beb1233e47baa0acdd36417c66c45811aa40a4e32ffdb1a35d93b13b289fb
//   expectedResults.json sha256 259f5e2a0665de0adc0fefa45b5db3a2a6ed13c3c44d14bdaf64a80aee12c687
//   internalProjection.json sha a013fc2104f4ed4799d96d51141f65b965969b2cf10646626a021b6d456ce792
// ---------------------------------------------------------------------------
describe("AereSphincsVerifier (FIPS 205 SLH-DSA-SHA2-128s, NIST ACVP KAT)", function () {
  this.timeout(600000);
  let v;
  const byId = (id) => kat.tests.find((t) => t.tcId === id);
  const flip = (hex, i) => { const b = ethers.getBytes(hex); b[i] ^= 0x01; return ethers.hexlify(b); };

  before(async () => {
    const F = await ethers.getContractFactory("AereSphincsVerifier");
    v = await F.deploy();
    await v.waitForDeployment();
  });

  it("advertises the parameter set", async () => {
    expect(await v.paramSet()).to.equal("SLH-DSA-SHA2-128s (SPHINCS+-SHA2-128s-simple), FIPS 205");
    expect(await v.SIG_BYTES()).to.equal(7856n);
  });

  it("reproduces NIST's expected testPassed for all 14 ACVP vectors", async () => {
    for (const t of kat.tests) {
      expect(await v.verify(t.pk, t.message, t.signature), `tc${t.tcId} (${t.reason})`).to.equal(t.expectedPass);
    }
  });

  it("accepts the official valid vectors (tc422, tc424)", async () => {
    for (const id of [422, 424]) {
      const t = byId(id);
      expect(await v.verify(t.pk, t.message, t.signature)).to.equal(true);
    }
  });

  it("rejects explicit byte-flips inside R / SIG_FORS / SIG_HT / message of a valid vector", async () => {
    const t = byId(422);
    expect(await v.verify(t.pk, t.message, t.signature)).to.equal(true);
    expect(await v.verify(t.pk, t.message, flip(t.signature, 0))).to.equal(false); // R
    expect(await v.verify(t.pk, t.message, flip(t.signature, 20))).to.equal(false); // SIG_FORS
    expect(await v.verify(t.pk, t.message, flip(t.signature, 3000))).to.equal(false); // SIG_HT
    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(422);
    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);
    expect(await v.verify(t.pk, t.message, t.signature.slice(0, -2))).to.equal(false);
  });

  it("verifyAndRecord fits under the EIP-7825 2^24 per-tx cap and records the result", async () => {
    const t = byId(422);
    const g = await v.verifyAndRecord.estimateGas(t.pk, t.message, t.signature);
    expect(g).to.be.lessThan(16777216n);
    const tx = await v.verifyAndRecord(t.pk, t.message, t.signature);
    const rc = await tx.wait();
    expect(rc.status).to.equal(1);
    expect(await v.lastResult()).to.equal(true);
    expect(await v.verifyCount()).to.equal(1n);
  });
});
