@quantakrypto/sieve 0.1.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.
Files changed (83) hide show
  1. package/README.md +227 -0
  2. package/dist/categories/correctness.d.ts +13 -0
  3. package/dist/categories/correctness.d.ts.map +1 -0
  4. package/dist/categories/correctness.js +78 -0
  5. package/dist/categories/correctness.js.map +1 -0
  6. package/dist/categories/determinism.d.ts +12 -0
  7. package/dist/categories/determinism.d.ts.map +1 -0
  8. package/dist/categories/determinism.js +78 -0
  9. package/dist/categories/determinism.js.map +1 -0
  10. package/dist/categories/dsa.d.ts +17 -0
  11. package/dist/categories/dsa.d.ts.map +1 -0
  12. package/dist/categories/dsa.js +17 -0
  13. package/dist/categories/dsa.js.map +1 -0
  14. package/dist/categories/helpers.d.ts +50 -0
  15. package/dist/categories/helpers.d.ts.map +1 -0
  16. package/dist/categories/helpers.js +127 -0
  17. package/dist/categories/helpers.js.map +1 -0
  18. package/dist/categories/implicit-rejection.d.ts +29 -0
  19. package/dist/categories/implicit-rejection.d.ts.map +1 -0
  20. package/dist/categories/implicit-rejection.js +126 -0
  21. package/dist/categories/implicit-rejection.js.map +1 -0
  22. package/dist/categories/index.d.ts +30 -0
  23. package/dist/categories/index.d.ts.map +1 -0
  24. package/dist/categories/index.js +33 -0
  25. package/dist/categories/index.js.map +1 -0
  26. package/dist/categories/kat.d.ts +21 -0
  27. package/dist/categories/kat.d.ts.map +1 -0
  28. package/dist/categories/kat.js +173 -0
  29. package/dist/categories/kat.js.map +1 -0
  30. package/dist/categories/robustness.d.ts +15 -0
  31. package/dist/categories/robustness.d.ts.map +1 -0
  32. package/dist/categories/robustness.js +98 -0
  33. package/dist/categories/robustness.js.map +1 -0
  34. package/dist/categories/signature.d.ts +29 -0
  35. package/dist/categories/signature.d.ts.map +1 -0
  36. package/dist/categories/signature.js +259 -0
  37. package/dist/categories/signature.js.map +1 -0
  38. package/dist/categories/sizes.d.ts +23 -0
  39. package/dist/categories/sizes.d.ts.map +1 -0
  40. package/dist/categories/sizes.js +150 -0
  41. package/dist/categories/sizes.js.map +1 -0
  42. package/dist/categories/slh-dsa.d.ts +23 -0
  43. package/dist/categories/slh-dsa.d.ts.map +1 -0
  44. package/dist/categories/slh-dsa.js +23 -0
  45. package/dist/categories/slh-dsa.js.map +1 -0
  46. package/dist/categories/timing.d.ts +16 -0
  47. package/dist/categories/timing.d.ts.map +1 -0
  48. package/dist/categories/timing.js +98 -0
  49. package/dist/categories/timing.js.map +1 -0
  50. package/dist/categories/types.d.ts +68 -0
  51. package/dist/categories/types.d.ts.map +1 -0
  52. package/dist/categories/types.js +31 -0
  53. package/dist/categories/types.js.map +1 -0
  54. package/dist/cli.d.ts +14 -0
  55. package/dist/cli.d.ts.map +1 -0
  56. package/dist/cli.js +181 -0
  57. package/dist/cli.js.map +1 -0
  58. package/dist/index.d.ts +70 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +96 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/protocol.d.ts +169 -0
  63. package/dist/protocol.d.ts.map +1 -0
  64. package/dist/protocol.js +115 -0
  65. package/dist/protocol.js.map +1 -0
  66. package/dist/report.d.ts +48 -0
  67. package/dist/report.d.ts.map +1 -0
  68. package/dist/report.js +79 -0
  69. package/dist/report.js.map +1 -0
  70. package/dist/runner.d.ts +129 -0
  71. package/dist/runner.d.ts.map +1 -0
  72. package/dist/runner.js +305 -0
  73. package/dist/runner.js.map +1 -0
  74. package/dist/sizes.d.ts +84 -0
  75. package/dist/sizes.d.ts.map +1 -0
  76. package/dist/sizes.js +214 -0
  77. package/dist/sizes.js.map +1 -0
  78. package/dist/vectors.d.ts +69 -0
  79. package/dist/vectors.d.ts.map +1 -0
  80. package/dist/vectors.js +198 -0
  81. package/dist/vectors.js.map +1 -0
  82. package/package.json +43 -0
  83. package/vectors/README.md +83 -0
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Loader for OFFICIAL NIST ACVP Known-Answer-Test (KAT) vector files.
3
+ *
4
+ * HONESTY NOTE: Sieve ships NO cryptographic test vectors. It does not and must
5
+ * not fabricate expected pk/sk/ct/ss/sig bytes. This module only PARSES vector
6
+ * files that the user downloads from NIST and points Sieve at via --vectors.
7
+ * See vectors/README.md for where to obtain them and the file format.
8
+ *
9
+ * Supported input: the NIST ACVP-server JSON format for ML-KEM (keyGen,
10
+ * encapDecap) and ML-DSA (keyGen, sigGen, sigVer). The ACVP JSON encodes bytes
11
+ * as hex strings. We normalize the fields we need into a flat list of typed
12
+ * test cases. Anything we don't recognize is ignored (not invented).
13
+ *
14
+ * Uses only node:fs. No cryptography.
15
+ */
16
+ import type { ParamSet } from "./sizes.js";
17
+ /** A normalized ML-KEM keygen vector: seed -> (pk, sk). */
18
+ export interface KemKeygenVector {
19
+ kind: "kem-keygen";
20
+ param: ParamSet;
21
+ /** Concatenated d||z seed (hex-decoded). */
22
+ seed?: Uint8Array;
23
+ pk: Uint8Array;
24
+ sk: Uint8Array;
25
+ }
26
+ /** A normalized ML-KEM encapsulation vector: (pk, coins) -> (ct, ss). */
27
+ export interface KemEncapVector {
28
+ kind: "kem-encap";
29
+ param: ParamSet;
30
+ pk: Uint8Array;
31
+ /** Encapsulation coins/message m (hex-decoded), if present. */
32
+ coins?: Uint8Array;
33
+ ct: Uint8Array;
34
+ ss: Uint8Array;
35
+ }
36
+ /** A normalized ML-KEM decapsulation vector: (sk, ct) -> ss. */
37
+ export interface KemDecapVector {
38
+ kind: "kem-decap";
39
+ param: ParamSet;
40
+ sk: Uint8Array;
41
+ ct: Uint8Array;
42
+ ss: Uint8Array;
43
+ }
44
+ /** A normalized ML-DSA signature-verification vector: (pk, msg, sig) -> ok. */
45
+ export interface DsaVerifyVector {
46
+ kind: "dsa-verify";
47
+ param: ParamSet;
48
+ pk: Uint8Array;
49
+ msg: Uint8Array;
50
+ sig: Uint8Array;
51
+ expected: boolean;
52
+ }
53
+ /** Any normalized vector. */
54
+ export type Vector = KemKeygenVector | KemEncapVector | KemDecapVector | DsaVerifyVector;
55
+ /** Result of scanning a vectors directory. */
56
+ export interface VectorSet {
57
+ vectors: Vector[];
58
+ /** Files that were read. */
59
+ files: string[];
60
+ /** Non-fatal parse notes (unrecognized files/groups). */
61
+ notes: string[];
62
+ }
63
+ /**
64
+ * Load and normalize all `*.json` ACVP vector files in `dir`.
65
+ *
66
+ * @throws if `dir` does not exist or contains no readable JSON files.
67
+ */
68
+ export declare function loadVectors(dir: string): VectorSet;
69
+ //# sourceMappingURL=vectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectors.d.ts","sourceRoot":"","sources":["../src/vectors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAU,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnD,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC9B,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,MAAM,WAAW,cAAc;IAC7B,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,MAAM,WAAW,cAAc;IAC7B,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,MAAM,WAAW,eAAe;IAC9B,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,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;CACjB;AAgJD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAgClD"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Loader for OFFICIAL NIST ACVP Known-Answer-Test (KAT) vector files.
3
+ *
4
+ * HONESTY NOTE: Sieve ships NO cryptographic test vectors. It does not and must
5
+ * not fabricate expected pk/sk/ct/ss/sig bytes. This module only PARSES vector
6
+ * files that the user downloads from NIST and points Sieve at via --vectors.
7
+ * See vectors/README.md for where to obtain them and the file format.
8
+ *
9
+ * Supported input: the NIST ACVP-server JSON format for ML-KEM (keyGen,
10
+ * encapDecap) and ML-DSA (keyGen, sigGen, sigVer). The ACVP JSON encodes bytes
11
+ * as hex strings. We normalize the fields we need into a flat list of typed
12
+ * test cases. Anything we don't recognize is ignored (not invented).
13
+ *
14
+ * Uses only node:fs. No cryptography.
15
+ */
16
+ import { readdirSync, readFileSync, statSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ function hexToBytes(hex) {
19
+ const clean = hex.trim();
20
+ if (clean.length === 0)
21
+ return new Uint8Array(0);
22
+ if (clean.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean)) {
23
+ throw new Error(`invalid hex string (len ${clean.length})`);
24
+ }
25
+ const out = new Uint8Array(clean.length / 2);
26
+ for (let i = 0; i < out.length; i++) {
27
+ out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
28
+ }
29
+ return out;
30
+ }
31
+ /** Map an ACVP parameterSet string to our canonical ParamSet, or undefined. */
32
+ function normParam(family, raw) {
33
+ if (typeof raw !== "string")
34
+ return undefined;
35
+ const s = raw.toLowerCase().replace(/_/g, "-");
36
+ // ACVP uses e.g. "ML-KEM-768", "ML-DSA-65".
37
+ const candidates = {
38
+ "ml-kem-512": "ml-kem-512",
39
+ "ml-kem-768": "ml-kem-768",
40
+ "ml-kem-1024": "ml-kem-1024",
41
+ "ml-dsa-44": "ml-dsa-44",
42
+ "ml-dsa-65": "ml-dsa-65",
43
+ "ml-dsa-87": "ml-dsa-87",
44
+ };
45
+ const hit = candidates[s];
46
+ if (hit && hit.startsWith(family))
47
+ return hit;
48
+ return undefined;
49
+ }
50
+ function asArray(v) {
51
+ return Array.isArray(v) ? v : [];
52
+ }
53
+ function asObj(v) {
54
+ return typeof v === "object" && v !== null ? v : {};
55
+ }
56
+ function str(v) {
57
+ return typeof v === "string" ? v : undefined;
58
+ }
59
+ /**
60
+ * Parse one ACVP test-vectors JSON document into normalized vectors.
61
+ * The ACVP shape is: { algorithm, mode, testGroups: [{ parameterSet, tests:[...] }] }.
62
+ */
63
+ function parseAcvpDocument(doc, notes, file) {
64
+ const root = asObj(doc);
65
+ const algorithm = str(root["algorithm"])?.toUpperCase() ?? "";
66
+ const mode = str(root["mode"])?.toLowerCase() ?? "";
67
+ const out = [];
68
+ const family = algorithm.includes("KEM")
69
+ ? "ml-kem"
70
+ : algorithm.includes("DSA")
71
+ ? "ml-dsa"
72
+ : undefined;
73
+ if (family === undefined) {
74
+ notes.push(`${file}: unrecognized algorithm "${algorithm}", skipped`);
75
+ return out;
76
+ }
77
+ for (const groupRaw of asArray(root["testGroups"])) {
78
+ const group = asObj(groupRaw);
79
+ const param = normParam(family, group["parameterSet"]);
80
+ if (param === undefined) {
81
+ notes.push(`${file}: skipped group with parameterSet=${String(group["parameterSet"])}`);
82
+ continue;
83
+ }
84
+ const fn = str(group["function"])?.toLowerCase(); // encapDecap: "encapsulation"/"decapsulation"
85
+ for (const testRaw of asArray(group["tests"])) {
86
+ const t = asObj(testRaw);
87
+ try {
88
+ if (family === "ml-kem") {
89
+ if (mode.includes("keygen")) {
90
+ const d = str(t["d"]);
91
+ const z = str(t["z"]);
92
+ const seedHex = str(t["seed"]) ?? (d && z ? d + z : undefined);
93
+ out.push({
94
+ kind: "kem-keygen",
95
+ param,
96
+ ...(seedHex ? { seed: hexToBytes(seedHex) } : {}),
97
+ pk: hexToBytes(reqHex(t, "ek", "pk")),
98
+ sk: hexToBytes(reqHex(t, "dk", "sk")),
99
+ });
100
+ }
101
+ else if (mode.includes("encapdecap") || mode.includes("encap")) {
102
+ // function may distinguish encapsulation vs decapsulation cases.
103
+ if (fn === "decapsulation" || ("dk" in t && "c" in t)) {
104
+ out.push({
105
+ kind: "kem-decap",
106
+ param,
107
+ sk: hexToBytes(reqHex(t, "dk", "sk")),
108
+ ct: hexToBytes(reqHex(t, "c", "ct")),
109
+ ss: hexToBytes(reqHex(t, "k", "ss")),
110
+ });
111
+ }
112
+ else {
113
+ const m = str(t["m"]);
114
+ out.push({
115
+ kind: "kem-encap",
116
+ param,
117
+ pk: hexToBytes(reqHex(t, "ek", "pk")),
118
+ ...(m ? { coins: hexToBytes(m) } : {}),
119
+ ct: hexToBytes(reqHex(t, "c", "ct")),
120
+ ss: hexToBytes(reqHex(t, "k", "ss")),
121
+ });
122
+ }
123
+ }
124
+ else {
125
+ notes.push(`${file}: unrecognized ML-KEM mode "${mode}"`);
126
+ }
127
+ }
128
+ else {
129
+ // ML-DSA: we can robustly check sigVer cases (no nonce dependence).
130
+ if (mode.includes("sigver") || ("signature" in t && "pk" in t)) {
131
+ const expected = t["testPassed"];
132
+ out.push({
133
+ kind: "dsa-verify",
134
+ param,
135
+ pk: hexToBytes(reqHex(t, "pk", "ek")),
136
+ msg: hexToBytes(reqHex(t, "message", "msg")),
137
+ sig: hexToBytes(reqHex(t, "signature", "sig")),
138
+ expected: typeof expected === "boolean" ? expected : true,
139
+ });
140
+ }
141
+ else {
142
+ notes.push(`${file}: ML-DSA mode "${mode}" not used for KAT (sign is nonce-dependent)`);
143
+ }
144
+ }
145
+ }
146
+ catch (err) {
147
+ notes.push(`${file}: skipped a test case: ${err.message}`);
148
+ }
149
+ }
150
+ }
151
+ return out;
152
+ }
153
+ /** Read the first present hex field among `keys`, else throw. */
154
+ function reqHex(t, ...keys) {
155
+ for (const k of keys) {
156
+ const v = str(t[k]);
157
+ if (v !== undefined)
158
+ return v;
159
+ }
160
+ throw new Error(`missing field (any of: ${keys.join(", ")})`);
161
+ }
162
+ /**
163
+ * Load and normalize all `*.json` ACVP vector files in `dir`.
164
+ *
165
+ * @throws if `dir` does not exist or contains no readable JSON files.
166
+ */
167
+ export function loadVectors(dir) {
168
+ const st = statSync(dir); // throws ENOENT if missing
169
+ if (!st.isDirectory()) {
170
+ throw new Error(`--vectors path is not a directory: ${dir}`);
171
+ }
172
+ const entries = readdirSync(dir).filter((f) => f.toLowerCase().endsWith(".json"));
173
+ if (entries.length === 0) {
174
+ throw new Error(`no .json vector files found in ${dir}`);
175
+ }
176
+ const vectors = [];
177
+ const files = [];
178
+ const notes = [];
179
+ for (const name of entries) {
180
+ const path = join(dir, name);
181
+ let doc;
182
+ try {
183
+ doc = JSON.parse(readFileSync(path, "utf8"));
184
+ }
185
+ catch (err) {
186
+ notes.push(`${name}: not valid JSON (${err.message})`);
187
+ continue;
188
+ }
189
+ files.push(name);
190
+ // ACVP test-vector files may be a single object or an array of prompts.
191
+ const docs = Array.isArray(doc) ? doc : [doc];
192
+ for (const d of docs) {
193
+ vectors.push(...parseAcvpDocument(d, notes, name));
194
+ }
195
+ }
196
+ return { vectors, files, notes };
197
+ }
198
+ //# sourceMappingURL=vectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectors.js","sourceRoot":"","sources":["../src/vectors.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@quantakrypto/sieve",
3
+ "version": "0.1.0",
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
+ "license": "Apache-2.0",
6
+ "author": "Dandelion Labs <hello@dandelionlabs.io> (https://dandelionlabs.io)",
7
+ "homepage": "https://github.com/dandelionlabs-io/qproof-tools/tree/main/packages/sieve#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/dandelionlabs-io/qproof-tools.git",
11
+ "directory": "packages/sieve"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/dandelionlabs-io/qproof-tools/issues"
15
+ },
16
+ "type": "module",
17
+ "bin": {
18
+ "sieve": "./dist/cli.js"
19
+ },
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/index.js"
26
+ }
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "vectors",
31
+ "README.md"
32
+ ],
33
+ "engines": {
34
+ "node": ">=20"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "scripts": {
40
+ "build": "tsc -b",
41
+ "test": "node --import tsx --test test/*.test.ts"
42
+ }
43
+ }
@@ -0,0 +1,83 @@
1
+ # Official KAT / ACVP vectors
2
+
3
+ **Sieve ships no cryptographic test vectors.** This directory is where *you*
4
+ place official NIST vector files so the `kat` category can run exact-value
5
+ checks. Without `--vectors <dir>`, the `kat` category is **SKIPPED** — Sieve
6
+ will not invent expected values.
7
+
8
+ ## Where to get them
9
+
10
+ Use the **NIST ACVP (Automated Cryptographic Validation Protocol) test
11
+ vectors**, which cover ML-KEM (FIPS 203) and ML-DSA (FIPS 204):
12
+
13
+ - **ACVP test vectors (recommended):**
14
+ <https://github.com/usnistgov/ACVP-Server> — under
15
+ `gen-val/json-files/`, e.g. `ML-KEM-encapDecap-FIPS203/`,
16
+ `ML-KEM-keyGen-FIPS203/`, `ML-DSA-sigVer-FIPS204/`,
17
+ `ML-DSA-keyGen-FIPS204/`. Each folder contains an
18
+ `internalProjection.json` / `prompt.json` / `expectedResults.json` set.
19
+ - **ACVTS demo / production** servers publish the same format.
20
+ - The **CAVP** program pages link to the current vector packages:
21
+ <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program>.
22
+
23
+ Always verify you downloaded vectors from an authoritative NIST source. Do not
24
+ trust vectors of unknown provenance for conformance claims.
25
+
26
+ ## How to use them
27
+
28
+ 1. Download the relevant ACVP JSON files for your parameter set.
29
+ 2. Drop the `*.json` files into a directory (this one, or any path).
30
+ 3. Run Sieve with `--vectors`:
31
+
32
+ ```bash
33
+ sieve --impl "node ./my-impl.js" --param ml-kem-768 --vectors ./vectors
34
+ ```
35
+
36
+ Only vectors whose `parameterSet` matches `--param` are used; the rest are
37
+ ignored (and noted).
38
+
39
+ ## Expected file format
40
+
41
+ The loader (`src/vectors.ts`) parses the **standard NIST ACVP test-vector
42
+ JSON**. The relevant shape is:
43
+
44
+ ```jsonc
45
+ {
46
+ "algorithm": "ML-KEM", // or "ML-DSA"
47
+ "mode": "encapDecap", // or "keyGen", "sigVer", ...
48
+ "testGroups": [
49
+ {
50
+ "parameterSet": "ML-KEM-768",
51
+ "function": "decapsulation", // for encapDecap groups
52
+ "tests": [
53
+ { "dk": "<hex>", "c": "<hex>", "k": "<hex>" } // sk, ct, ss
54
+ ]
55
+ }
56
+ ]
57
+ }
58
+ ```
59
+
60
+ Bytes are **hex** strings in ACVP. The loader normalizes the fields it
61
+ recognizes into typed cases:
62
+
63
+ | ACVP `mode` / fields | Sieve check | What is asserted |
64
+ |-------------------------------------|--------------------|------------------|
65
+ | `keyGen` with `d`+`z` (or `seed`), `ek`, `dk` | `kem-keygen` | seeded keygen reproduces `pk`/`sk` (skipped if the SUT can't seed) |
66
+ | `encapDecap` (encapsulation), `ek`, `m`, `c`, `k` | `kem-encap` | with `coins=m`, deterministic encaps reproduces `ct`/`ss` (skipped if no coins support) |
67
+ | `encapDecap` (decapsulation), `dk`, `c`, `k` | `kem-decap` | `decaps(sk, ct)` equals expected `ss` |
68
+ | `sigVer`, `pk`, `message`, `signature`, `testPassed` | `dsa-verify` | `verify(pk, msg, sig)` equals `testPassed` |
69
+
70
+ > **Note on ML-DSA signing.** ML-DSA `sign` is randomized (hedged), so signature
71
+ > bytes are not reproducible without the exact private randomness. Sieve
72
+ > therefore uses ACVP **sigVer** vectors (verification verdicts) for ML-DSA KAT,
73
+ > not sigGen, and exercises sign/verify self-consistency separately in the `dsa`
74
+ > category.
75
+
76
+ Unrecognized files, algorithms, or fields are recorded as non-fatal notes and
77
+ skipped — Sieve never fabricates a value to fill a gap.
78
+
79
+ ## `.gitkeep`
80
+
81
+ This directory is intentionally tracked (so `files` in `package.json` can ship
82
+ this README) but contains no vectors. Add your own; do not commit
83
+ redistributed NIST files unless their license permits it.