/**
 * vf-w7a-crypto-sovereign-proof.ts
 * AS/PLATFORM/2026/007 — Full-Platform Verification Sweep, WAVE W7a.
 * Surface: the server-root "crypto-sovereign" cluster —
 *   pqcEngine (MLKEMEngine + MLDSAEngine + handshake) · hsmEnclave · differentialPrivacy.
 *
 * VERIFICATION-ONLY: this harness asserts what the EXISTING code DOES. It
 * remediates nothing. Every denial is paired with a positive (Rule 18).
 * Env: DEV (Rule 17 — dev verdict only; non-transitive).
 *
 * ── Role axis ────────────────────────────────────────────────────────────────
 * ALL three modules are pure in-process logic (crypto + in-mem Map state); NONE
 * touch a tenant-scoped DB. The RLS role axis (aegis_app vs owner) is therefore
 * N/A platform-wide for W7 — these legs are in-process POS/NEG only. No DB writes,
 * so no marker / cleanup is needed.
 *
 * ── What each group proves ───────────────────────────────────────────────────
 *
 * GROUP K — pqcEngine.MLKEMEngine = REAL/VERIFIED (FIPS 203 ML-KEM-768 via
 *   @noble/post-quantum). The byte-exact NIST KAT proof is the two EXISTING
 *   scripts (scripts/verify-mlkem768-real.ts 125/125 + -engine.ts 30/30, re-run
 *   this wave). These legs add a self-contained engine-API round-trip + the
 *   FIPS-203 implicit-rejection + size-validation behaviour.
 *     K1   generateKeyPair→encapsulate→decapsulate round-trips (SS == SS')
 *     K2   FIPS-203 implicit rejection — tamper 1 ct byte ⇒ decapsulate returns a
 *          DIFFERENT 32-byte secret and does NOT throw (NEG, real lattice behaviour)
 *     K3   FIPS-203 Table-3 sizes (ek 1184 / dk 2400 / ct 1088 / ss 32)
 *     K4   wrong-size ciphertext REJECTED (real input validation, throws)
 *
 * GROUP S — pqcEngine session MAC = REAL symmetric HMAC (honestly labelled
 *   'HMAC-SHA256-PQC'). (MLDSAEngine + /api/pqc/handshake are LABELLED-SIM by
 *   code-read + route self-disclosure — see register; not driven here.)
 *     S1   signTransaction→verifySignature true (POS)
 *     S2   tampered transaction data ⇒ verifySignature false (NEG)
 *
 * GROUP H — hsmEnclave = DEMO-GRADE (in-mem PKCS#11 simulation, honest header
 *   L4-8) with REAL AES-GCM / HMAC primitives BUT a FABRICATED-assurance
 *   attestation sub-surface + sim "PQC" + demo auth.
 *     H1   REAL AES-256-GCM encrypt→decrypt round-trip (POS)
 *     H1b  tampered ciphertext ⇒ decrypt throws (GCM auth, NEG)
 *     H2   REAL HMAC sign→verify true (POS)
 *     H2b  tampered data ⇒ verify false (NEG)
 *     H3   FABRICATION-CONFIRM (F-W7a-1) — getAttestation().valid===true
 *          unconditionally (even on an empty nonce); never computed from a check
 *     H3b  attestation "signature" is a bare 64-hex SHA-256 hash, NOT a signature
 *          (code-read: createHash L557, no key)
 *     H4   DEMO-AUTH — authenticateSession accepts any >=4-char PIN ('0000'→true POS)
 *     H4b  ...and rejects only on length ('12'→false NEG) — the ONLY check is len>=4
 *     H5   sim "PQC" — pqcEncapsulate returns a 1088-byte random ct (fake size)
 *     H5b  SIM-CONFIRM — pqcDecapsulate ACCEPTS a garbage 5-byte ct without error
 *          (ignores the ciphertext entirely L343) — contrast K4 (real engine rejects)
 *
 * GROUP D — differentialPrivacy = REAL (ε,δ)-DP mechanism (calibrated Laplace +
 *   budget + k-anonymity) with two findings.
 *     D1   k-anonymity gate — <minAggregationSize(10) ⇒ null (NEG); >=10 ⇒ result (POS)
 *     D2   noise actually injected — noise!=0 and noisyValue-trueValue==noise (POS)
 *     D2b  REAL calibration — addLaplacianNoise over N samples: mean≈0 + stdev≈√2·scale
 *          (proves a genuine Laplace, not a token perturbation)
 *     D3   budget consumed — remainingEpsilon drops by exactly epsilon per query (POS)
 *     D3b  budget-exhaustion gate — exactly 100 queries succeed, 101st ⇒ null (NEG)
 *     D5   FINDING-CONFIRM (F-W7a-3) — anonymizeTransaction is a DETERMINISTIC hash
 *          with the literal static salt 'salt' (re-id by precomputation): same input
 *          ⇒ same id, and sha256(id+'salt')[:16] reproduces it; merchant hash unsalted
 *   (FINDING F-W7a-2 — DP noise drawn from Math.random (non-CSPRNG) at L328 — is a
 *    code-read finding; a non-CSPRNG cannot be proven a negative behaviourally.)
 *
 * Run: npx tsx scripts/vf-w7a-crypto-sovereign-proof.ts
 */
import crypto from "crypto";
import { MLKEMEngine } from "../server/pqcEngine";
import { initializeGlobalHSM } from "../server/hsmEnclave";
import { DifferentialPrivacyEngine } from "../server/differentialPrivacy";

let passed = 0;
let failed = 0;
const fail = (label: string, detail: string) => { failed++; console.log(`  ✗ FAIL ${label} — ${detail}`); };
const ok = (label: string, detail: string) => { passed++; console.log(`  ✓ ${label} — ${detail}`); };
function assert(cond: boolean, label: string, detail: string) {
  if (cond) ok(label, detail); else fail(label, detail);
}

function txns(n: number) {
  return Array.from({ length: n }, (_, i) => ({
    amount: 1000 + i * 137,
    merchantId: `M-${i % 4}`,
    timestamp: new Date(2026, 5, 18, (i % 24)),
  }));
}

async function main() {
  console.log("=== W7a crypto-sovereign substrate proof (pqcEngine / hsmEnclave / differentialPrivacy) ===");
  console.log("Env: DEV. In-process only — RLS role axis N/A (no tenant DB). No DB writes / no cleanup.\n");

  // ── GROUP K — MLKEMEngine REAL FIPS-203 ──────────────────────────────────
  console.log("[K] pqcEngine.MLKEMEngine — REAL ML-KEM-768 (FIPS 203 via @noble):");
  {
    const eng = new MLKEMEngine("vf-w7a-edge");
    const kp = eng.generateKeyPair();
    const enc = eng.encapsulate(kp.publicKey);
    const ss2 = eng.decapsulate(enc.ciphertext);
    assert(Buffer.compare(ss2, enc.sharedSecret) === 0, "K1", "round-trip: decapsulate(ct) === encapsulated shared secret");

    const tampered = Buffer.from(enc.ciphertext);
    tampered[0] = tampered[0] ^ 0xff;
    let threw = false; let ss3: Buffer | null = null;
    try { ss3 = eng.decapsulate(tampered); } catch { threw = true; }
    assert(!threw && ss3 !== null && ss3.length === 32 && Buffer.compare(ss3, enc.sharedSecret) !== 0,
      "K2", "implicit rejection: tampered ct ⇒ different 32B secret, no throw (FIPS 203 §6.3)");

    assert(kp.publicKey.length === 1184 && kp.secretKey.length === 2400 && enc.ciphertext.length === 1088 && enc.sharedSecret.length === 32,
      "K3", `FIPS-203 sizes ek=${kp.publicKey.length} dk=${kp.secretKey.length} ct=${enc.ciphertext.length} ss=${enc.sharedSecret.length}`);

    let rejected = false;
    try { eng.decapsulate(Buffer.alloc(5)); } catch { rejected = true; }
    assert(rejected, "K4", "wrong-size ciphertext REJECTED (real input validation throws)");
  }

  // ── GROUP S — session MAC REAL HMAC ──────────────────────────────────────
  console.log("\n[S] pqcEngine session MAC — REAL HMAC-SHA256 (honest label):");
  {
    const eng = new MLKEMEngine("vf-w7a-mac");
    const kp = eng.generateKeyPair();
    eng.establishSession("term1", kp.publicKey);
    const data = "tx:1000:UGX:merchantX";
    const sig = eng.signTransaction("term1", data);
    assert(eng.verifySignature("term1", data, sig.signature, 0) === true, "S1", "signTransaction→verifySignature true (POS)");
    assert(eng.verifySignature("term1", "tx:9999:UGX:merchantX", sig.signature, 0) === false, "S2", "tampered data ⇒ verify false (NEG)");
  }

  // ── GROUP H — hsmEnclave DEMO-GRADE + fabricated attestation ──────────────
  console.log("\n[H] hsmEnclave — DEMO-GRADE (real AES/HMAC) + fabricated attestation + demo auth + sim PQC:");
  {
    const hsm = initializeGlobalHSM({ enclaveId: "VF-W7A-HSM" });
    await hsm.initialize();
    const s = hsm.openSession("USER");
    hsm.authenticateSession(s.sessionId, "1234");
    const kh = hsm.generatePQCKey(s.sessionId, "k1");

    const pt = Buffer.from("sovereign-secret-payload");
    const e = hsm.encrypt(s.sessionId, kh.keyId, pt);
    const d = hsm.decrypt(s.sessionId, kh.keyId, e.ciphertext, e.iv, e.tag);
    assert(Buffer.compare(d, pt) === 0, "H1", "REAL AES-256-GCM encrypt→decrypt round-trip (POS)");

    const badCt = Buffer.from(e.ciphertext); badCt[0] = badCt[0] ^ 0xff;
    let gcmThrew = false;
    try { hsm.decrypt(s.sessionId, kh.keyId, badCt, e.iv, e.tag); } catch { gcmThrew = true; }
    assert(gcmThrew, "H1b", "tampered ciphertext ⇒ decrypt throws (GCM auth tag, NEG)");

    const sd = Buffer.from("attest-this");
    const sig = hsm.sign(s.sessionId, kh.keyId, sd);
    assert(hsm.verify(s.sessionId, kh.keyId, sd, sig) === true, "H2", "REAL HMAC sign→verify true (POS)");
    assert(hsm.verify(s.sessionId, kh.keyId, Buffer.from("attest-THAT"), sig) === false, "H2b", "tampered data ⇒ verify false (NEG)");

    const att1 = hsm.getAttestation("nonce-1");
    const att2 = hsm.getAttestation("");
    assert(att1.valid === true && att2.valid === true, "H3", "F-W7a-1: getAttestation().valid===true unconditionally (even empty nonce) — hardcoded, never computed");
    assert(/^[0-9a-f]{64}$/.test(att1.signature), "H3b", `attestation "signature" is a bare 64-hex SHA-256 hash (createHash, no key) len=${att1.signature.length}`);

    const sA = hsm.openSession("USER");
    assert(hsm.authenticateSession(sA.sessionId, "0000") === true, "H4", "DEMO-AUTH: any >=4-char PIN '0000' accepted (POS)");
    const sB = hsm.openSession("USER");
    assert(hsm.authenticateSession(sB.sessionId, "12") === false, "H4b", "the ONLY check is length>=4: '12' rejected (NEG)");

    const encap = hsm.pqcEncapsulate(s.sessionId, kh.keyId);
    assert(encap.ciphertext.length === 1088, "H5", `sim "PQC": pqcEncapsulate returns ${encap.ciphertext.length}-byte RANDOM ct (crypto.randomBytes, not lattice)`);
    let simAccepted = false;
    try { const h = hsm.pqcDecapsulate(s.sessionId, kh.keyId, Buffer.alloc(5)); simAccepted = typeof h === "string" && h.startsWith("SS-"); } catch { simAccepted = false; }
    assert(simAccepted, "H5b", "SIM-CONFIRM: pqcDecapsulate ACCEPTS a 5-byte garbage ct (ignores ciphertext, L343) — contrast K4");
  }

  // ── GROUP D — differentialPrivacy REAL mechanism + findings ───────────────
  console.log("\n[D] differentialPrivacy — REAL (ε,δ)-DP mechanism + findings:");
  {
    const dp = new DifferentialPrivacyEngine();
    assert(dp.generatePrivateAggregate("R", txns(5)) === null, "D1neg", "k-anonymity: <10 records ⇒ null (NEG)");
    const r = dp.generatePrivateAggregate("R", txns(10));
    assert(r !== null && typeof r.noisyValue === "number" && r.recordCount === 10, "D1pos", "k-anonymity: >=10 records ⇒ result (POS)");
    assert(r !== null && r.noise !== 0 && Math.abs((r.noisyValue === Math.max(0, r.trueValue + r.noise) ? r.trueValue + r.noise : r.noisyValue) - r.trueValue - r.noise) < 1e-6,
      "D2", `noise injected: noise=${r ? Math.round(r.noise) : 0}, noisyValue=trueValue+noise`);

    // D2b — calibration over many samples (REAL Laplace: mean≈0, stdev≈√2·scale)
    const dp2 = new DifferentialPrivacyEngine();
    const N = 20000;
    let sum = 0; let sumsq = 0;
    for (let i = 0; i < N; i++) { const { noise } = dp2.addLaplacianNoise(0); sum += noise; sumsq += noise * noise; }
    const mean = sum / N;
    const stdev = Math.sqrt(sumsq / N - mean * mean);
    const scale = 10000 / 1.0; // sensitivity/epsilon (defaults)
    const expectedStdev = Math.SQRT2 * scale; // ≈14142
    assert(Math.abs(mean) < 1500, "D2b-mean", `Laplace mean≈0 (mean=${mean.toFixed(1)}, |·|<1500 over N=${N})`);
    assert(stdev > expectedStdev * 0.78 && stdev < expectedStdev * 1.22, "D2b-stdev", `Laplace stdev≈√2·scale (stdev=${stdev.toFixed(0)}, expected≈${expectedStdev.toFixed(0)})`);

    // D3 — budget consumed by exactly epsilon per query
    const dp3 = new DifferentialPrivacyEngine();
    const b0 = dp3.getBudgetStatus().remainingEpsilon;
    dp3.generatePrivateAggregate("R", txns(10));
    const b1 = dp3.getBudgetStatus().remainingEpsilon;
    assert(Math.abs((b0 - b1) - dp3.getConfig().epsilon) < 1e-9 && dp3.getBudgetStatus().queryCount === 1,
      "D3", `budget consumed: remaining ${b0}→${b1} (Δ=${(b0 - b1).toFixed(2)}=epsilon)`);

    // D3b — exhaustion: total budget = epsilon*100 ⇒ exactly 100 queries then null
    const dp4 = new DifferentialPrivacyEngine();
    let successes = 0;
    for (let i = 0; i < 100; i++) { if (dp4.generatePrivateAggregate("R", txns(10)) !== null) successes++; else break; }
    const after = dp4.generatePrivateAggregate("R", txns(10));
    assert(successes === 100 && after === null, "D3b", `budget-exhaustion: ${successes}/100 succeed then 101st ⇒ null (POS+NEG)`);

    // D5 — F-W7a-3 re-identification (deterministic static-salt hash)
    const dp5 = new DifferentialPrivacyEngine();
    const tx = { id: "CUST-123", amount: 5000, merchantId: "MERCH-9", customerId: "C9", timestamp: new Date(2026, 5, 18, 13), location: { lat: 0.347, lng: 32.582 } };
    const a1 = dp5.anonymizeTransaction(tx);
    const a2 = dp5.anonymizeTransaction(tx);
    assert(a1.anonymizedId === a2.anonymizedId, "D5-det", "anonymizeTransaction is DETERMINISTIC (same input ⇒ same id)");
    const recomputed = crypto.createHash("sha256").update("CUST-123" + "salt").digest("hex").substring(0, 16);
    assert(recomputed === a1.anonymizedId, "D5-salt", "F-W7a-3: id = sha256(id+'salt')[:16] — literal static salt, reversible by precomputation");
    const merchRecomputed = crypto.createHash("sha256").update("MERCH-9").digest("hex").substring(0, 4);
    assert(merchRecomputed === a1.merchantRegion, "D5-merch", "F-W7a-3: merchantRegion = UNSALTED sha256(merchantId)[:4] — dictionary-attackable");
  }

  console.log(`\n=== SUMMARY: ${passed} passed, ${failed} failed ===`);
  if (failed === 0) console.log("RESULT: ✓ ALL LEGS GREEN — W7a crypto-sovereign behaviours verified (dev, in-process).");
  else console.log("RESULT: ✗ SOME LEGS FAILED.");
  process.exit(failed === 0 ? 0 : 1);
}

main().catch((e) => { console.error("HARNESS ERROR:", e); process.exit(2); });
