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