@quantakrypto/sieve 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/categories/index.d.ts +1 -1
- package/dist/categories/index.d.ts.map +1 -1
- package/dist/categories/index.js.map +1 -1
- package/dist/categories/kat.d.ts.map +1 -1
- package/dist/categories/kat.js +18 -4
- package/dist/categories/kat.js.map +1 -1
- package/dist/protocol.d.ts +11 -13
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/dist/vectors.d.ts +5 -4
- package/dist/vectors.d.ts.map +1 -1
- package/dist/vectors.js.map +1 -1
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ import { kat } from "./kat.js";
|
|
|
15
15
|
import { timing } from "./timing.js";
|
|
16
16
|
export * from "./types.js";
|
|
17
17
|
/** A named, family-scoped category. */
|
|
18
|
-
|
|
18
|
+
interface RegisteredCategory {
|
|
19
19
|
name: string;
|
|
20
20
|
family: Family | "any";
|
|
21
21
|
/** Whether the category runs by default (timing is opt-in). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/categories/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,cAAc,YAAY,CAAC;AAE3B,uCAAuC;AACvC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/categories/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,cAAc,YAAY,CAAC;AAE3B,uCAAuC;AACvC,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;IACvB,+DAA+D;IAC/D,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,EAAE,QAAQ,CAAC;CACf;AAED,4CAA4C;AAC5C,eAAO,MAAM,UAAU,EAAE,SAAS,kBAAkB,EAUnD,CAAC;AAEF,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,GAAG,kBAAkB,EAAE,CAM1F;AAED,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/categories/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,cAAc,YAAY,CAAC;AAW3B,4CAA4C;AAC5C,MAAM,CAAC,MAAM,UAAU,GAAkC;IACvD,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE;IAC5E,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE;IAC5E,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,iBAAiB,EAAE;IACzF,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE;IAChE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE;IAC1E,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE;IAC5D,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE;IACpE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE;IACzD,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE;CACpE,CAAC;AAEF,qEAAqE;AACrE,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,aAAsB;IAClE,OAAO,UAAU,CAAC,MAAM,CACtB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC;QAC3C,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,aAAa,CAAC,CAAC,CAC1D,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC","sourcesContent":["/**\n * Category registry. Each entry is selected by family so the runner only\n * executes categories relevant to the parameter set under test.\n */\n\nimport type { Category } from \"./types.js\";\nimport type { Family } from \"../sizes.js\";\n\nimport { correctness } from \"./correctness.js\";\nimport { determinism } from \"./determinism.js\";\nimport { implicitRejection } from \"./implicit-rejection.js\";\nimport { sizes } from \"./sizes.js\";\nimport { robustness } from \"./robustness.js\";\nimport { dsa } from \"./dsa.js\";\nimport { slhDsa } from \"./slh-dsa.js\";\nimport { kat } from \"./kat.js\";\nimport { timing } from \"./timing.js\";\n\nexport * from \"./types.js\";\n\n/** A named, family-scoped category. */\
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/categories/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,cAAc,YAAY,CAAC;AAW3B,4CAA4C;AAC5C,MAAM,CAAC,MAAM,UAAU,GAAkC;IACvD,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE;IAC5E,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE;IAC5E,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,iBAAiB,EAAE;IACzF,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE;IAChE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE;IAC1E,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE;IAC5D,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE;IACpE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE;IACzD,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE;CACpE,CAAC;AAEF,qEAAqE;AACrE,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,aAAsB;IAClE,OAAO,UAAU,CAAC,MAAM,CACtB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC;QAC3C,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,aAAa,CAAC,CAAC,CAC1D,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC","sourcesContent":["/**\n * Category registry. Each entry is selected by family so the runner only\n * executes categories relevant to the parameter set under test.\n */\n\nimport type { Category } from \"./types.js\";\nimport type { Family } from \"../sizes.js\";\n\nimport { correctness } from \"./correctness.js\";\nimport { determinism } from \"./determinism.js\";\nimport { implicitRejection } from \"./implicit-rejection.js\";\nimport { sizes } from \"./sizes.js\";\nimport { robustness } from \"./robustness.js\";\nimport { dsa } from \"./dsa.js\";\nimport { slhDsa } from \"./slh-dsa.js\";\nimport { kat } from \"./kat.js\";\nimport { timing } from \"./timing.js\";\n\nexport * from \"./types.js\";\n\n/** A named, family-scoped category. */\ninterface RegisteredCategory {\n name: string;\n family: Family | \"any\";\n /** Whether the category runs by default (timing is opt-in). */\n defaultOn: boolean;\n run: Category;\n}\n\n/** The full catalog, in execution order. */\nexport const CATEGORIES: readonly RegisteredCategory[] = [\n { name: \"correctness\", family: \"ml-kem\", defaultOn: true, run: correctness },\n { name: \"determinism\", family: \"ml-kem\", defaultOn: true, run: determinism },\n { name: \"implicit-rejection\", family: \"ml-kem\", defaultOn: true, run: implicitRejection },\n { name: \"sizes\", family: \"ml-kem\", defaultOn: true, run: sizes },\n { name: \"robustness\", family: \"ml-kem\", defaultOn: true, run: robustness },\n { name: \"dsa\", family: \"ml-dsa\", defaultOn: true, run: dsa },\n { name: \"slh-dsa\", family: \"slh-dsa\", defaultOn: true, run: slhDsa },\n { name: \"kat\", family: \"any\", defaultOn: true, run: kat },\n { name: \"timing\", family: \"ml-kem\", defaultOn: false, run: timing },\n];\n\n/** Categories applicable to a family (plus family-agnostic ones). */\nexport function categoriesFor(family: Family, includeTiming: boolean): RegisteredCategory[] {\n return CATEGORIES.filter(\n (c) =>\n (c.family === family || c.family === \"any\") &&\n (c.defaultOn || (c.name === \"timing\" && includeTiming)),\n );\n}\n\nexport { correctness, determinism, implicitRejection, sizes, robustness, dsa, slhDsa, kat, timing };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kat.d.ts","sourceRoot":"","sources":["../../src/categories/kat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,KAAK,QAAQ,EAOd,MAAM,YAAY,CAAC;AAKpB,eAAO,MAAM,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"kat.d.ts","sourceRoot":"","sources":["../../src/categories/kat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,KAAK,QAAQ,EAOd,MAAM,YAAY,CAAC;AAKpB,eAAO,MAAM,GAAG,EAAE,QA+FjB,CAAC"}
|
package/dist/categories/kat.js
CHANGED
|
@@ -60,12 +60,19 @@ export const kat = async (ctx) => {
|
|
|
60
60
|
return { category: "kat", status, checks, summary: `no ${param} vectors among supplied files` };
|
|
61
61
|
}
|
|
62
62
|
let okCount = 0;
|
|
63
|
+
let skipCount = 0;
|
|
63
64
|
let idx = 0;
|
|
64
65
|
for (const v of relevant) {
|
|
65
66
|
idx++;
|
|
66
67
|
try {
|
|
67
68
|
const result = await checkVector(ctx, v);
|
|
68
|
-
if (result.
|
|
69
|
+
if (result.skipped) {
|
|
70
|
+
// Unverifiable (e.g. a keygen vector with no seed) — NOT a match. Record it as
|
|
71
|
+
// a skip so it can't inflate the "matched" count into a false conformance pass.
|
|
72
|
+
skipCount++;
|
|
73
|
+
checks.push(skip(`${v.kind}[${idx}]`, result.detail));
|
|
74
|
+
}
|
|
75
|
+
else if (result.ok) {
|
|
69
76
|
okCount++;
|
|
70
77
|
// Keep the report compact: don't push a pass per vector.
|
|
71
78
|
}
|
|
@@ -77,8 +84,15 @@ export const kat = async (ctx) => {
|
|
|
77
84
|
checks.push(fail(`${v.kind}[${idx}]`, `harness error: ${err.message}`));
|
|
78
85
|
}
|
|
79
86
|
}
|
|
87
|
+
// Denominator is the number of ACTUALLY-verified vectors, excluding skips.
|
|
88
|
+
const verified = relevant.length - skipCount;
|
|
80
89
|
if (okCount > 0) {
|
|
81
|
-
checks.push(pass("kat", `${okCount}/${
|
|
90
|
+
checks.push(pass("kat", `${okCount}/${verified} ${param} vectors matched expected values`));
|
|
91
|
+
}
|
|
92
|
+
else if (skipCount > 0) {
|
|
93
|
+
// Everything relevant was unverifiable — say so explicitly rather than passing on
|
|
94
|
+
// zero comparisons.
|
|
95
|
+
checks.push(skip("kat", `all ${skipCount} ${param} vector(s) were unverifiable (no seed/coins)`));
|
|
82
96
|
}
|
|
83
97
|
const status = rollUp(checks);
|
|
84
98
|
return {
|
|
@@ -96,7 +110,7 @@ async function checkVector(ctx, v) {
|
|
|
96
110
|
switch (v.kind) {
|
|
97
111
|
case "kem-keygen": {
|
|
98
112
|
if (!v.seed)
|
|
99
|
-
return { ok: true, detail: "no seed; skipped" };
|
|
113
|
+
return { ok: false, skipped: true, detail: "no seed; skipped" };
|
|
100
114
|
const resp = await runner.send({
|
|
101
115
|
family: "ml-kem",
|
|
102
116
|
param,
|
|
@@ -117,7 +131,7 @@ async function checkVector(ctx, v) {
|
|
|
117
131
|
}
|
|
118
132
|
case "kem-encap": {
|
|
119
133
|
if (!v.coins)
|
|
120
|
-
return { ok: true, detail: "no coins; skipped" };
|
|
134
|
+
return { ok: false, skipped: true, detail: "no coins; skipped" };
|
|
121
135
|
const resp = await runner.send({
|
|
122
136
|
family: "ml-kem",
|
|
123
137
|
param,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kat.js","sourceRoot":"","sources":["../../src/categories/kat.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * KAT category — Known-Answer Tests against OFFICIAL NIST ACVP vectors.\n *\n * This category is SKIPPED unless the user supplies `--vectors <dir>` with real\n * ACVP files. Sieve never fabricates expected values; if no vectors are\n * present, every check is a `skip` with a clear message pointing at\n * vectors/README.md.\n *\n * What we check when vectors ARE present:\n * - kem-keygen: if a seed is given, deterministic keygen must reproduce the\n * expected pk/sk exactly. (Skipped if the SUT can't do seeded keygen.)\n * - kem-encap: if coins are given, deterministic encaps must reproduce ct/ss.\n * - kem-decap: decaps(sk, ct) must equal the expected ss exactly.\n * - dsa-verify: verify(pk, msg, sig) must equal the expected verdict.\n *\n * These ARE exact-value assertions — but the expected bytes come from the\n * user's NIST files, not from Sieve.\n */\n\nimport {\n type Category,\n type CategoryResult,\n type Check,\n fail,\n pass,\n rollUp,\n skip,\n} from \"./types.js\";\nimport { bytesEqual } from \"./helpers.js\";\nimport { fromB64, toB64 } from \"../protocol.js\";\nimport { loadVectors, type Vector } from \"../vectors.js\";\n\nexport const kat: Category = async (ctx): Promise<CategoryResult> => {\n if (!ctx.vectorsDir) {\n return {\n category: \"kat\",\n status: \"skip\",\n checks: [\n skip(\n \"vectors\",\n \"no --vectors <dir> supplied; Sieve ships no test vectors and will not \" +\n \"fabricate them. See vectors/README.md to obtain official NIST ACVP files.\",\n ),\n ],\n summary: \"skipped — no official vectors provided\",\n };\n }\n\n const checks: Check[] = [];\n let loaded: ReturnType<typeof loadVectors>;\n try {\n loaded = loadVectors(ctx.vectorsDir);\n } catch (err) {\n return {\n category: \"kat\",\n status: \"fail\",\n checks: [\n fail(\"load\", `could not load vectors from ${ctx.vectorsDir}: ${(err as Error).message}`),\n ],\n summary: \"vector load failed\",\n };\n }\n\n for (const note of loaded.notes.slice(0, 10)) {\n checks.push(skip(\"note\", note));\n }\n\n // Only run vectors matching the parameter set under test.\n const param = ctx.sizes.id;\n const relevant = loaded.vectors.filter((v) => v.param === param);\n if (relevant.length === 0) {\n checks.push(\n skip(\n \"applicable\",\n `loaded ${loaded.vectors.length} vector(s) from ${loaded.files.length} file(s), ` +\n `but none for ${param}`,\n ),\n );\n const status = rollUp(checks);\n return { category: \"kat\", status, checks, summary: `no ${param} vectors among supplied files` };\n }\n\n let okCount = 0;\n let idx = 0;\n for (const v of relevant) {\n idx++;\n try {\n const result = await checkVector(ctx, v);\n if (result.ok) {\n okCount++;\n // Keep the report compact: don't push a pass per vector.\n } else {\n checks.push(fail(`${v.kind}[${idx}]`, result.detail, undefined));\n }\n } catch (err) {\n checks.push(fail(`${v.kind}[${idx}]`, `harness error: ${(err as Error).message}`));\n }\n }\n\n if (okCount > 0) {\n checks.push(\n pass(\"kat\", `${okCount}/${relevant.length} ${param} vectors matched expected values`),\n );\n }\n\n const status = rollUp(checks);\n return {\n category: \"kat\",\n status,\n checks,\n summary:\n status === \"pass\"\n ? `${okCount} ${param} KAT vectors passed`\n : `${checks.filter((c) => c.status === \"fail\").length} KAT mismatch(es)`,\n };\n};\n\ninterface VectorResult {\n ok: boolean;\n detail: string;\n}\n\nasync function checkVector(\n ctx: import(\"./types.js\").CategoryContext,\n v: Vector,\n): Promise<VectorResult> {\n const { runner } = ctx;\n const param = v.param;\n\n switch (v.kind) {\n case \"kem-keygen\": {\n if (!v.seed) return { ok: true, detail: \"no seed; skipped\" };\n const resp = await runner.send({\n family: \"ml-kem\",\n param,\n op: \"keygen\",\n seed: toB64(v.seed),\n });\n if (resp.ok !== true || !(\"pk\" in resp) || !(\"sk\" in resp)) {\n return {\n ok: false,\n detail: \"seeded keygen did not return pk/sk (SUT may not support seeds)\",\n };\n }\n const pkOk = bytesEqual(fromB64(resp.pk), v.pk);\n const skOk = bytesEqual(fromB64(resp.sk), v.sk);\n return pkOk && skOk\n ? { ok: true, detail: \"pk/sk match\" }\n : { ok: false, detail: `seeded keygen mismatch (pkOk=${pkOk}, skOk=${skOk})` };\n }\n case \"kem-encap\": {\n if (!v.coins) return { ok: true, detail: \"no coins; skipped\" };\n const resp = await runner.send({\n family: \"ml-kem\",\n param,\n op: \"encaps\",\n pk: toB64(v.pk),\n coins: toB64(v.coins),\n });\n if (resp.ok !== true || !(\"ct\" in resp) || !(\"ss\" in resp)) {\n return {\n ok: false,\n detail: \"deterministic encaps did not return ct/ss (SUT may not support coins)\",\n };\n }\n const ctOk = bytesEqual(fromB64(resp.ct), v.ct);\n const ssOk = bytesEqual(fromB64(resp.ss), v.ss);\n return ctOk && ssOk\n ? { ok: true, detail: \"ct/ss match\" }\n : { ok: false, detail: `encaps mismatch (ctOk=${ctOk}, ssOk=${ssOk})` };\n }\n case \"kem-decap\": {\n const resp = await runner.send({\n family: \"ml-kem\",\n param,\n op: \"decaps\",\n sk: toB64(v.sk),\n ct: toB64(v.ct),\n });\n if (resp.ok !== true || !(\"ss\" in resp)) {\n return { ok: false, detail: \"decaps did not return ss\" };\n }\n return bytesEqual(fromB64(resp.ss), v.ss)\n ? { ok: true, detail: \"ss matches\" }\n : { ok: false, detail: \"decaps shared secret does not match expected\" };\n }\n case \"dsa-verify\": {\n const resp = await runner.send({\n family: \"ml-dsa\",\n param,\n op: \"verify\",\n pk: toB64(v.pk),\n msg: toB64(v.msg),\n sig: toB64(v.sig),\n });\n if (resp.ok !== true || !(\"valid\" in resp)) {\n return { ok: false, detail: \"verify did not return a 'valid' verdict\" };\n }\n return resp.valid === v.expected\n ? { ok: true, detail: `verdict ${resp.valid} matches expected` }\n : { ok: false, detail: `verify returned ${resp.valid}, expected ${v.expected}` };\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"kat.js","sourceRoot":"","sources":["../../src/categories/kat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAIL,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,IAAI,GACL,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAe,MAAM,eAAe,CAAC;AAEzD,MAAM,CAAC,MAAM,GAAG,GAAa,KAAK,EAAE,GAAG,EAA2B,EAAE;IAClE,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QACpB,OAAO;YACL,QAAQ,EAAE,KAAK;YACf,MAAM,EAAE,MAAM;YACd,MAAM,EAAE;gBACN,IAAI,CACF,SAAS,EACT,wEAAwE;oBACtE,2EAA2E,CAC9E;aACF;YACD,OAAO,EAAE,wCAAwC;SAClD,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,IAAI,MAAsC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,QAAQ,EAAE,KAAK;YACf,MAAM,EAAE,MAAM;YACd,MAAM,EAAE;gBACN,IAAI,CAAC,MAAM,EAAE,+BAA+B,GAAG,CAAC,UAAU,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC;aACzF;YACD,OAAO,EAAE,oBAAoB;SAC9B,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,0DAA0D;IAC1D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;IACjE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CACT,IAAI,CACF,YAAY,EACZ,UAAU,MAAM,CAAC,OAAO,CAAC,MAAM,mBAAmB,MAAM,CAAC,KAAK,CAAC,MAAM,YAAY;YAC/E,gBAAgB,KAAK,EAAE,CAC1B,CACF,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,+BAA+B,EAAE,CAAC;IAClG,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,GAAG,EAAE,CAAC;QACN,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACzC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,+EAA+E;gBAC/E,gFAAgF;gBAChF,SAAS,EAAE,CAAC;gBACZ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACxD,CAAC;iBAAM,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACrB,OAAO,EAAE,CAAC;gBACV,yDAAyD;YAC3D,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,GAAG,EAAE,kBAAmB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC;IAC7C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,OAAO,IAAI,QAAQ,IAAI,KAAK,kCAAkC,CAAC,CAAC,CAAC;IAC9F,CAAC;SAAM,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QACzB,kFAAkF;QAClF,oBAAoB;QACpB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,KAAK,EAAE,OAAO,SAAS,IAAI,KAAK,8CAA8C,CAAC,CACrF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9B,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,MAAM;QACN,MAAM;QACN,OAAO,EACL,MAAM,KAAK,MAAM;YACf,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,qBAAqB;YAC1C,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM,mBAAmB;KAC7E,CAAC;AACJ,CAAC,CAAC;AASF,KAAK,UAAU,WAAW,CACxB,GAAyC,EACzC,CAAS;IAET,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IACvB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;IAEtB,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,IAAI,CAAC,CAAC,CAAC,IAAI;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;YAC7E,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC;gBAC7B,MAAM,EAAE,QAAQ;gBAChB,KAAK;gBACL,EAAE,EAAE,QAAQ;gBACZ,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;aACpB,CAAC,CAAC;YACH,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;gBAC3D,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,MAAM,EAAE,gEAAgE;iBACzE,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAChD,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAChD,OAAO,IAAI,IAAI,IAAI;gBACjB,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE;gBACrC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gCAAgC,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;QACnF,CAAC;QACD,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,IAAI,CAAC,CAAC,CAAC,KAAK;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;YAC/E,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC;gBAC7B,MAAM,EAAE,QAAQ;gBAChB,KAAK;gBACL,EAAE,EAAE,QAAQ;gBACZ,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBACf,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;aACtB,CAAC,CAAC;YACH,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;gBAC3D,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,MAAM,EAAE,uEAAuE;iBAChF,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAChD,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAChD,OAAO,IAAI,IAAI,IAAI;gBACjB,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE;gBACrC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,yBAAyB,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;QAC5E,CAAC;QACD,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC;gBAC7B,MAAM,EAAE,QAAQ;gBAChB,KAAK;gBACL,EAAE,EAAE,QAAQ;gBACZ,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBACf,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;aAChB,CAAC,CAAC;YACH,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;gBACxC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC;YAC3D,CAAC;YACD,OAAO,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACvC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE;gBACpC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,8CAA8C,EAAE,CAAC;QAC5E,CAAC;QACD,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC;gBAC7B,MAAM,EAAE,QAAQ;gBAChB,KAAK;gBACL,EAAE,EAAE,QAAQ;gBACZ,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBACf,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;gBACjB,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;aAClB,CAAC,CAAC;YACH,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC;gBAC3C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,yCAAyC,EAAE,CAAC;YAC1E,CAAC;YACD,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,QAAQ;gBAC9B,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,IAAI,CAAC,KAAK,mBAAmB,EAAE;gBAChE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,IAAI,CAAC,KAAK,cAAc,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;QACrF,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["/**\n * KAT category — Known-Answer Tests against OFFICIAL NIST ACVP vectors.\n *\n * This category is SKIPPED unless the user supplies `--vectors <dir>` with real\n * ACVP files. Sieve never fabricates expected values; if no vectors are\n * present, every check is a `skip` with a clear message pointing at\n * vectors/README.md.\n *\n * What we check when vectors ARE present:\n * - kem-keygen: if a seed is given, deterministic keygen must reproduce the\n * expected pk/sk exactly. (Skipped if the SUT can't do seeded keygen.)\n * - kem-encap: if coins are given, deterministic encaps must reproduce ct/ss.\n * - kem-decap: decaps(sk, ct) must equal the expected ss exactly.\n * - dsa-verify: verify(pk, msg, sig) must equal the expected verdict.\n *\n * These ARE exact-value assertions — but the expected bytes come from the\n * user's NIST files, not from Sieve.\n */\n\nimport {\n type Category,\n type CategoryResult,\n type Check,\n fail,\n pass,\n rollUp,\n skip,\n} from \"./types.js\";\nimport { bytesEqual } from \"./helpers.js\";\nimport { fromB64, toB64 } from \"../protocol.js\";\nimport { loadVectors, type Vector } from \"../vectors.js\";\n\nexport const kat: Category = async (ctx): Promise<CategoryResult> => {\n if (!ctx.vectorsDir) {\n return {\n category: \"kat\",\n status: \"skip\",\n checks: [\n skip(\n \"vectors\",\n \"no --vectors <dir> supplied; Sieve ships no test vectors and will not \" +\n \"fabricate them. See vectors/README.md to obtain official NIST ACVP files.\",\n ),\n ],\n summary: \"skipped — no official vectors provided\",\n };\n }\n\n const checks: Check[] = [];\n let loaded: ReturnType<typeof loadVectors>;\n try {\n loaded = loadVectors(ctx.vectorsDir);\n } catch (err) {\n return {\n category: \"kat\",\n status: \"fail\",\n checks: [\n fail(\"load\", `could not load vectors from ${ctx.vectorsDir}: ${(err as Error).message}`),\n ],\n summary: \"vector load failed\",\n };\n }\n\n for (const note of loaded.notes.slice(0, 10)) {\n checks.push(skip(\"note\", note));\n }\n\n // Only run vectors matching the parameter set under test.\n const param = ctx.sizes.id;\n const relevant = loaded.vectors.filter((v) => v.param === param);\n if (relevant.length === 0) {\n checks.push(\n skip(\n \"applicable\",\n `loaded ${loaded.vectors.length} vector(s) from ${loaded.files.length} file(s), ` +\n `but none for ${param}`,\n ),\n );\n const status = rollUp(checks);\n return { category: \"kat\", status, checks, summary: `no ${param} vectors among supplied files` };\n }\n\n let okCount = 0;\n let skipCount = 0;\n let idx = 0;\n for (const v of relevant) {\n idx++;\n try {\n const result = await checkVector(ctx, v);\n if (result.skipped) {\n // Unverifiable (e.g. a keygen vector with no seed) — NOT a match. Record it as\n // a skip so it can't inflate the \"matched\" count into a false conformance pass.\n skipCount++;\n checks.push(skip(`${v.kind}[${idx}]`, result.detail));\n } else if (result.ok) {\n okCount++;\n // Keep the report compact: don't push a pass per vector.\n } else {\n checks.push(fail(`${v.kind}[${idx}]`, result.detail, undefined));\n }\n } catch (err) {\n checks.push(fail(`${v.kind}[${idx}]`, `harness error: ${(err as Error).message}`));\n }\n }\n\n // Denominator is the number of ACTUALLY-verified vectors, excluding skips.\n const verified = relevant.length - skipCount;\n if (okCount > 0) {\n checks.push(pass(\"kat\", `${okCount}/${verified} ${param} vectors matched expected values`));\n } else if (skipCount > 0) {\n // Everything relevant was unverifiable — say so explicitly rather than passing on\n // zero comparisons.\n checks.push(\n skip(\"kat\", `all ${skipCount} ${param} vector(s) were unverifiable (no seed/coins)`),\n );\n }\n\n const status = rollUp(checks);\n return {\n category: \"kat\",\n status,\n checks,\n summary:\n status === \"pass\"\n ? `${okCount} ${param} KAT vectors passed`\n : `${checks.filter((c) => c.status === \"fail\").length} KAT mismatch(es)`,\n };\n};\n\ninterface VectorResult {\n ok: boolean;\n /** True when the vector could not be verified (no seed/coins) — NOT a match. */\n skipped?: boolean;\n detail: string;\n}\n\nasync function checkVector(\n ctx: import(\"./types.js\").CategoryContext,\n v: Vector,\n): Promise<VectorResult> {\n const { runner } = ctx;\n const param = v.param;\n\n switch (v.kind) {\n case \"kem-keygen\": {\n if (!v.seed) return { ok: false, skipped: true, detail: \"no seed; skipped\" };\n const resp = await runner.send({\n family: \"ml-kem\",\n param,\n op: \"keygen\",\n seed: toB64(v.seed),\n });\n if (resp.ok !== true || !(\"pk\" in resp) || !(\"sk\" in resp)) {\n return {\n ok: false,\n detail: \"seeded keygen did not return pk/sk (SUT may not support seeds)\",\n };\n }\n const pkOk = bytesEqual(fromB64(resp.pk), v.pk);\n const skOk = bytesEqual(fromB64(resp.sk), v.sk);\n return pkOk && skOk\n ? { ok: true, detail: \"pk/sk match\" }\n : { ok: false, detail: `seeded keygen mismatch (pkOk=${pkOk}, skOk=${skOk})` };\n }\n case \"kem-encap\": {\n if (!v.coins) return { ok: false, skipped: true, detail: \"no coins; skipped\" };\n const resp = await runner.send({\n family: \"ml-kem\",\n param,\n op: \"encaps\",\n pk: toB64(v.pk),\n coins: toB64(v.coins),\n });\n if (resp.ok !== true || !(\"ct\" in resp) || !(\"ss\" in resp)) {\n return {\n ok: false,\n detail: \"deterministic encaps did not return ct/ss (SUT may not support coins)\",\n };\n }\n const ctOk = bytesEqual(fromB64(resp.ct), v.ct);\n const ssOk = bytesEqual(fromB64(resp.ss), v.ss);\n return ctOk && ssOk\n ? { ok: true, detail: \"ct/ss match\" }\n : { ok: false, detail: `encaps mismatch (ctOk=${ctOk}, ssOk=${ssOk})` };\n }\n case \"kem-decap\": {\n const resp = await runner.send({\n family: \"ml-kem\",\n param,\n op: \"decaps\",\n sk: toB64(v.sk),\n ct: toB64(v.ct),\n });\n if (resp.ok !== true || !(\"ss\" in resp)) {\n return { ok: false, detail: \"decaps did not return ss\" };\n }\n return bytesEqual(fromB64(resp.ss), v.ss)\n ? { ok: true, detail: \"ss matches\" }\n : { ok: false, detail: \"decaps shared secret does not match expected\" };\n }\n case \"dsa-verify\": {\n const resp = await runner.send({\n family: \"ml-dsa\",\n param,\n op: \"verify\",\n pk: toB64(v.pk),\n msg: toB64(v.msg),\n sig: toB64(v.sig),\n });\n if (resp.ok !== true || !(\"valid\" in resp)) {\n return { ok: false, detail: \"verify did not return a 'valid' verdict\" };\n }\n return resp.valid === v.expected\n ? { ok: true, detail: `verdict ${resp.valid} matches expected` }\n : { ok: false, detail: `verify returned ${resp.valid}, expected ${v.expected}` };\n }\n }\n}\n"]}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { Family, ParamSet } from "./sizes.js";
|
|
|
14
14
|
/** Protocol version. Bumped on any breaking wire change. */
|
|
15
15
|
export declare const PROTOCOL_VERSION: 1;
|
|
16
16
|
/** Operation names, shared across families where the semantics overlap. */
|
|
17
|
-
|
|
17
|
+
type Op = "keygen" | "encaps" | "decaps" | "sign" | "verify";
|
|
18
18
|
/** Families that support the signature operations (sign / verify). */
|
|
19
19
|
export type SignatureFamily = "ml-dsa" | "slh-dsa";
|
|
20
20
|
/** Fields common to every request. */
|
|
@@ -29,13 +29,13 @@ interface RequestBase {
|
|
|
29
29
|
op: Op;
|
|
30
30
|
}
|
|
31
31
|
/** ML-KEM / ML-DSA key generation. `seed` (base64) makes it deterministic. */
|
|
32
|
-
|
|
32
|
+
interface KeygenRequest extends RequestBase {
|
|
33
33
|
op: "keygen";
|
|
34
34
|
/** Optional base64 seed for deterministic keygen (impl-defined length). */
|
|
35
35
|
seed?: string;
|
|
36
36
|
}
|
|
37
37
|
/** ML-KEM encapsulation against a public key. */
|
|
38
|
-
|
|
38
|
+
interface EncapsRequest extends RequestBase {
|
|
39
39
|
family: "ml-kem";
|
|
40
40
|
op: "encaps";
|
|
41
41
|
/** Base64 public (encapsulation) key. */
|
|
@@ -44,7 +44,7 @@ export interface EncapsRequest extends RequestBase {
|
|
|
44
44
|
coins?: string;
|
|
45
45
|
}
|
|
46
46
|
/** ML-KEM decapsulation of a ciphertext with a secret key. */
|
|
47
|
-
|
|
47
|
+
interface DecapsRequest extends RequestBase {
|
|
48
48
|
family: "ml-kem";
|
|
49
49
|
op: "decaps";
|
|
50
50
|
/** Base64 secret (decapsulation) key. */
|
|
@@ -53,7 +53,7 @@ export interface DecapsRequest extends RequestBase {
|
|
|
53
53
|
ct: string;
|
|
54
54
|
}
|
|
55
55
|
/** ML-DSA / SLH-DSA signature generation. */
|
|
56
|
-
|
|
56
|
+
interface SignRequest extends RequestBase {
|
|
57
57
|
family: SignatureFamily;
|
|
58
58
|
op: "sign";
|
|
59
59
|
/** Base64 secret (signing) key. */
|
|
@@ -62,7 +62,7 @@ export interface SignRequest extends RequestBase {
|
|
|
62
62
|
msg: string;
|
|
63
63
|
}
|
|
64
64
|
/** ML-DSA / SLH-DSA signature verification. */
|
|
65
|
-
|
|
65
|
+
interface VerifyRequest extends RequestBase {
|
|
66
66
|
family: SignatureFamily;
|
|
67
67
|
op: "verify";
|
|
68
68
|
/** Base64 public (verification) key. */
|
|
@@ -84,7 +84,7 @@ export type RequestInput = DistributiveOmit<Request, "id"> & {
|
|
|
84
84
|
id?: number;
|
|
85
85
|
};
|
|
86
86
|
/** Successful keygen result. */
|
|
87
|
-
|
|
87
|
+
interface KeygenResult {
|
|
88
88
|
id: number;
|
|
89
89
|
ok: true;
|
|
90
90
|
/** Base64 public key. */
|
|
@@ -93,7 +93,7 @@ export interface KeygenResult {
|
|
|
93
93
|
sk: string;
|
|
94
94
|
}
|
|
95
95
|
/** Successful encapsulation result. */
|
|
96
|
-
|
|
96
|
+
interface EncapsResult {
|
|
97
97
|
id: number;
|
|
98
98
|
ok: true;
|
|
99
99
|
/** Base64 ciphertext. */
|
|
@@ -102,14 +102,14 @@ export interface EncapsResult {
|
|
|
102
102
|
ss: string;
|
|
103
103
|
}
|
|
104
104
|
/** Successful decapsulation result. */
|
|
105
|
-
|
|
105
|
+
interface DecapsResult {
|
|
106
106
|
id: number;
|
|
107
107
|
ok: true;
|
|
108
108
|
/** Base64 shared secret. */
|
|
109
109
|
ss: string;
|
|
110
110
|
}
|
|
111
111
|
/** Successful signing result. */
|
|
112
|
-
|
|
112
|
+
interface SignResult {
|
|
113
113
|
id: number;
|
|
114
114
|
ok: true;
|
|
115
115
|
/** Base64 signature. */
|
|
@@ -128,7 +128,7 @@ export interface VerifyResult {
|
|
|
128
128
|
* for example when given a wrong-length key. Sieve treats a clean `error`
|
|
129
129
|
* response as a *correct* rejection in the size/robustness categories.
|
|
130
130
|
*/
|
|
131
|
-
|
|
131
|
+
interface ErrorResult {
|
|
132
132
|
id: number;
|
|
133
133
|
ok: false;
|
|
134
134
|
/** Short machine-readable code, e.g. "invalid-length", "unsupported". */
|
|
@@ -138,8 +138,6 @@ export interface ErrorResult {
|
|
|
138
138
|
}
|
|
139
139
|
/** Any response the SUT may emit. */
|
|
140
140
|
export type Response = KeygenResult | EncapsResult | DecapsResult | SignResult | VerifyResult | ErrorResult;
|
|
141
|
-
/** A successful (non-error) response. */
|
|
142
|
-
export type SuccessResponse = Exclude<Response, ErrorResult>;
|
|
143
141
|
/** Serialize a request to a single NDJSON line (including the trailing "\n"). */
|
|
144
142
|
export declare function encodeRequest(req: Request): string;
|
|
145
143
|
/** Raised when a line from the SUT cannot be parsed into a valid Response. */
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnD,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,EAAG,CAAU,CAAC;AAM3C,2EAA2E;AAC3E,
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Sieve <-> SUT wire protocol.\n *\n * Sieve drives a system-under-test (SUT) — any ML-KEM / ML-DSA implementation\n * the user provides — by spawning it as a child process and exchanging\n * newline-delimited JSON (NDJSON) over stdin/stdout. One request per line, one\n * response per line. All byte fields are base64-encoded strings.\n *\n * This module defines the request/response TypeScript types and the\n * (de)serialization + validation logic. It performs NO cryptography. See\n * PROTOCOL.md for the human-readable specification.\n */\n\nimport type { Family, ParamSet } from \"./sizes.js\";\n\n/** Protocol version. Bumped on any breaking wire change. */\nexport const PROTOCOL_VERSION = 1 as const;\n\n// ---------------------------------------------------------------------------\n// Request types\n// ---------------------------------------------------------------------------\n\n/** Operation names, shared across families where the semantics overlap. */\nexport type Op = \"keygen\" | \"encaps\" | \"decaps\" | \"sign\" | \"verify\";\n\n/** Families that support the signature operations (sign / verify). */\nexport type SignatureFamily = \"ml-dsa\" | \"slh-dsa\";\n\n/** Fields common to every request. */\ninterface RequestBase {\n /** Correlation id; the SUT MUST echo it back on the matching response. */\n id: number;\n /** Algorithm family this request targets. */\n family: Family;\n /** Parameter-set identifier, e.g. \"ml-kem-768\". */\n param: ParamSet;\n /** Operation to perform. */\n op: Op;\n}\n\n/** ML-KEM / ML-DSA key generation. `seed` (base64) makes it deterministic. */\nexport interface KeygenRequest extends RequestBase {\n op: \"keygen\";\n /** Optional base64 seed for deterministic keygen (impl-defined length). */\n seed?: string;\n}\n\n/** ML-KEM encapsulation against a public key. */\nexport interface EncapsRequest extends RequestBase {\n family: \"ml-kem\";\n op: \"encaps\";\n /** Base64 public (encapsulation) key. */\n pk: string;\n /** Optional base64 coins/randomness for deterministic encapsulation. */\n coins?: string;\n}\n\n/** ML-KEM decapsulation of a ciphertext with a secret key. */\nexport interface DecapsRequest extends RequestBase {\n family: \"ml-kem\";\n op: \"decaps\";\n /** Base64 secret (decapsulation) key. */\n sk: string;\n /** Base64 ciphertext. */\n ct: string;\n}\n\n/** ML-DSA / SLH-DSA signature generation. */\nexport interface SignRequest extends RequestBase {\n family: SignatureFamily;\n op: \"sign\";\n /** Base64 secret (signing) key. */\n sk: string;\n /** Base64 message to sign. */\n msg: string;\n}\n\n/** ML-DSA / SLH-DSA signature verification. */\nexport interface VerifyRequest extends RequestBase {\n family: SignatureFamily;\n op: \"verify\";\n /** Base64 public (verification) key. */\n pk: string;\n /** Base64 message. */\n msg: string;\n /** Base64 signature. */\n sig: string;\n}\n\n/** Any request Sieve may send. */\nexport type Request = KeygenRequest | EncapsRequest | DecapsRequest | SignRequest | VerifyRequest;\n\n/**\n * Omit that distributes over a union, so each variant keeps its own fields\n * (plain `Omit<Request, \"id\">` would collapse to only the common keys).\n */\ntype DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;\n\n/** A request as handed to the runner — the `id` is assigned by the runner. */\nexport type RequestInput = DistributiveOmit<Request, \"id\"> & { id?: number };\n\n// ---------------------------------------------------------------------------\n// Response types\n// ---------------------------------------------------------------------------\n\n/** Successful keygen result. */\nexport interface KeygenResult {\n id: number;\n ok: true;\n /** Base64 public key. */\n pk: string;\n /** Base64 secret key. */\n sk: string;\n}\n\n/** Successful encapsulation result. */\nexport interface EncapsResult {\n id: number;\n ok: true;\n /** Base64 ciphertext. */\n ct: string;\n /** Base64 shared secret. */\n ss: string;\n}\n\n/** Successful decapsulation result. */\nexport interface DecapsResult {\n id: number;\n ok: true;\n /** Base64 shared secret. */\n ss: string;\n}\n\n/** Successful signing result. */\nexport interface SignResult {\n id: number;\n ok: true;\n /** Base64 signature. */\n sig: string;\n}\n\n/** Successful verification result. `valid` is the verification verdict. */\nexport interface VerifyResult {\n id: number;\n ok: true;\n /** Whether the signature verified against (pk, msg). */\n valid: boolean;\n}\n\n/**\n * A defined, well-formed error. The SUT MUST return this (not crash, not hang,\n * not silently produce garbage) when it cannot or will not honor a request —\n * for example when given a wrong-length key. Sieve treats a clean `error`\n * response as a *correct* rejection in the size/robustness categories.\n */\nexport interface ErrorResult {\n id: number;\n ok: false;\n /** Short machine-readable code, e.g. \"invalid-length\", \"unsupported\". */\n code: string;\n /** Human-readable detail. */\n message: string;\n}\n\n/** Any response the SUT may emit. */\nexport type Response =\n | KeygenResult\n | EncapsResult\n | DecapsResult\n | SignResult\n | VerifyResult\n | ErrorResult;\n\n/** A successful (non-error) response. */\nexport type SuccessResponse = Exclude<Response, ErrorResult>;\n\n// ---------------------------------------------------------------------------\n// Serialization\n// ---------------------------------------------------------------------------\n\n/** Serialize a request to a single NDJSON line (including the trailing \"\\n\"). */\nexport function encodeRequest(req: Request): string {\n return JSON.stringify(req) + \"\\n\";\n}\n\n/** Raised when a line from the SUT cannot be parsed into a valid Response. */\nexport class ProtocolError extends Error {\n /** The offending raw line, truncated for safety. */\n readonly raw: string;\n constructor(message: string, raw: string) {\n super(message);\n this.name = \"ProtocolError\";\n this.raw = raw.length > 512 ? raw.slice(0, 512) + \"…\" : raw;\n }\n}\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction isStr(v: unknown): v is string {\n return typeof v === \"string\";\n}\n\n/**\n * Parse one NDJSON line from the SUT into a validated {@link Response}.\n *\n * Validates structural shape only (presence and types of fields); it does NOT\n * validate cryptographic content or byte lengths — that is the categories'\n * job. Throws {@link ProtocolError} on malformed input.\n */\nexport function decodeResponse(line: string): Response {\n const trimmed = line.trim();\n if (trimmed.length === 0) {\n throw new ProtocolError(\"empty line\", line);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch (err) {\n throw new ProtocolError(`not valid JSON: ${(err as Error).message}`, line);\n }\n\n if (!isObject(parsed)) {\n throw new ProtocolError(\"response is not a JSON object\", line);\n }\n\n const id = parsed[\"id\"];\n if (typeof id !== \"number\" || !Number.isInteger(id)) {\n throw new ProtocolError(\"missing/invalid integer 'id'\", line);\n }\n\n const ok = parsed[\"ok\"];\n if (typeof ok !== \"boolean\") {\n throw new ProtocolError(\"missing/invalid boolean 'ok'\", line);\n }\n\n if (ok === false) {\n const code = parsed[\"code\"];\n const message = parsed[\"message\"];\n if (!isStr(code) || !isStr(message)) {\n throw new ProtocolError(\"error response must have string 'code' and 'message'\", line);\n }\n return { id, ok: false, code, message };\n }\n\n // ok === true: discriminate by which payload fields are present.\n if (isStr(parsed[\"pk\"]) && isStr(parsed[\"sk\"])) {\n return { id, ok: true, pk: parsed[\"pk\"], sk: parsed[\"sk\"] };\n }\n if (isStr(parsed[\"ct\"]) && isStr(parsed[\"ss\"])) {\n return { id, ok: true, ct: parsed[\"ct\"], ss: parsed[\"ss\"] };\n }\n if (isStr(parsed[\"ss\"])) {\n return { id, ok: true, ss: parsed[\"ss\"] };\n }\n if (isStr(parsed[\"sig\"])) {\n return { id, ok: true, sig: parsed[\"sig\"] };\n }\n if (typeof parsed[\"valid\"] === \"boolean\") {\n return { id, ok: true, valid: parsed[\"valid\"] };\n }\n\n throw new ProtocolError(\n \"ok response has no recognizable payload \" + \"(expected pk+sk, ct+ss, ss, sig, or valid)\",\n line,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Base64 helpers (Node built-in Buffer — no external dependency)\n// ---------------------------------------------------------------------------\n\n/** Encode raw bytes to a base64 string. */\nexport function toB64(bytes: Uint8Array): string {\n return Buffer.from(bytes).toString(\"base64\");\n}\n\n/**\n * Decode a base64 string to bytes.\n *\n * @throws {ProtocolError} if the input is not valid base64 (i.e. re-encoding\n * the decoded bytes does not reproduce the canonical form).\n */\nexport function fromB64(b64: string): Uint8Array {\n const buf = Buffer.from(b64, \"base64\");\n // Buffer.from is lenient; sanity-check by re-encoding the canonical form.\n if (buf.toString(\"base64\").replace(/=+$/, \"\") !== b64.replace(/\\s/g, \"\").replace(/=+$/, \"\")) {\n throw new ProtocolError(\"invalid base64\", b64);\n }\n return new Uint8Array(buf);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Sieve <-> SUT wire protocol.\n *\n * Sieve drives a system-under-test (SUT) — any ML-KEM / ML-DSA implementation\n * the user provides — by spawning it as a child process and exchanging\n * newline-delimited JSON (NDJSON) over stdin/stdout. One request per line, one\n * response per line. All byte fields are base64-encoded strings.\n *\n * This module defines the request/response TypeScript types and the\n * (de)serialization + validation logic. It performs NO cryptography. See\n * PROTOCOL.md for the human-readable specification.\n */\n\nimport type { Family, ParamSet } from \"./sizes.js\";\n\n/** Protocol version. Bumped on any breaking wire change. */\nexport const PROTOCOL_VERSION = 1 as const;\n\n// ---------------------------------------------------------------------------\n// Request types\n// ---------------------------------------------------------------------------\n\n/** Operation names, shared across families where the semantics overlap. */\ntype Op = \"keygen\" | \"encaps\" | \"decaps\" | \"sign\" | \"verify\";\n\n/** Families that support the signature operations (sign / verify). */\nexport type SignatureFamily = \"ml-dsa\" | \"slh-dsa\";\n\n/** Fields common to every request. */\ninterface RequestBase {\n /** Correlation id; the SUT MUST echo it back on the matching response. */\n id: number;\n /** Algorithm family this request targets. */\n family: Family;\n /** Parameter-set identifier, e.g. \"ml-kem-768\". */\n param: ParamSet;\n /** Operation to perform. */\n op: Op;\n}\n\n/** ML-KEM / ML-DSA key generation. `seed` (base64) makes it deterministic. */\ninterface KeygenRequest extends RequestBase {\n op: \"keygen\";\n /** Optional base64 seed for deterministic keygen (impl-defined length). */\n seed?: string;\n}\n\n/** ML-KEM encapsulation against a public key. */\ninterface EncapsRequest extends RequestBase {\n family: \"ml-kem\";\n op: \"encaps\";\n /** Base64 public (encapsulation) key. */\n pk: string;\n /** Optional base64 coins/randomness for deterministic encapsulation. */\n coins?: string;\n}\n\n/** ML-KEM decapsulation of a ciphertext with a secret key. */\ninterface DecapsRequest extends RequestBase {\n family: \"ml-kem\";\n op: \"decaps\";\n /** Base64 secret (decapsulation) key. */\n sk: string;\n /** Base64 ciphertext. */\n ct: string;\n}\n\n/** ML-DSA / SLH-DSA signature generation. */\ninterface SignRequest extends RequestBase {\n family: SignatureFamily;\n op: \"sign\";\n /** Base64 secret (signing) key. */\n sk: string;\n /** Base64 message to sign. */\n msg: string;\n}\n\n/** ML-DSA / SLH-DSA signature verification. */\ninterface VerifyRequest extends RequestBase {\n family: SignatureFamily;\n op: \"verify\";\n /** Base64 public (verification) key. */\n pk: string;\n /** Base64 message. */\n msg: string;\n /** Base64 signature. */\n sig: string;\n}\n\n/** Any request Sieve may send. */\nexport type Request = KeygenRequest | EncapsRequest | DecapsRequest | SignRequest | VerifyRequest;\n\n/**\n * Omit that distributes over a union, so each variant keeps its own fields\n * (plain `Omit<Request, \"id\">` would collapse to only the common keys).\n */\ntype DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;\n\n/** A request as handed to the runner — the `id` is assigned by the runner. */\nexport type RequestInput = DistributiveOmit<Request, \"id\"> & { id?: number };\n\n// ---------------------------------------------------------------------------\n// Response types\n// ---------------------------------------------------------------------------\n\n/** Successful keygen result. */\ninterface KeygenResult {\n id: number;\n ok: true;\n /** Base64 public key. */\n pk: string;\n /** Base64 secret key. */\n sk: string;\n}\n\n/** Successful encapsulation result. */\ninterface EncapsResult {\n id: number;\n ok: true;\n /** Base64 ciphertext. */\n ct: string;\n /** Base64 shared secret. */\n ss: string;\n}\n\n/** Successful decapsulation result. */\ninterface DecapsResult {\n id: number;\n ok: true;\n /** Base64 shared secret. */\n ss: string;\n}\n\n/** Successful signing result. */\ninterface SignResult {\n id: number;\n ok: true;\n /** Base64 signature. */\n sig: string;\n}\n\n/** Successful verification result. `valid` is the verification verdict. */\nexport interface VerifyResult {\n id: number;\n ok: true;\n /** Whether the signature verified against (pk, msg). */\n valid: boolean;\n}\n\n/**\n * A defined, well-formed error. The SUT MUST return this (not crash, not hang,\n * not silently produce garbage) when it cannot or will not honor a request —\n * for example when given a wrong-length key. Sieve treats a clean `error`\n * response as a *correct* rejection in the size/robustness categories.\n */\ninterface ErrorResult {\n id: number;\n ok: false;\n /** Short machine-readable code, e.g. \"invalid-length\", \"unsupported\". */\n code: string;\n /** Human-readable detail. */\n message: string;\n}\n\n/** Any response the SUT may emit. */\nexport type Response =\n | KeygenResult\n | EncapsResult\n | DecapsResult\n | SignResult\n | VerifyResult\n | ErrorResult;\n\n// ---------------------------------------------------------------------------\n// Serialization\n// ---------------------------------------------------------------------------\n\n/** Serialize a request to a single NDJSON line (including the trailing \"\\n\"). */\nexport function encodeRequest(req: Request): string {\n return JSON.stringify(req) + \"\\n\";\n}\n\n/** Raised when a line from the SUT cannot be parsed into a valid Response. */\nexport class ProtocolError extends Error {\n /** The offending raw line, truncated for safety. */\n readonly raw: string;\n constructor(message: string, raw: string) {\n super(message);\n this.name = \"ProtocolError\";\n this.raw = raw.length > 512 ? raw.slice(0, 512) + \"…\" : raw;\n }\n}\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction isStr(v: unknown): v is string {\n return typeof v === \"string\";\n}\n\n/**\n * Parse one NDJSON line from the SUT into a validated {@link Response}.\n *\n * Validates structural shape only (presence and types of fields); it does NOT\n * validate cryptographic content or byte lengths — that is the categories'\n * job. Throws {@link ProtocolError} on malformed input.\n */\nexport function decodeResponse(line: string): Response {\n const trimmed = line.trim();\n if (trimmed.length === 0) {\n throw new ProtocolError(\"empty line\", line);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch (err) {\n throw new ProtocolError(`not valid JSON: ${(err as Error).message}`, line);\n }\n\n if (!isObject(parsed)) {\n throw new ProtocolError(\"response is not a JSON object\", line);\n }\n\n const id = parsed[\"id\"];\n if (typeof id !== \"number\" || !Number.isInteger(id)) {\n throw new ProtocolError(\"missing/invalid integer 'id'\", line);\n }\n\n const ok = parsed[\"ok\"];\n if (typeof ok !== \"boolean\") {\n throw new ProtocolError(\"missing/invalid boolean 'ok'\", line);\n }\n\n if (ok === false) {\n const code = parsed[\"code\"];\n const message = parsed[\"message\"];\n if (!isStr(code) || !isStr(message)) {\n throw new ProtocolError(\"error response must have string 'code' and 'message'\", line);\n }\n return { id, ok: false, code, message };\n }\n\n // ok === true: discriminate by which payload fields are present.\n if (isStr(parsed[\"pk\"]) && isStr(parsed[\"sk\"])) {\n return { id, ok: true, pk: parsed[\"pk\"], sk: parsed[\"sk\"] };\n }\n if (isStr(parsed[\"ct\"]) && isStr(parsed[\"ss\"])) {\n return { id, ok: true, ct: parsed[\"ct\"], ss: parsed[\"ss\"] };\n }\n if (isStr(parsed[\"ss\"])) {\n return { id, ok: true, ss: parsed[\"ss\"] };\n }\n if (isStr(parsed[\"sig\"])) {\n return { id, ok: true, sig: parsed[\"sig\"] };\n }\n if (typeof parsed[\"valid\"] === \"boolean\") {\n return { id, ok: true, valid: parsed[\"valid\"] };\n }\n\n throw new ProtocolError(\n \"ok response has no recognizable payload \" + \"(expected pk+sk, ct+ss, ss, sig, or valid)\",\n line,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Base64 helpers (Node built-in Buffer — no external dependency)\n// ---------------------------------------------------------------------------\n\n/** Encode raw bytes to a base64 string. */\nexport function toB64(bytes: Uint8Array): string {\n return Buffer.from(bytes).toString(\"base64\");\n}\n\n/**\n * Decode a base64 string to bytes.\n *\n * @throws {ProtocolError} if the input is not valid base64 (i.e. re-encoding\n * the decoded bytes does not reproduce the canonical form).\n */\nexport function fromB64(b64: string): Uint8Array {\n const buf = Buffer.from(b64, \"base64\");\n // Buffer.from is lenient; sanity-check by re-encoding the canonical form.\n if (buf.toString(\"base64\").replace(/=+$/, \"\") !== b64.replace(/\\s/g, \"\").replace(/=+$/, \"\")) {\n throw new ProtocolError(\"invalid base64\", b64);\n }\n return new Uint8Array(buf);\n}\n"]}
|
package/dist/vectors.d.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import type { ParamSet } from "./sizes.js";
|
|
17
17
|
/** A normalized ML-KEM keygen vector: seed -> (pk, sk). */
|
|
18
|
-
|
|
18
|
+
interface KemKeygenVector {
|
|
19
19
|
kind: "kem-keygen";
|
|
20
20
|
param: ParamSet;
|
|
21
21
|
/** Concatenated d||z seed (hex-decoded). */
|
|
@@ -24,7 +24,7 @@ export interface KemKeygenVector {
|
|
|
24
24
|
sk: Uint8Array;
|
|
25
25
|
}
|
|
26
26
|
/** A normalized ML-KEM encapsulation vector: (pk, coins) -> (ct, ss). */
|
|
27
|
-
|
|
27
|
+
interface KemEncapVector {
|
|
28
28
|
kind: "kem-encap";
|
|
29
29
|
param: ParamSet;
|
|
30
30
|
pk: Uint8Array;
|
|
@@ -34,7 +34,7 @@ export interface KemEncapVector {
|
|
|
34
34
|
ss: Uint8Array;
|
|
35
35
|
}
|
|
36
36
|
/** A normalized ML-KEM decapsulation vector: (sk, ct) -> ss. */
|
|
37
|
-
|
|
37
|
+
interface KemDecapVector {
|
|
38
38
|
kind: "kem-decap";
|
|
39
39
|
param: ParamSet;
|
|
40
40
|
sk: Uint8Array;
|
|
@@ -42,7 +42,7 @@ export interface KemDecapVector {
|
|
|
42
42
|
ss: Uint8Array;
|
|
43
43
|
}
|
|
44
44
|
/** A normalized ML-DSA signature-verification vector: (pk, msg, sig) -> ok. */
|
|
45
|
-
|
|
45
|
+
interface DsaVerifyVector {
|
|
46
46
|
kind: "dsa-verify";
|
|
47
47
|
param: ParamSet;
|
|
48
48
|
pk: Uint8Array;
|
|
@@ -84,4 +84,5 @@ export interface VectorSet {
|
|
|
84
84
|
provenanceDeclared: boolean;
|
|
85
85
|
}
|
|
86
86
|
export declare function loadVectors(dir: string): VectorSet;
|
|
87
|
+
export {};
|
|
87
88
|
//# sourceMappingURL=vectors.d.ts.map
|
package/dist/vectors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vectors.d.ts","sourceRoot":"","sources":["../src/vectors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,OAAO,KAAK,EAAU,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnD,2DAA2D;AAC3D,
|
|
1
|
+
{"version":3,"file":"vectors.d.ts","sourceRoot":"","sources":["../src/vectors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,OAAO,KAAK,EAAU,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnD,2DAA2D;AAC3D,UAAU,eAAe;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,QAAQ,CAAC;IAChB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,EAAE,EAAE,UAAU,CAAC;IACf,EAAE,EAAE,UAAU,CAAC;CAChB;AAED,yEAAyE;AACzE,UAAU,cAAc;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;IAChB,EAAE,EAAE,UAAU,CAAC;IACf,+DAA+D;IAC/D,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,EAAE,EAAE,UAAU,CAAC;IACf,EAAE,EAAE,UAAU,CAAC;CAChB;AAED,gEAAgE;AAChE,UAAU,cAAc;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;IAChB,EAAE,EAAE,UAAU,CAAC;IACf,EAAE,EAAE,UAAU,CAAC;IACf,EAAE,EAAE,UAAU,CAAC;CAChB;AAED,+EAA+E;AAC/E,UAAU,eAAe;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,QAAQ,CAAC;IAChB,EAAE,EAAE,UAAU,CAAC;IACf,GAAG,EAAE,UAAU,CAAC;IAChB,GAAG,EAAE,UAAU,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,6BAA6B;AAC7B,MAAM,MAAM,MAAM,GAAG,eAAe,GAAG,cAAc,GAAG,cAAc,GAAG,eAAe,CAAC;AAEzF;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,uCAAuC;IACvC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,8CAA8C;AAC9C,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yDAAyD;IACzD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yEAAyE;IACzE,UAAU,EAAE,oBAAoB,EAAE,CAAC;IACnC,4EAA4E;IAC5E,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AA6JD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAsElD"}
|
package/dist/vectors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vectors.js","sourceRoot":"","sources":["../src/vectors.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Loader for OFFICIAL NIST ACVP Known-Answer-Test (KAT) vector files.\n *\n * HONESTY NOTE: Sieve ships NO cryptographic test vectors. It does not and must\n * not fabricate expected pk/sk/ct/ss/sig bytes. This module only PARSES vector\n * files that the user downloads from NIST and points Sieve at via --vectors.\n * See vectors/README.md for where to obtain them and the file format.\n *\n * Supported input: the NIST ACVP-server JSON format for ML-KEM (keyGen,\n * encapDecap) and ML-DSA (keyGen, sigGen, sigVer). The ACVP JSON encodes bytes\n * as hex strings. We normalize the fields we need into a flat list of typed\n * test cases. Anything we don't recognize is ignored (not invented).\n *\n * Uses only node:fs. No cryptography.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { isParamSet } from \"./sizes.js\";\nimport type { Family, ParamSet } from \"./sizes.js\";\n\n/** A normalized ML-KEM keygen vector: seed -> (pk, sk). */\nexport interface KemKeygenVector {\n kind: \"kem-keygen\";\n param: ParamSet;\n /** Concatenated d||z seed (hex-decoded). */\n seed?: Uint8Array;\n pk: Uint8Array;\n sk: Uint8Array;\n}\n\n/** A normalized ML-KEM encapsulation vector: (pk, coins) -> (ct, ss). */\nexport interface KemEncapVector {\n kind: \"kem-encap\";\n param: ParamSet;\n pk: Uint8Array;\n /** Encapsulation coins/message m (hex-decoded), if present. */\n coins?: Uint8Array;\n ct: Uint8Array;\n ss: Uint8Array;\n}\n\n/** A normalized ML-KEM decapsulation vector: (sk, ct) -> ss. */\nexport interface KemDecapVector {\n kind: \"kem-decap\";\n param: ParamSet;\n sk: Uint8Array;\n ct: Uint8Array;\n ss: Uint8Array;\n}\n\n/** A normalized ML-DSA signature-verification vector: (pk, msg, sig) -> ok. */\nexport interface DsaVerifyVector {\n kind: \"dsa-verify\";\n param: ParamSet;\n pk: Uint8Array;\n msg: Uint8Array;\n sig: Uint8Array;\n expected: boolean;\n}\n\n/** Any normalized vector. */\nexport type Vector = KemKeygenVector | KemEncapVector | KemDecapVector | DsaVerifyVector;\n\n/**\n * Provenance of one ACVP vector file (docs/compliance/acvp-provenance.md): a\n * content hash over the RAW bytes plus the declared source, so a passing `kat`\n * run is traceable to the exact operator-supplied inputs. Sieve records what it\n * was given; it never fetches or ships vectors (ADR-0004).\n */\nexport interface VectorFileProvenance {\n path: string;\n sha256: string;\n sizeBytes: number;\n algorithm: string | null;\n mode: string | null;\n /** Parameter sets seen in the file. */\n parameterSets: string[];\n /** Operator-declared origin, or \"unknown (operator-supplied)\". */\n sourceUrl: string;\n /** Recognized test cases consumed from this file. */\n casesUsed: number;\n}\n\n/** Result of scanning a vectors directory. */\nexport interface VectorSet {\n vectors: Vector[];\n /** Files that were read. */\n files: string[];\n /** Non-fatal parse notes (unrecognized files/groups). */\n notes: string[];\n /** Per-file provenance for every vector file used (kat traceability). */\n provenance: VectorFileProvenance[];\n /** True when the operator declared a source via `vectors-manifest.json`. */\n provenanceDeclared: boolean;\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n const clean = hex.trim();\n if (clean.length === 0) return new Uint8Array(0);\n if (clean.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean)) {\n throw new Error(`invalid hex string (len ${clean.length})`);\n }\n const out = new Uint8Array(clean.length / 2);\n for (let i = 0; i < out.length; i++) {\n out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\n/** Map an ACVP parameterSet string to our canonical ParamSet, or undefined.\n * ACVP uses e.g. \"ML-KEM-768\", \"ML-DSA-65\", \"SLH-DSA-SHA2-128s\" — lower-casing\n * and `_`→`-` yields our canonical ids for all three families (incl. FIPS 205). */\nfunction normParam(family: Family, raw: unknown): ParamSet | undefined {\n if (typeof raw !== \"string\") return undefined;\n const s = raw.toLowerCase().replace(/_/g, \"-\");\n if (isParamSet(s) && s.startsWith(family)) return s;\n return undefined;\n}\n\nfunction asArray(v: unknown): unknown[] {\n return Array.isArray(v) ? v : [];\n}\nfunction asObj(v: unknown): Record<string, unknown> {\n return typeof v === \"object\" && v !== null ? (v as Record<string, unknown>) : {};\n}\nfunction str(v: unknown): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\n\n/**\n * Parse one ACVP test-vectors JSON document into normalized vectors.\n * The ACVP shape is: { algorithm, mode, testGroups: [{ parameterSet, tests:[...] }] }.\n */\nfunction parseAcvpDocument(doc: unknown, notes: string[], file: string): Vector[] {\n const root = asObj(doc);\n const algorithm = str(root[\"algorithm\"])?.toUpperCase() ?? \"\";\n const mode = str(root[\"mode\"])?.toLowerCase() ?? \"\";\n const out: Vector[] = [];\n\n // Order matters: \"SLH-DSA\" contains \"DSA\", so test SLH before the ML-DSA branch.\n const family: Family | undefined = algorithm.includes(\"KEM\")\n ? \"ml-kem\"\n : algorithm.includes(\"SLH\")\n ? \"slh-dsa\"\n : algorithm.includes(\"DSA\")\n ? \"ml-dsa\"\n : undefined;\n if (family === undefined) {\n notes.push(`${file}: unrecognized algorithm \"${algorithm}\", skipped`);\n return out;\n }\n\n for (const groupRaw of asArray(root[\"testGroups\"])) {\n const group = asObj(groupRaw);\n const param = normParam(family, group[\"parameterSet\"]);\n if (param === undefined) {\n notes.push(`${file}: skipped group with parameterSet=${String(group[\"parameterSet\"])}`);\n continue;\n }\n const fn = str(group[\"function\"])?.toLowerCase(); // encapDecap: \"encapsulation\"/\"decapsulation\"\n\n for (const testRaw of asArray(group[\"tests\"])) {\n const t = asObj(testRaw);\n try {\n if (family === \"ml-kem\") {\n if (mode.includes(\"keygen\")) {\n const d = str(t[\"d\"]);\n const z = str(t[\"z\"]);\n const seedHex = str(t[\"seed\"]) ?? (d && z ? d + z : undefined);\n out.push({\n kind: \"kem-keygen\",\n param,\n ...(seedHex ? { seed: hexToBytes(seedHex) } : {}),\n pk: hexToBytes(reqHex(t, \"ek\", \"pk\")),\n sk: hexToBytes(reqHex(t, \"dk\", \"sk\")),\n });\n } else if (mode.includes(\"encapdecap\") || mode.includes(\"encap\")) {\n // function may distinguish encapsulation vs decapsulation cases.\n if (fn === \"decapsulation\" || (\"dk\" in t && \"c\" in t)) {\n out.push({\n kind: \"kem-decap\",\n param,\n sk: hexToBytes(reqHex(t, \"dk\", \"sk\")),\n ct: hexToBytes(reqHex(t, \"c\", \"ct\")),\n ss: hexToBytes(reqHex(t, \"k\", \"ss\")),\n });\n } else {\n const m = str(t[\"m\"]);\n out.push({\n kind: \"kem-encap\",\n param,\n pk: hexToBytes(reqHex(t, \"ek\", \"pk\")),\n ...(m ? { coins: hexToBytes(m) } : {}),\n ct: hexToBytes(reqHex(t, \"c\", \"ct\")),\n ss: hexToBytes(reqHex(t, \"k\", \"ss\")),\n });\n }\n } else {\n notes.push(`${file}: unrecognized ML-KEM mode \"${mode}\"`);\n }\n } else {\n // ML-DSA / SLH-DSA: we can robustly check sigVer cases (verdict-driven).\n if (mode.includes(\"sigver\") || (\"signature\" in t && \"pk\" in t)) {\n const expected = t[\"testPassed\"];\n // NIST ACVP sigVer files mix valid and INTENTIONALLY-INVALID\n // signatures; the expected verdict lives in `testPassed`. If that\n // field is absent (or not a boolean) we cannot know whether the\n // signature should verify, so we SKIP the case rather than invent\n // `true` — defaulting to true flags a conformant SUT (which\n // correctly returns valid:false on a bad signature) as failing.\n if (typeof expected !== \"boolean\") {\n notes.push(`${file}: skipped a sigVer case with no boolean \"testPassed\" verdict`);\n continue;\n }\n out.push({\n kind: \"dsa-verify\",\n param,\n pk: hexToBytes(reqHex(t, \"pk\", \"ek\")),\n msg: hexToBytes(reqHex(t, \"message\", \"msg\")),\n sig: hexToBytes(reqHex(t, \"signature\", \"sig\")),\n expected,\n });\n } else {\n notes.push(`${file}: ML-DSA mode \"${mode}\" not used for KAT (sign is nonce-dependent)`);\n }\n }\n } catch (err) {\n notes.push(`${file}: skipped a test case: ${(err as Error).message}`);\n }\n }\n }\n return out;\n}\n\n/** Read the first present hex field among `keys`, else throw. */\nfunction reqHex(t: Record<string, unknown>, ...keys: string[]): string {\n for (const k of keys) {\n const v = str(t[k]);\n if (v !== undefined) return v;\n }\n throw new Error(`missing field (any of: ${keys.join(\", \")})`);\n}\n\n/**\n * Load and normalize all `*.json` ACVP vector files in `dir`.\n *\n * @throws if `dir` does not exist or contains no readable JSON files.\n */\n/** Operator-declared source manifest filename (not itself a vector file). */\nconst VECTORS_MANIFEST = \"vectors-manifest.json\";\n\nexport function loadVectors(dir: string): VectorSet {\n const st = statSync(dir); // throws ENOENT if missing\n if (!st.isDirectory()) {\n throw new Error(`--vectors path is not a directory: ${dir}`);\n }\n\n // Optional provenance manifest: `{ \"sourceUrl\": \"https://…\" }` declaring where\n // the operator obtained these vectors. Absent → provenance is undeclared.\n let declaredSource: string | undefined;\n try {\n const m = JSON.parse(readFileSync(join(dir, VECTORS_MANIFEST), \"utf8\")) as {\n sourceUrl?: unknown;\n };\n if (typeof m.sourceUrl === \"string\" && m.sourceUrl.trim()) declaredSource = m.sourceUrl.trim();\n } catch {\n /* no manifest — provenanceDeclared stays false */\n }\n\n const entries = readdirSync(dir).filter(\n (f) => f.toLowerCase().endsWith(\".json\") && f.toLowerCase() !== VECTORS_MANIFEST,\n );\n if (entries.length === 0) {\n throw new Error(`no .json vector files found in ${dir}`);\n }\n\n const vectors: Vector[] = [];\n const files: string[] = [];\n const notes: string[] = [];\n const provenance: VectorFileProvenance[] = [];\n\n for (const name of entries) {\n const path = join(dir, name);\n // Hash the RAW bytes as supplied, before parsing — proves exactly what was used.\n const raw = readFileSync(path);\n const sha256 = createHash(\"sha256\").update(raw).digest(\"hex\");\n let doc: unknown;\n try {\n doc = JSON.parse(raw.toString(\"utf8\"));\n } catch (err) {\n notes.push(`${name}: not valid JSON (${(err as Error).message})`);\n continue;\n }\n files.push(name);\n const before = vectors.length;\n // ACVP test-vector files may be a single object or an array of prompts.\n const docs = Array.isArray(doc) ? doc : [doc];\n for (const d of docs) {\n vectors.push(...parseAcvpDocument(d, notes, name));\n }\n\n // Best-effort ACVP metadata for the provenance record.\n const root = asObj(docs[0]);\n const params = new Set<string>();\n for (const g of asArray(root[\"testGroups\"])) {\n const p = str(asObj(g)[\"parameterSet\"]);\n if (p) params.add(p);\n }\n provenance.push({\n path: name,\n sha256,\n sizeBytes: raw.length,\n algorithm: str(root[\"algorithm\"]) ?? null,\n mode: str(root[\"mode\"]) ?? null,\n parameterSets: [...params],\n sourceUrl: declaredSource ?? \"unknown (operator-supplied)\",\n casesUsed: vectors.length - before,\n });\n }\n\n return { vectors, files, notes, provenance, provenanceDeclared: declaredSource !== undefined };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"vectors.js","sourceRoot":"","sources":["../src/vectors.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Loader for OFFICIAL NIST ACVP Known-Answer-Test (KAT) vector files.\n *\n * HONESTY NOTE: Sieve ships NO cryptographic test vectors. It does not and must\n * not fabricate expected pk/sk/ct/ss/sig bytes. This module only PARSES vector\n * files that the user downloads from NIST and points Sieve at via --vectors.\n * See vectors/README.md for where to obtain them and the file format.\n *\n * Supported input: the NIST ACVP-server JSON format for ML-KEM (keyGen,\n * encapDecap) and ML-DSA (keyGen, sigGen, sigVer). The ACVP JSON encodes bytes\n * as hex strings. We normalize the fields we need into a flat list of typed\n * test cases. Anything we don't recognize is ignored (not invented).\n *\n * Uses only node:fs. No cryptography.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { isParamSet } from \"./sizes.js\";\nimport type { Family, ParamSet } from \"./sizes.js\";\n\n/** A normalized ML-KEM keygen vector: seed -> (pk, sk). */\ninterface KemKeygenVector {\n kind: \"kem-keygen\";\n param: ParamSet;\n /** Concatenated d||z seed (hex-decoded). */\n seed?: Uint8Array;\n pk: Uint8Array;\n sk: Uint8Array;\n}\n\n/** A normalized ML-KEM encapsulation vector: (pk, coins) -> (ct, ss). */\ninterface KemEncapVector {\n kind: \"kem-encap\";\n param: ParamSet;\n pk: Uint8Array;\n /** Encapsulation coins/message m (hex-decoded), if present. */\n coins?: Uint8Array;\n ct: Uint8Array;\n ss: Uint8Array;\n}\n\n/** A normalized ML-KEM decapsulation vector: (sk, ct) -> ss. */\ninterface KemDecapVector {\n kind: \"kem-decap\";\n param: ParamSet;\n sk: Uint8Array;\n ct: Uint8Array;\n ss: Uint8Array;\n}\n\n/** A normalized ML-DSA signature-verification vector: (pk, msg, sig) -> ok. */\ninterface DsaVerifyVector {\n kind: \"dsa-verify\";\n param: ParamSet;\n pk: Uint8Array;\n msg: Uint8Array;\n sig: Uint8Array;\n expected: boolean;\n}\n\n/** Any normalized vector. */\nexport type Vector = KemKeygenVector | KemEncapVector | KemDecapVector | DsaVerifyVector;\n\n/**\n * Provenance of one ACVP vector file (docs/compliance/acvp-provenance.md): a\n * content hash over the RAW bytes plus the declared source, so a passing `kat`\n * run is traceable to the exact operator-supplied inputs. Sieve records what it\n * was given; it never fetches or ships vectors (ADR-0004).\n */\nexport interface VectorFileProvenance {\n path: string;\n sha256: string;\n sizeBytes: number;\n algorithm: string | null;\n mode: string | null;\n /** Parameter sets seen in the file. */\n parameterSets: string[];\n /** Operator-declared origin, or \"unknown (operator-supplied)\". */\n sourceUrl: string;\n /** Recognized test cases consumed from this file. */\n casesUsed: number;\n}\n\n/** Result of scanning a vectors directory. */\nexport interface VectorSet {\n vectors: Vector[];\n /** Files that were read. */\n files: string[];\n /** Non-fatal parse notes (unrecognized files/groups). */\n notes: string[];\n /** Per-file provenance for every vector file used (kat traceability). */\n provenance: VectorFileProvenance[];\n /** True when the operator declared a source via `vectors-manifest.json`. */\n provenanceDeclared: boolean;\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n const clean = hex.trim();\n if (clean.length === 0) return new Uint8Array(0);\n if (clean.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean)) {\n throw new Error(`invalid hex string (len ${clean.length})`);\n }\n const out = new Uint8Array(clean.length / 2);\n for (let i = 0; i < out.length; i++) {\n out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\n/** Map an ACVP parameterSet string to our canonical ParamSet, or undefined.\n * ACVP uses e.g. \"ML-KEM-768\", \"ML-DSA-65\", \"SLH-DSA-SHA2-128s\" — lower-casing\n * and `_`→`-` yields our canonical ids for all three families (incl. FIPS 205). */\nfunction normParam(family: Family, raw: unknown): ParamSet | undefined {\n if (typeof raw !== \"string\") return undefined;\n const s = raw.toLowerCase().replace(/_/g, \"-\");\n if (isParamSet(s) && s.startsWith(family)) return s;\n return undefined;\n}\n\nfunction asArray(v: unknown): unknown[] {\n return Array.isArray(v) ? v : [];\n}\nfunction asObj(v: unknown): Record<string, unknown> {\n return typeof v === \"object\" && v !== null ? (v as Record<string, unknown>) : {};\n}\nfunction str(v: unknown): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\n\n/**\n * Parse one ACVP test-vectors JSON document into normalized vectors.\n * The ACVP shape is: { algorithm, mode, testGroups: [{ parameterSet, tests:[...] }] }.\n */\nfunction parseAcvpDocument(doc: unknown, notes: string[], file: string): Vector[] {\n const root = asObj(doc);\n const algorithm = str(root[\"algorithm\"])?.toUpperCase() ?? \"\";\n const mode = str(root[\"mode\"])?.toLowerCase() ?? \"\";\n const out: Vector[] = [];\n\n // Order matters: \"SLH-DSA\" contains \"DSA\", so test SLH before the ML-DSA branch.\n const family: Family | undefined = algorithm.includes(\"KEM\")\n ? \"ml-kem\"\n : algorithm.includes(\"SLH\")\n ? \"slh-dsa\"\n : algorithm.includes(\"DSA\")\n ? \"ml-dsa\"\n : undefined;\n if (family === undefined) {\n notes.push(`${file}: unrecognized algorithm \"${algorithm}\", skipped`);\n return out;\n }\n\n for (const groupRaw of asArray(root[\"testGroups\"])) {\n const group = asObj(groupRaw);\n const param = normParam(family, group[\"parameterSet\"]);\n if (param === undefined) {\n notes.push(`${file}: skipped group with parameterSet=${String(group[\"parameterSet\"])}`);\n continue;\n }\n const fn = str(group[\"function\"])?.toLowerCase(); // encapDecap: \"encapsulation\"/\"decapsulation\"\n\n for (const testRaw of asArray(group[\"tests\"])) {\n const t = asObj(testRaw);\n try {\n if (family === \"ml-kem\") {\n if (mode.includes(\"keygen\")) {\n const d = str(t[\"d\"]);\n const z = str(t[\"z\"]);\n const seedHex = str(t[\"seed\"]) ?? (d && z ? d + z : undefined);\n out.push({\n kind: \"kem-keygen\",\n param,\n ...(seedHex ? { seed: hexToBytes(seedHex) } : {}),\n pk: hexToBytes(reqHex(t, \"ek\", \"pk\")),\n sk: hexToBytes(reqHex(t, \"dk\", \"sk\")),\n });\n } else if (mode.includes(\"encapdecap\") || mode.includes(\"encap\")) {\n // function may distinguish encapsulation vs decapsulation cases.\n if (fn === \"decapsulation\" || (\"dk\" in t && \"c\" in t)) {\n out.push({\n kind: \"kem-decap\",\n param,\n sk: hexToBytes(reqHex(t, \"dk\", \"sk\")),\n ct: hexToBytes(reqHex(t, \"c\", \"ct\")),\n ss: hexToBytes(reqHex(t, \"k\", \"ss\")),\n });\n } else {\n const m = str(t[\"m\"]);\n out.push({\n kind: \"kem-encap\",\n param,\n pk: hexToBytes(reqHex(t, \"ek\", \"pk\")),\n ...(m ? { coins: hexToBytes(m) } : {}),\n ct: hexToBytes(reqHex(t, \"c\", \"ct\")),\n ss: hexToBytes(reqHex(t, \"k\", \"ss\")),\n });\n }\n } else {\n notes.push(`${file}: unrecognized ML-KEM mode \"${mode}\"`);\n }\n } else {\n // ML-DSA / SLH-DSA: we can robustly check sigVer cases (verdict-driven).\n if (mode.includes(\"sigver\") || (\"signature\" in t && \"pk\" in t)) {\n const expected = t[\"testPassed\"];\n // NIST ACVP sigVer files mix valid and INTENTIONALLY-INVALID\n // signatures; the expected verdict lives in `testPassed`. If that\n // field is absent (or not a boolean) we cannot know whether the\n // signature should verify, so we SKIP the case rather than invent\n // `true` — defaulting to true flags a conformant SUT (which\n // correctly returns valid:false on a bad signature) as failing.\n if (typeof expected !== \"boolean\") {\n notes.push(`${file}: skipped a sigVer case with no boolean \"testPassed\" verdict`);\n continue;\n }\n out.push({\n kind: \"dsa-verify\",\n param,\n pk: hexToBytes(reqHex(t, \"pk\", \"ek\")),\n msg: hexToBytes(reqHex(t, \"message\", \"msg\")),\n sig: hexToBytes(reqHex(t, \"signature\", \"sig\")),\n expected,\n });\n } else {\n notes.push(`${file}: ML-DSA mode \"${mode}\" not used for KAT (sign is nonce-dependent)`);\n }\n }\n } catch (err) {\n notes.push(`${file}: skipped a test case: ${(err as Error).message}`);\n }\n }\n }\n return out;\n}\n\n/** Read the first present hex field among `keys`, else throw. */\nfunction reqHex(t: Record<string, unknown>, ...keys: string[]): string {\n for (const k of keys) {\n const v = str(t[k]);\n if (v !== undefined) return v;\n }\n throw new Error(`missing field (any of: ${keys.join(\", \")})`);\n}\n\n/**\n * Load and normalize all `*.json` ACVP vector files in `dir`.\n *\n * @throws if `dir` does not exist or contains no readable JSON files.\n */\n/** Operator-declared source manifest filename (not itself a vector file). */\nconst VECTORS_MANIFEST = \"vectors-manifest.json\";\n\nexport function loadVectors(dir: string): VectorSet {\n const st = statSync(dir); // throws ENOENT if missing\n if (!st.isDirectory()) {\n throw new Error(`--vectors path is not a directory: ${dir}`);\n }\n\n // Optional provenance manifest: `{ \"sourceUrl\": \"https://…\" }` declaring where\n // the operator obtained these vectors. Absent → provenance is undeclared.\n let declaredSource: string | undefined;\n try {\n const m = JSON.parse(readFileSync(join(dir, VECTORS_MANIFEST), \"utf8\")) as {\n sourceUrl?: unknown;\n };\n if (typeof m.sourceUrl === \"string\" && m.sourceUrl.trim()) declaredSource = m.sourceUrl.trim();\n } catch {\n /* no manifest — provenanceDeclared stays false */\n }\n\n const entries = readdirSync(dir).filter(\n (f) => f.toLowerCase().endsWith(\".json\") && f.toLowerCase() !== VECTORS_MANIFEST,\n );\n if (entries.length === 0) {\n throw new Error(`no .json vector files found in ${dir}`);\n }\n\n const vectors: Vector[] = [];\n const files: string[] = [];\n const notes: string[] = [];\n const provenance: VectorFileProvenance[] = [];\n\n for (const name of entries) {\n const path = join(dir, name);\n // Hash the RAW bytes as supplied, before parsing — proves exactly what was used.\n const raw = readFileSync(path);\n const sha256 = createHash(\"sha256\").update(raw).digest(\"hex\");\n let doc: unknown;\n try {\n doc = JSON.parse(raw.toString(\"utf8\"));\n } catch (err) {\n notes.push(`${name}: not valid JSON (${(err as Error).message})`);\n continue;\n }\n files.push(name);\n const before = vectors.length;\n // ACVP test-vector files may be a single object or an array of prompts.\n const docs = Array.isArray(doc) ? doc : [doc];\n for (const d of docs) {\n vectors.push(...parseAcvpDocument(d, notes, name));\n }\n\n // Best-effort ACVP metadata for the provenance record.\n const root = asObj(docs[0]);\n const params = new Set<string>();\n for (const g of asArray(root[\"testGroups\"])) {\n const p = str(asObj(g)[\"parameterSet\"]);\n if (p) params.add(p);\n }\n provenance.push({\n path: name,\n sha256,\n sizeBytes: raw.length,\n algorithm: str(root[\"algorithm\"]) ?? null,\n mode: str(root[\"mode\"]) ?? null,\n parameterSets: [...params],\n sourceUrl: declaredSource ?? \"unknown (operator-supplied)\",\n casesUsed: vectors.length - before,\n });\n }\n\n return { vectors, files, notes, provenance, provenanceDeclared: declaredSource !== undefined };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quantakrypto/sieve",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Sieve — conformance battery for ML-KEM / ML-DSA implementations. Drives any implementation over a simple stdin/stdout JSON protocol. Zero runtime dependencies.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Dandelion Labs <hello@dandelionlabs.io> (https://dandelionlabs.io)",
|