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