/** * Spec-conformance tests for `openspec/specs/crypto-curve/spec.md`. * * Pins structural scenarios that the per-primitive unit suites do not * cover directly: every curve has both `noble.ts` and `native.ts` impl * files, every `*.select.ts` carries the GENERATED banner, every * `*.native.ts` is currently a `PrimitiveNotImplemented` stub (the * runtime reflection of the dangerous-tier "no flip without audit" * gate), and every `*.native.ts` source contains no banned data- * dependent branch patterns on secret material. */ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "@suaveplan/testing/runner"; const ROOT = join(__dirname, ".."); const SRC = join(ROOT, "src"); const PRIMITIVES = join(SRC, "primitives"); const CURVE_IDS = ["secp256k1", "ed25519", "x25519", "p256"] as const; describe("crypto-curve — universal curve primitive surface", () => { it("every curve id has its primitive directory", { timeout: 5000 }, () => { for (const id of CURVE_IDS) { expect(existsSync(join(PRIMITIVES, id))).toBe(true); } }); }); describe("crypto-curve — per-primitive replaceability layout", () => { for (const id of CURVE_IDS) { it(`${id} has both noble.ts and native.ts impl files`, { timeout: 5000, }, () => { const noble = join( PRIMITIVES, id, "impl", `${id}.noble`, `${id}.noble.ts` ); const native = join( PRIMITIVES, id, "impl", `${id}.native`, `${id}.native.ts` ); expect(existsSync(noble)).toBe(true); expect(existsSync(native)).toBe(true); }); it(`${id}.select.ts carries the GENERATED banner`, { timeout: 5000, }, () => { const sel = join(PRIMITIVES, id, `${id}.select`, `${id}.select.ts`); expect(existsSync(sel)).toBe(true); const content = readFileSync(sel, "utf8"); expect(content).toMatch(/GENERATED/); expect(content).toMatch(/DO NOT EDIT/); }); } }); describe("crypto-curve — vendored noble source (Phase 0.5)", () => { it("is a Phase-0.5 forward gate; current state is pre-0.5 (noble dep + no vendored/)", { timeout: 5000, }, () => { const pkg = JSON.parse( readFileSync(join(ROOT, "package.json"), "utf8") ); const noblePresent = "@noble/curves" in (pkg.dependencies ?? {}) || "@noble/curves" in (pkg.peerDependencies ?? {}); const vendoredPresent = existsSync(join(SRC, "vendored")); const upstreamFile = existsSync(join(ROOT, "NOBLE_UPSTREAM.md")); // Either we are pre-0.5 (noble dep present, no vendored, no // upstream record) or post-0.5 (no noble dep, vendored // directory exists with NOBLE_UPSTREAM.md present). Mixed // states are forbidden. const pre05 = noblePresent && !vendoredPresent && !upstreamFile; const post05 = !noblePresent && vendoredPresent && upstreamFile; expect(pre05 || post05).toBe(true); }); }); describe("crypto-curve — constant-time curve math (native stubs)", () => { function srcOf(id: (typeof CURVE_IDS)[number]): string { return readFileSync( join(PRIMITIVES, id, "impl", `${id}.native`, `${id}.native.ts`), "utf8" ); } for (const id of CURVE_IDS) { it(`${id}.native.ts is currently a PrimitiveNotImplemented stub`, { timeout: 5000, }, () => { // While native impls are stubs, "no data-dependent branch on // private key material" is trivially satisfied. The flip-PR // gate (audit + ct-lint pass) is what re-checks the // invariant when the stub is replaced. const src = srcOf(id); expect(src).toMatch(/PrimitiveNotImplemented/); }); } }); describe("crypto-curve — dangerous-tier flip gate (runtime reflection)", () => { it("every native is a stub today, so no curve has been flipped without an audit", { timeout: 5000, }, () => { const offenders: string[] = []; for (const id of CURVE_IDS) { const native = readFileSync( join(PRIMITIVES, id, "impl", `${id}.native`, `${id}.native.ts`), "utf8" ); if (!/PrimitiveNotImplemented/.test(native)) { offenders.push(id); } } // If a curve graduates from stub, this test will fail and // force the change to attach an audit attestation per the // CI-policy gate before re-baselining. expect(offenders).toEqual([]); }); }); void readdirSync; void statSync;