const { expect } = require("chai"); const { ethers } = require("hardhat"); const Q = 12289, N = 64; function ringMul(a, b) { const t = new Array(N).fill(0); for (let i = 0; i < N; i++) { if (!a[i]) continue; for (let j = 0; j < N; j++) { const p = (a[i] * b[j]) % Q; const k = i + j; if (k < N) t[k] = (t[k] + p) % Q; else t[k - N] = (t[k - N] + Q - p) % Q; } } return t; } const short = () => Array.from({ length: N }, () => (((Math.floor(Math.random() * 7) - 3) % Q) + Q) % Q); // coeffs in [-3,3] const randPoly = () => Array.from({ length: N }, () => Math.floor(Math.random() * Q)); describe("AereLatticeVerifier (Falcon/Dilithium-family lattice core)", function () { async function deploy() { const V = await ethers.getContractFactory("AereLatticeVerifier"); const v = await V.deploy(); await v.waitForDeployment(); return v; } it("accepts a valid short-vector lattice signature", async function () { const v = await deploy(); const s1 = short(), s2 = short(), h = randPoly(); const c = ringMul(s2, h).map((tv, i) => (s1[i] + tv) % Q); // c = s1 + s2*h expect(await v.verify(h, c, s1, s2, 20000)).to.equal(true); }); it("rejects a tampered s1 (relation broken)", async function () { const v = await deploy(); const s1 = short(), s2 = short(), h = randPoly(); const c = ringMul(s2, h).map((tv, i) => (s1[i] + tv) % Q); const bad = [...s1]; bad[0] = (bad[0] + 1) % Q; expect(await v.verify(h, c, bad, s2, 20000)).to.equal(false); }); it("rejects a forgery: the relation holds but (s1,s2) is NOT short", async function () { const v = await deploy(); const s1 = short(), s2 = short(), h = randPoly(); const c = ringMul(s2, h).map((tv, i) => (s1[i] + tv) % Q); // attacker picks a different short s2b, solves s1b = c - s2b*h — which is LARGE const s2b = short(); const tb = ringMul(s2b, h); const s1b = c.map((cv, i) => ((cv - tb[i]) % Q + Q) % Q); // relation c - s2b*h == s1b holds by construction, but norm blows the bound expect(await v.verify(h, c, s1b, s2b, 20000)).to.equal(false); }); it("ringMul is negacyclic (x^n = -1): x^(n-1) * x = -1", async function () { const v = await deploy(); const a = new Array(N).fill(0); a[N - 1] = 1; // x^(n-1) const b = new Array(N).fill(0); b[1] = 1; // x const t = (await v.ringMul(a, b)).map(Number); // x^(n-1) * x = x^n = -1 == q-1 at coefficient 0 expect(t[0]).to.equal(Q - 1); expect(t.slice(1).every(x => x === 0)).to.equal(true); }); });