@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.
- package/README.md +227 -0
- package/dist/categories/correctness.d.ts +13 -0
- package/dist/categories/correctness.d.ts.map +1 -0
- package/dist/categories/correctness.js +78 -0
- package/dist/categories/correctness.js.map +1 -0
- package/dist/categories/determinism.d.ts +12 -0
- package/dist/categories/determinism.d.ts.map +1 -0
- package/dist/categories/determinism.js +78 -0
- package/dist/categories/determinism.js.map +1 -0
- package/dist/categories/dsa.d.ts +17 -0
- package/dist/categories/dsa.d.ts.map +1 -0
- package/dist/categories/dsa.js +17 -0
- package/dist/categories/dsa.js.map +1 -0
- package/dist/categories/helpers.d.ts +50 -0
- package/dist/categories/helpers.d.ts.map +1 -0
- package/dist/categories/helpers.js +127 -0
- package/dist/categories/helpers.js.map +1 -0
- package/dist/categories/implicit-rejection.d.ts +29 -0
- package/dist/categories/implicit-rejection.d.ts.map +1 -0
- package/dist/categories/implicit-rejection.js +126 -0
- package/dist/categories/implicit-rejection.js.map +1 -0
- package/dist/categories/index.d.ts +30 -0
- package/dist/categories/index.d.ts.map +1 -0
- package/dist/categories/index.js +33 -0
- package/dist/categories/index.js.map +1 -0
- package/dist/categories/kat.d.ts +21 -0
- package/dist/categories/kat.d.ts.map +1 -0
- package/dist/categories/kat.js +173 -0
- package/dist/categories/kat.js.map +1 -0
- package/dist/categories/robustness.d.ts +15 -0
- package/dist/categories/robustness.d.ts.map +1 -0
- package/dist/categories/robustness.js +98 -0
- package/dist/categories/robustness.js.map +1 -0
- package/dist/categories/signature.d.ts +29 -0
- package/dist/categories/signature.d.ts.map +1 -0
- package/dist/categories/signature.js +259 -0
- package/dist/categories/signature.js.map +1 -0
- package/dist/categories/sizes.d.ts +23 -0
- package/dist/categories/sizes.d.ts.map +1 -0
- package/dist/categories/sizes.js +150 -0
- package/dist/categories/sizes.js.map +1 -0
- package/dist/categories/slh-dsa.d.ts +23 -0
- package/dist/categories/slh-dsa.d.ts.map +1 -0
- package/dist/categories/slh-dsa.js +23 -0
- package/dist/categories/slh-dsa.js.map +1 -0
- package/dist/categories/timing.d.ts +16 -0
- package/dist/categories/timing.d.ts.map +1 -0
- package/dist/categories/timing.js +98 -0
- package/dist/categories/timing.js.map +1 -0
- package/dist/categories/types.d.ts +68 -0
- package/dist/categories/types.d.ts.map +1 -0
- package/dist/categories/types.js +31 -0
- package/dist/categories/types.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +181 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +96 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +169 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +115 -0
- package/dist/protocol.js.map +1 -0
- package/dist/report.d.ts +48 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +79 -0
- package/dist/report.js.map +1 -0
- package/dist/runner.d.ts +129 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +305 -0
- package/dist/runner.js.map +1 -0
- package/dist/sizes.d.ts +84 -0
- package/dist/sizes.d.ts.map +1 -0
- package/dist/sizes.js +214 -0
- package/dist/sizes.js.map +1 -0
- package/dist/vectors.d.ts +69 -0
- package/dist/vectors.d.ts.map +1 -0
- package/dist/vectors.js +198 -0
- package/dist/vectors.js.map +1 -0
- package/package.json +43 -0
- package/vectors/README.md +83 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic signature self-consistency category (FIPS 204 ML-DSA, FIPS 205
|
|
3
|
+
* SLH-DSA).
|
|
4
|
+
*
|
|
5
|
+
* Both schemes expose the same black-box surface — keygen, sign, verify — so a
|
|
6
|
+
* single driver covers them. Signing is randomized (hedged) by default, so we
|
|
7
|
+
* cannot assert exact signature bytes without official vectors; but several
|
|
8
|
+
* properties hold for any conforming implementation and need no external data:
|
|
9
|
+
*
|
|
10
|
+
* - sizes: pk/sk lengths match the parameter set; signature length
|
|
11
|
+
* matches the fixed encoding.
|
|
12
|
+
* - sign-then-verify: verify(pk, msg, sign(sk, msg)) === true, over N msgs.
|
|
13
|
+
* - tamper-message: verify(pk, msg', sig) === false when msg' != msg.
|
|
14
|
+
* - tamper-signature: verify(pk, msg, flip-a-bit(sig)) === false.
|
|
15
|
+
* - wrong-length verify input is rejected with a defined error (AF-05).
|
|
16
|
+
* - signing-mode (advisory): detect whether sign(sk, msg) is deterministic or
|
|
17
|
+
* hedged by signing one fixed message twice and comparing. BOTH are valid;
|
|
18
|
+
* this never fails — it only surfaces the observed behavior.
|
|
19
|
+
*
|
|
20
|
+
* Exact-value KAT (sigVer vectors) is handled separately by the kat category.
|
|
21
|
+
*/
|
|
22
|
+
import { fail, pass, rollUp, skip, } from "./types.js";
|
|
23
|
+
import { flipBitB64, zerosB64 } from "./helpers.js";
|
|
24
|
+
import { fromB64, toB64 } from "../protocol.js";
|
|
25
|
+
import { asSignatureSizes } from "../sizes.js";
|
|
26
|
+
const BUG_SIZE = "AF-05";
|
|
27
|
+
/**
|
|
28
|
+
* Build a signature category bound to a family. The same logic drives ML-DSA
|
|
29
|
+
* and SLH-DSA; only the family tag on the wire requests differs.
|
|
30
|
+
*/
|
|
31
|
+
export function makeSignatureCategory(name, family) {
|
|
32
|
+
return async (ctx) => {
|
|
33
|
+
const d = asSignatureSizes(ctx.sizes);
|
|
34
|
+
if (!d || d.family !== family) {
|
|
35
|
+
return {
|
|
36
|
+
category: name,
|
|
37
|
+
status: "skip",
|
|
38
|
+
checks: [],
|
|
39
|
+
summary: `${name} category applies only to ${family} parameter sets`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return runSignature(name, family, d, ctx);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async function runSignature(name, family, d, ctx) {
|
|
46
|
+
const param = d.id;
|
|
47
|
+
const checks = [];
|
|
48
|
+
const msgs = makeMessages(ctx.iterations);
|
|
49
|
+
// Keygen once; reuse the key pair across messages.
|
|
50
|
+
let pkB64;
|
|
51
|
+
let skB64;
|
|
52
|
+
try {
|
|
53
|
+
const kg = await ctx.runner.send({ family, param, op: "keygen" });
|
|
54
|
+
if (kg.ok !== true || !("pk" in kg) || !("sk" in kg)) {
|
|
55
|
+
return wrap(name, checks, [fail("keygen", `${family} keygen did not return pk/sk`)]);
|
|
56
|
+
}
|
|
57
|
+
pkB64 = kg.pk;
|
|
58
|
+
skB64 = kg.sk;
|
|
59
|
+
const pk = fromB64(pkB64);
|
|
60
|
+
const sk = fromB64(skB64);
|
|
61
|
+
checks.push(pk.length === d.publicKey
|
|
62
|
+
? pass("pk-length", `verification key ${pk.length} bytes (expected ${d.publicKey})`, BUG_SIZE)
|
|
63
|
+
: fail("pk-length", `verification key ${pk.length} bytes, expected ${d.publicKey}`, BUG_SIZE));
|
|
64
|
+
checks.push(sk.length === d.secretKey
|
|
65
|
+
? pass("sk-length", `signing key ${sk.length} bytes (expected ${d.secretKey})`, BUG_SIZE)
|
|
66
|
+
: fail("sk-length", `signing key ${sk.length} bytes, expected ${d.secretKey}`, BUG_SIZE));
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
return wrap(name, checks, [fail("keygen", `harness error: ${err.message}`)]);
|
|
70
|
+
}
|
|
71
|
+
// --- Round-trips. Each message's sign is independent, so we PIPELINE the
|
|
72
|
+
// sign requests (bounded concurrency), then process verdicts. Verify probes
|
|
73
|
+
// for a given message are independent across messages too. ----------------
|
|
74
|
+
let signed;
|
|
75
|
+
try {
|
|
76
|
+
signed = await ctx.runner.sendMany(msgs.map((msg) => ({ family, param, op: "sign", sk: skB64, msg })), ctx.pipelineDepth ?? 16);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
return wrap(name, checks, [fail("sign", `harness error: ${err.message}`)]);
|
|
80
|
+
}
|
|
81
|
+
let goodVerify = 0;
|
|
82
|
+
let tamperMsgCaught = 0;
|
|
83
|
+
let tamperSigCaught = 0;
|
|
84
|
+
let sigLenOk = 0;
|
|
85
|
+
let attempts = 0;
|
|
86
|
+
for (let i = 0; i < msgs.length; i++) {
|
|
87
|
+
const msgB64 = msgs[i];
|
|
88
|
+
const s = signed[i];
|
|
89
|
+
attempts++;
|
|
90
|
+
if (s.ok !== true || !("sig" in s)) {
|
|
91
|
+
checks.push(fail(`sign[${i}]`, "sign did not return a signature"));
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const sigB64 = s.sig;
|
|
95
|
+
const sig = fromB64(sigB64);
|
|
96
|
+
if (sig.length === d.signature) {
|
|
97
|
+
sigLenOk++;
|
|
98
|
+
}
|
|
99
|
+
else if (i < 3) {
|
|
100
|
+
checks.push(fail(`sig-length[${i}]`, `signature ${sig.length} bytes, expected ${d.signature}`, BUG_SIZE));
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
// The three verify probes for this message are independent → pipeline them.
|
|
104
|
+
const tamperedMsg = flipBitB64(msgB64.length > 0 ? msgB64 : toB64(new Uint8Array([0])), 0, 1);
|
|
105
|
+
const tamperedSig = flipBitB64(sigB64, sig.length >> 1, 3);
|
|
106
|
+
const [good, badMsg, badSig] = await ctx.runner.sendMany([
|
|
107
|
+
{ family, param, op: "verify", pk: pkB64, msg: msgB64, sig: sigB64 },
|
|
108
|
+
{ family, param, op: "verify", pk: pkB64, msg: tamperedMsg, sig: sigB64 },
|
|
109
|
+
{ family, param, op: "verify", pk: pkB64, msg: msgB64, sig: tamperedSig },
|
|
110
|
+
], ctx.pipelineDepth ?? 16);
|
|
111
|
+
if (verdict(good)) {
|
|
112
|
+
goodVerify++;
|
|
113
|
+
}
|
|
114
|
+
else if (i < 3) {
|
|
115
|
+
checks.push(fail(`verify[${i}]`, "a freshly produced signature failed to verify"));
|
|
116
|
+
}
|
|
117
|
+
if (!verdict(badMsg)) {
|
|
118
|
+
tamperMsgCaught++;
|
|
119
|
+
}
|
|
120
|
+
else if (i < 3) {
|
|
121
|
+
checks.push(fail(`tamper-msg[${i}]`, "signature verified against a different message"));
|
|
122
|
+
}
|
|
123
|
+
if (!verdict(badSig)) {
|
|
124
|
+
tamperSigCaught++;
|
|
125
|
+
}
|
|
126
|
+
else if (i < 3) {
|
|
127
|
+
checks.push(fail(`tamper-sig[${i}]`, "a bit-flipped signature still verified"));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
checks.push(fail(`verify[${i}]`, `harness error: ${err.message}`));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (attempts > 0) {
|
|
135
|
+
if (goodVerify === attempts) {
|
|
136
|
+
checks.push(pass("sign-verify", `${goodVerify}/${attempts} signatures verified`));
|
|
137
|
+
}
|
|
138
|
+
if (tamperMsgCaught === attempts) {
|
|
139
|
+
checks.push(pass("tamper-msg", `${tamperMsgCaught}/${attempts} altered-message forgeries rejected`));
|
|
140
|
+
}
|
|
141
|
+
if (tamperSigCaught === attempts) {
|
|
142
|
+
checks.push(pass("tamper-sig", `${tamperSigCaught}/${attempts} altered-signature forgeries rejected`));
|
|
143
|
+
}
|
|
144
|
+
if (sigLenOk === attempts) {
|
|
145
|
+
checks.push(pass("sig-length", `all ${sigLenOk} signatures had the expected ${d.signature} bytes`, BUG_SIZE));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// --- Advisory: deterministic vs hedged signing ---------------------------
|
|
149
|
+
await probeSigningMode(checks, ctx, family, param, skB64, pkB64);
|
|
150
|
+
// --- Negative: wrong-length verify inputs must be rejected cleanly -------
|
|
151
|
+
await expectVerifyReject(checks, "verify-pk-too-short", () => ctx.runner.send({
|
|
152
|
+
family,
|
|
153
|
+
param,
|
|
154
|
+
op: "verify",
|
|
155
|
+
pk: zerosB64(d.publicKey - 1),
|
|
156
|
+
msg: toB64(new Uint8Array([1, 2, 3])),
|
|
157
|
+
sig: zerosB64(d.signature),
|
|
158
|
+
}));
|
|
159
|
+
await expectVerifyReject(checks, "verify-sig-too-long", () => ctx.runner.send({
|
|
160
|
+
family,
|
|
161
|
+
param,
|
|
162
|
+
op: "verify",
|
|
163
|
+
pk: pkB64,
|
|
164
|
+
msg: toB64(new Uint8Array([1, 2, 3])),
|
|
165
|
+
sig: zerosB64(d.signature + 1),
|
|
166
|
+
}));
|
|
167
|
+
return wrap(name, checks, []);
|
|
168
|
+
}
|
|
169
|
+
function verdict(resp) {
|
|
170
|
+
if (resp.ok !== true || !("valid" in resp)) {
|
|
171
|
+
throw new Error("verify did not return a 'valid' verdict");
|
|
172
|
+
}
|
|
173
|
+
return resp.valid;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Advisory probe: sign one fixed message twice and report whether the SUT is
|
|
177
|
+
* deterministic (identical signatures) or hedged (differing signatures). BOTH
|
|
178
|
+
* are FIPS-conforming, so this NEVER fails — it records a `skip`-status note (so
|
|
179
|
+
* it cannot affect the verdict) describing the observed behavior. We also
|
|
180
|
+
* confirm both signatures verify, which IS asserted.
|
|
181
|
+
*/
|
|
182
|
+
async function probeSigningMode(checks, ctx, family, param, skB64, pkB64) {
|
|
183
|
+
const msgB64 = toB64(new Uint8Array([0x73, 0x69, 0x67, 0x6d, 0x6f, 0x64, 0x65])); // "sigmode"
|
|
184
|
+
try {
|
|
185
|
+
const [a, b] = await ctx.runner.sendMany([
|
|
186
|
+
{ family, param, op: "sign", sk: skB64, msg: msgB64 },
|
|
187
|
+
{ family, param, op: "sign", sk: skB64, msg: msgB64 },
|
|
188
|
+
],
|
|
189
|
+
// Keep these two strictly ordered/serial-equivalent is unnecessary; they
|
|
190
|
+
// are independent. A depth of 2 is fine.
|
|
191
|
+
2);
|
|
192
|
+
if (a.ok !== true || !("sig" in a) || b.ok !== true || !("sig" in b)) {
|
|
193
|
+
checks.push(skip("signing-mode", "could not obtain two signatures to compare (advisory)"));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const deterministic = a.sig === b.sig;
|
|
197
|
+
checks.push(skip("signing-mode", deterministic
|
|
198
|
+
? "advisory: sign(sk, msg) is DETERMINISTIC (identical signatures for a repeated message)"
|
|
199
|
+
: "advisory: sign(sk, msg) is HEDGED/randomized (signatures differ across calls)"));
|
|
200
|
+
// Both must still verify — this part IS asserted.
|
|
201
|
+
const [va, vb] = await ctx.runner.sendMany([
|
|
202
|
+
{ family, param, op: "verify", pk: pkB64, msg: msgB64, sig: a.sig },
|
|
203
|
+
{ family, param, op: "verify", pk: pkB64, msg: msgB64, sig: b.sig },
|
|
204
|
+
], 2);
|
|
205
|
+
if (verdict(va) && verdict(vb)) {
|
|
206
|
+
checks.push(pass("signing-mode-verify", "both repeated-message signatures verify"));
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
checks.push(fail("signing-mode-verify", "a repeated-message signature failed to verify"));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
checks.push(skip("signing-mode", `advisory probe could not run: ${err.message}`));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function wrap(name, checks, extra) {
|
|
217
|
+
const all = [...checks, ...extra];
|
|
218
|
+
const status = rollUp(all);
|
|
219
|
+
return {
|
|
220
|
+
category: name,
|
|
221
|
+
status,
|
|
222
|
+
checks: all,
|
|
223
|
+
summary: status === "pass"
|
|
224
|
+
? `${name} sign/verify self-consistency holds`
|
|
225
|
+
: `${all.filter((c) => c.status === "fail").length} ${name} issue(s)`,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
async function expectVerifyReject(checks, name, op) {
|
|
229
|
+
try {
|
|
230
|
+
const resp = await op();
|
|
231
|
+
if (resp.ok === false) {
|
|
232
|
+
checks.push(pass(name, `rejected with defined error: ${resp.code}`, BUG_SIZE));
|
|
233
|
+
}
|
|
234
|
+
else if ("valid" in resp && resp.valid === false) {
|
|
235
|
+
// Returning a false verdict for malformed input is also acceptable.
|
|
236
|
+
checks.push(pass(name, "wrong-length input verified as false (acceptable)", BUG_SIZE));
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
checks.push(fail(name, "SUT accepted a wrong-length verify input and verified true", BUG_SIZE));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
checks.push(fail(name, `SUT crashed/hung on wrong-length verify input: ${err.message}`, BUG_SIZE));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/** Deterministic, varied messages of assorted lengths (incl. empty). */
|
|
247
|
+
function makeMessages(n) {
|
|
248
|
+
const out = [];
|
|
249
|
+
const count = Math.max(1, Math.min(n, 16));
|
|
250
|
+
for (let i = 0; i < count; i++) {
|
|
251
|
+
const len = (i * 7) % 33; // 0..32 varying lengths
|
|
252
|
+
const bytes = new Uint8Array(len);
|
|
253
|
+
for (let j = 0; j < len; j++)
|
|
254
|
+
bytes[j] = (i * 31 + j * 17) & 0xff;
|
|
255
|
+
out.push(toB64(bytes));
|
|
256
|
+
}
|
|
257
|
+
return out;
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=signature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature.js","sourceRoot":"","sources":["../../src/categories/signature.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sizes/format category — AF-05 family (ML-KEM).
|
|
3
|
+
*
|
|
4
|
+
* Two complementary checks:
|
|
5
|
+
*
|
|
6
|
+
* A. Positive — emitted artifacts have the standardized byte lengths.
|
|
7
|
+
* keygen pk/sk, encaps ct/ss, decaps ss must match the parameter set's
|
|
8
|
+
* sizes from the public size table (the only constants we trust).
|
|
9
|
+
*
|
|
10
|
+
* B. Negative — the SUT rejects wrong-length inputs with a *defined error*,
|
|
11
|
+
* not a crash and not a silent success. We feed:
|
|
12
|
+
* - a too-short and too-long public key to encaps,
|
|
13
|
+
* - a too-short and too-long ciphertext to decaps,
|
|
14
|
+
* - a too-short secret key to decaps.
|
|
15
|
+
* Each must yield a protocol `error` response (ok:false) OR be otherwise
|
|
16
|
+
* cleanly handled; accepting it and returning a normal result is a fail.
|
|
17
|
+
*
|
|
18
|
+
* AF-05 is size/format confusion: an implementation that doesn't length-check
|
|
19
|
+
* its inputs can read out of bounds or accept malformed material.
|
|
20
|
+
*/
|
|
21
|
+
import { type Category } from "./types.js";
|
|
22
|
+
export declare const sizes: Category;
|
|
23
|
+
//# sourceMappingURL=sizes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sizes.d.ts","sourceRoot":"","sources":["../../src/categories/sizes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,QAAQ,EAAuD,MAAM,YAAY,CAAC;AAahG,eAAO,MAAM,KAAK,EAAE,QA4HnB,CAAC"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sizes/format category — AF-05 family (ML-KEM).
|
|
3
|
+
*
|
|
4
|
+
* Two complementary checks:
|
|
5
|
+
*
|
|
6
|
+
* A. Positive — emitted artifacts have the standardized byte lengths.
|
|
7
|
+
* keygen pk/sk, encaps ct/ss, decaps ss must match the parameter set's
|
|
8
|
+
* sizes from the public size table (the only constants we trust).
|
|
9
|
+
*
|
|
10
|
+
* B. Negative — the SUT rejects wrong-length inputs with a *defined error*,
|
|
11
|
+
* not a crash and not a silent success. We feed:
|
|
12
|
+
* - a too-short and too-long public key to encaps,
|
|
13
|
+
* - a too-short and too-long ciphertext to decaps,
|
|
14
|
+
* - a too-short secret key to decaps.
|
|
15
|
+
* Each must yield a protocol `error` response (ok:false) OR be otherwise
|
|
16
|
+
* cleanly handled; accepting it and returning a normal result is a fail.
|
|
17
|
+
*
|
|
18
|
+
* AF-05 is size/format confusion: an implementation that doesn't length-check
|
|
19
|
+
* its inputs can read out of bounds or accept malformed material.
|
|
20
|
+
*/
|
|
21
|
+
import { fail, pass, rollUp } from "./types.js";
|
|
22
|
+
import { kemDecapsRaw, kemEncapsRaw, kemKeygen, requireKem, UnexpectedResponse, zerosB64, } from "./helpers.js";
|
|
23
|
+
import { toB64 } from "../protocol.js";
|
|
24
|
+
const BUG = "AF-05";
|
|
25
|
+
export const sizes = async (ctx) => {
|
|
26
|
+
const checks = [];
|
|
27
|
+
if (ctx.sizes.family !== "ml-kem") {
|
|
28
|
+
return {
|
|
29
|
+
category: "sizes",
|
|
30
|
+
status: "skip",
|
|
31
|
+
bugClass: BUG,
|
|
32
|
+
checks: [],
|
|
33
|
+
summary: "size checks for ML-DSA live in the dsa category",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const km = requireKem(ctx.sizes);
|
|
37
|
+
const param = km.id;
|
|
38
|
+
// --- A. Positive: emitted lengths -----------------------------------------
|
|
39
|
+
let pkB64;
|
|
40
|
+
try {
|
|
41
|
+
const { pk, sk } = await kemKeygen(ctx.runner, param);
|
|
42
|
+
pkB64 = toB64(pk);
|
|
43
|
+
checks.push(pk.length === km.publicKey
|
|
44
|
+
? pass("pk-length", `public key is ${pk.length} bytes (expected ${km.publicKey})`, BUG)
|
|
45
|
+
: fail("pk-length", `public key is ${pk.length} bytes, expected ${km.publicKey}`, BUG));
|
|
46
|
+
checks.push(sk.length === km.secretKey
|
|
47
|
+
? pass("sk-length", `secret key is ${sk.length} bytes (expected ${km.secretKey})`, BUG)
|
|
48
|
+
: fail("sk-length", `secret key is ${sk.length} bytes, expected ${km.secretKey}`, BUG));
|
|
49
|
+
// encaps ct/ss lengths
|
|
50
|
+
const enc = await ctx.runner.send({ family: "ml-kem", param, op: "encaps", pk: pkB64 });
|
|
51
|
+
if (enc.ok === true && "ct" in enc && "ss" in enc) {
|
|
52
|
+
const ct = Buffer.from(enc.ct, "base64");
|
|
53
|
+
const ss = Buffer.from(enc.ss, "base64");
|
|
54
|
+
checks.push(ct.length === km.ciphertext
|
|
55
|
+
? pass("ct-length", `ciphertext is ${ct.length} bytes (expected ${km.ciphertext})`, BUG)
|
|
56
|
+
: fail("ct-length", `ciphertext is ${ct.length} bytes, expected ${km.ciphertext}`, BUG));
|
|
57
|
+
checks.push(ss.length === km.sharedSecret
|
|
58
|
+
? pass("ss-length", `shared secret is ${ss.length} bytes (expected ${km.sharedSecret})`, BUG)
|
|
59
|
+
: fail("ss-length", `shared secret is ${ss.length} bytes, expected ${km.sharedSecret}`, BUG));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
checks.push(fail("encaps-shape", "encaps did not return ct/ss for a valid public key", BUG));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
const detail = err instanceof UnexpectedResponse
|
|
67
|
+
? `SUT returned an unexpected response: ${err.message}`
|
|
68
|
+
: `harness error: ${err.message}`;
|
|
69
|
+
checks.push(fail("positive-sizes", detail, BUG));
|
|
70
|
+
pkB64 = "";
|
|
71
|
+
}
|
|
72
|
+
// --- B. Negative: wrong-length inputs must be rejected cleanly -------------
|
|
73
|
+
// Wrong-length public key to encaps.
|
|
74
|
+
await expectReject(checks, "encaps-pk-too-short", () => kemEncapsRaw(ctx.runner, param, zerosB64(km.publicKey - 1)));
|
|
75
|
+
await expectReject(checks, "encaps-pk-too-long", () => kemEncapsRaw(ctx.runner, param, zerosB64(km.publicKey + 1)));
|
|
76
|
+
// Wrong-length ciphertext to decaps (use a valid-length sk of zeros).
|
|
77
|
+
const skZeros = zerosB64(km.secretKey);
|
|
78
|
+
await expectReject(checks, "decaps-ct-too-short", () => kemDecapsRaw(ctx.runner, param, skZeros, zerosB64(km.ciphertext - 1)));
|
|
79
|
+
await expectReject(checks, "decaps-ct-too-long", () => kemDecapsRaw(ctx.runner, param, skZeros, zerosB64(km.ciphertext + 1)));
|
|
80
|
+
// Wrong-length secret key to decaps (use a valid-length ct of zeros).
|
|
81
|
+
await expectReject(checks, "decaps-sk-too-short", () => kemDecapsRaw(ctx.runner, param, zerosB64(km.secretKey - 1), zerosB64(km.ciphertext)));
|
|
82
|
+
// --- C. FIPS 203 §7.2 encapsulation-key modulus-range check ---------------
|
|
83
|
+
// A correctly-SIZED ek whose t̂ coefficients are NOT reduced mod q (< 3329)
|
|
84
|
+
// must be rejected: §7.2 requires encaps to perform the "modulus check"
|
|
85
|
+
// (ek must round-trip through ByteEncode₁₂/ByteDecode₁₂). The length checks
|
|
86
|
+
// above do NOT catch this — an ek with an out-of-range coefficient still has
|
|
87
|
+
// the right byte length. We take a VALID ek from keygen and force its first
|
|
88
|
+
// 12-bit coefficient to 0xFFF (4095 ≥ 3329) while preserving the length, then
|
|
89
|
+
// require encaps to reject it with a defined error. We assert NO crypto bytes.
|
|
90
|
+
if (pkB64.length > 0) {
|
|
91
|
+
await expectReject(checks, "encaps-ek-coeff-out-of-range", () => kemEncapsRaw(ctx.runner, param, outOfRangeEk(pkB64)));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
checks.push(fail("encaps-ek-coeff-out-of-range", "could not obtain a valid ek from keygen to build the modulus-range probe", BUG));
|
|
95
|
+
}
|
|
96
|
+
const status = rollUp(checks);
|
|
97
|
+
return {
|
|
98
|
+
category: "sizes",
|
|
99
|
+
status,
|
|
100
|
+
bugClass: BUG,
|
|
101
|
+
checks,
|
|
102
|
+
summary: status === "pass"
|
|
103
|
+
? "all artifact lengths correct; wrong-length inputs rejected"
|
|
104
|
+
: `${checks.filter((c) => c.status === "fail").length} size/format issue(s)`,
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Build a same-length-but-out-of-range encapsulation key from a valid one.
|
|
109
|
+
*
|
|
110
|
+
* FIPS 203 packs t̂ with ByteEncode₁₂: each consecutive 3 bytes [b0,b1,b2] hold
|
|
111
|
+
* two 12-bit little-endian coefficients
|
|
112
|
+
* d0 = b0 | ((b1 & 0x0F) << 8)
|
|
113
|
+
* d1 = (b1 >> 4) | (b2 << 4)
|
|
114
|
+
* We set the FIRST coefficient d0 to 0xFFF (4095), which is ≥ q (3329) and thus
|
|
115
|
+
* NOT a valid reduced coefficient — this is the classic "ek not reduced mod q"
|
|
116
|
+
* malleability. The byte length is unchanged, so only a real §7.2 modulus check
|
|
117
|
+
* (not a length check) catches it. We touch only b0/b1, leaving everything else
|
|
118
|
+
* (including ρ) intact, so the ek stays structurally well-formed apart from the
|
|
119
|
+
* single out-of-range coefficient. No cryptographic values are fabricated.
|
|
120
|
+
*/
|
|
121
|
+
function outOfRangeEk(ekB64) {
|
|
122
|
+
const buf = Buffer.from(ekB64, "base64");
|
|
123
|
+
if (buf.length >= 2) {
|
|
124
|
+
buf[0] = 0xff; // low 8 bits of d0
|
|
125
|
+
buf[1] = buf[1] | 0x0f; // high 4 bits of d0 -> d0 = 0xFFF = 4095
|
|
126
|
+
}
|
|
127
|
+
return buf.toString("base64");
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Run an operation that SHOULD be rejected. A clean protocol `error` (ok:false)
|
|
131
|
+
* passes. A normal success (the SUT accepted a wrong-length input) fails. A
|
|
132
|
+
* harness error such as a crash or timeout also fails — a conforming SUT must
|
|
133
|
+
* reject gracefully, not die.
|
|
134
|
+
*/
|
|
135
|
+
async function expectReject(checks, name, op) {
|
|
136
|
+
try {
|
|
137
|
+
const resp = await op();
|
|
138
|
+
if (resp.ok === false) {
|
|
139
|
+
checks.push(pass(name, `rejected with defined error: ${resp.code} (${resp.message})`, BUG));
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
checks.push(fail(name, "SUT accepted a wrong-length input and returned a success result", BUG));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
checks.push(fail(name, `SUT crashed/hung on a wrong-length input instead of returning a defined error: ` +
|
|
147
|
+
`${err.message}`, BUG));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=sizes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sizes.js","sourceRoot":"","sources":["../../src/categories/sizes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SLH-DSA self-consistency category (FIPS 205).
|
|
3
|
+
*
|
|
4
|
+
* SLH-DSA (the standardized SPHINCS+) presents the same black-box surface as
|
|
5
|
+
* ML-DSA — keygen / sign / verify — so it reuses the shared signature driver
|
|
6
|
+
* in signature.ts with the family fixed to "slh-dsa". It covers, for each of
|
|
7
|
+
* the 12 standardized parameter sets:
|
|
8
|
+
* - pk/sk/sig size conformance (FIPS 205 Table 2),
|
|
9
|
+
* - sign→verify correctness round-trips,
|
|
10
|
+
* - verify rejects a tampered signature and a wrong message,
|
|
11
|
+
* - a deterministic-vs-hedged signing advisory probe (SLH-DSA supports both),
|
|
12
|
+
* - wrong-length verify inputs rejected with a defined error (AF-05).
|
|
13
|
+
*
|
|
14
|
+
* No external vectors are needed for self-consistency; exact-value KAT would
|
|
15
|
+
* come from official ACVP files via the kat category. We assert NO crypto bytes.
|
|
16
|
+
*
|
|
17
|
+
* Out of scope: SP 800-208 stateful hash signatures (LMS / XMSS / HSS). Those
|
|
18
|
+
* require state-management guarantees a stateless request/response harness
|
|
19
|
+
* cannot model; see README.md.
|
|
20
|
+
*/
|
|
21
|
+
import type { Category } from "./types.js";
|
|
22
|
+
export declare const slhDsa: Category;
|
|
23
|
+
//# sourceMappingURL=slh-dsa.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slh-dsa.d.ts","sourceRoot":"","sources":["../../src/categories/slh-dsa.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,eAAO,MAAM,MAAM,EAAE,QAAsD,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SLH-DSA self-consistency category (FIPS 205).
|
|
3
|
+
*
|
|
4
|
+
* SLH-DSA (the standardized SPHINCS+) presents the same black-box surface as
|
|
5
|
+
* ML-DSA — keygen / sign / verify — so it reuses the shared signature driver
|
|
6
|
+
* in signature.ts with the family fixed to "slh-dsa". It covers, for each of
|
|
7
|
+
* the 12 standardized parameter sets:
|
|
8
|
+
* - pk/sk/sig size conformance (FIPS 205 Table 2),
|
|
9
|
+
* - sign→verify correctness round-trips,
|
|
10
|
+
* - verify rejects a tampered signature and a wrong message,
|
|
11
|
+
* - a deterministic-vs-hedged signing advisory probe (SLH-DSA supports both),
|
|
12
|
+
* - wrong-length verify inputs rejected with a defined error (AF-05).
|
|
13
|
+
*
|
|
14
|
+
* No external vectors are needed for self-consistency; exact-value KAT would
|
|
15
|
+
* come from official ACVP files via the kat category. We assert NO crypto bytes.
|
|
16
|
+
*
|
|
17
|
+
* Out of scope: SP 800-208 stateful hash signatures (LMS / XMSS / HSS). Those
|
|
18
|
+
* require state-management guarantees a stateless request/response harness
|
|
19
|
+
* cannot model; see README.md.
|
|
20
|
+
*/
|
|
21
|
+
import { makeSignatureCategory } from "./signature.js";
|
|
22
|
+
export const slhDsa = makeSignatureCategory("slh-dsa", "slh-dsa");
|
|
23
|
+
//# sourceMappingURL=slh-dsa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slh-dsa.js","sourceRoot":"","sources":["../../src/categories/slh-dsa.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,MAAM,CAAC,MAAM,MAAM,GAAa,qBAAqB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timing category — ADVISORY ONLY (ML-KEM).
|
|
3
|
+
*
|
|
4
|
+
* Coarsely compares decapsulation wall-clock time for valid vs. invalid
|
|
5
|
+
* ciphertexts over many trials. A large, consistent difference can hint at a
|
|
6
|
+
* non-constant-time reject path (an AF-02-adjacent timing oracle).
|
|
7
|
+
*
|
|
8
|
+
* THIS IS NOT A CONFORMANCE VERDICT. Cross-process timing over stdin/stdout is
|
|
9
|
+
* dominated by IPC and scheduler noise, so the result is reported as ADVISORY
|
|
10
|
+
* and NEVER fails the overall run. Real constant-time analysis needs in-process
|
|
11
|
+
* statistical tooling (e.g. dudect), not a black-box harness. Treat any signal
|
|
12
|
+
* here as "worth a closer look", not proof.
|
|
13
|
+
*/
|
|
14
|
+
import { type Category } from "./types.js";
|
|
15
|
+
export declare const timing: Category;
|
|
16
|
+
//# sourceMappingURL=timing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../../src/categories/timing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,KAAK,QAAQ,EAA+C,MAAM,YAAY,CAAC;AAIxF,eAAO,MAAM,MAAM,EAAE,QAwEpB,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timing category — ADVISORY ONLY (ML-KEM).
|
|
3
|
+
*
|
|
4
|
+
* Coarsely compares decapsulation wall-clock time for valid vs. invalid
|
|
5
|
+
* ciphertexts over many trials. A large, consistent difference can hint at a
|
|
6
|
+
* non-constant-time reject path (an AF-02-adjacent timing oracle).
|
|
7
|
+
*
|
|
8
|
+
* THIS IS NOT A CONFORMANCE VERDICT. Cross-process timing over stdin/stdout is
|
|
9
|
+
* dominated by IPC and scheduler noise, so the result is reported as ADVISORY
|
|
10
|
+
* and NEVER fails the overall run. Real constant-time analysis needs in-process
|
|
11
|
+
* statistical tooling (e.g. dudect), not a black-box harness. Treat any signal
|
|
12
|
+
* here as "worth a closer look", not proof.
|
|
13
|
+
*/
|
|
14
|
+
import { pass, skip } from "./types.js";
|
|
15
|
+
import { flipBitB64, kemDecapsRaw, kemEncaps, kemKeygen, requireKem } from "./helpers.js";
|
|
16
|
+
import { toB64 } from "../protocol.js";
|
|
17
|
+
export const timing = async (ctx) => {
|
|
18
|
+
if (ctx.sizes.family !== "ml-kem") {
|
|
19
|
+
return {
|
|
20
|
+
category: "timing",
|
|
21
|
+
status: "skip",
|
|
22
|
+
checks: [skip("applicability", "timing probe targets ML-KEM decaps")],
|
|
23
|
+
summary: "skipped (not ML-KEM)",
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const km = requireKem(ctx.sizes);
|
|
27
|
+
const param = km.id;
|
|
28
|
+
const checks = [];
|
|
29
|
+
// Establish a single key + honest ct + one corrupted ct.
|
|
30
|
+
let skB64;
|
|
31
|
+
let honestCtB64;
|
|
32
|
+
let badCtB64;
|
|
33
|
+
try {
|
|
34
|
+
const { pk, sk } = await kemKeygen(ctx.runner, param);
|
|
35
|
+
skB64 = toB64(sk);
|
|
36
|
+
const { ct } = await kemEncaps(ctx.runner, param, toB64(pk));
|
|
37
|
+
honestCtB64 = toB64(ct);
|
|
38
|
+
badCtB64 = flipBitB64(honestCtB64, 0, 0);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return {
|
|
42
|
+
category: "timing",
|
|
43
|
+
status: "skip",
|
|
44
|
+
checks: [skip("setup", `could not set up timing probe: ${err.message}`)],
|
|
45
|
+
summary: "skipped — setup failed",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const trials = Math.max(50, Math.min(ctx.iterations * 20, 2000));
|
|
49
|
+
// Warm-up to amortize JIT/spawn effects.
|
|
50
|
+
for (let i = 0; i < 10; i++) {
|
|
51
|
+
await kemDecapsRaw(ctx.runner, param, skB64, honestCtB64);
|
|
52
|
+
await kemDecapsRaw(ctx.runner, param, skB64, badCtB64);
|
|
53
|
+
}
|
|
54
|
+
const validTimes = await measure(ctx, skB64, honestCtB64, trials, param);
|
|
55
|
+
const invalidTimes = await measure(ctx, skB64, badCtB64, trials, param);
|
|
56
|
+
const vMed = median(validTimes);
|
|
57
|
+
const iMed = median(invalidTimes);
|
|
58
|
+
const denom = Math.min(vMed, iMed) || 1;
|
|
59
|
+
const relDiff = Math.abs(vMed - iMed) / denom;
|
|
60
|
+
// Heuristic, intentionally loose threshold given cross-process noise.
|
|
61
|
+
const ADVISORY_THRESHOLD = 0.25; // 25% median difference
|
|
62
|
+
const signal = relDiff > ADVISORY_THRESHOLD;
|
|
63
|
+
const detail = `valid decaps median ${vMed.toFixed(3)}ms, invalid median ${iMed.toFixed(3)}ms ` +
|
|
64
|
+
`(rel. diff ${(relDiff * 100).toFixed(1)}%, ${trials} trials each). ` +
|
|
65
|
+
(signal
|
|
66
|
+
? "ADVISORY: noticeable timing gap between valid/invalid decaps — investigate with " +
|
|
67
|
+
"in-process constant-time tooling; cross-process timing is noisy and not conclusive."
|
|
68
|
+
: "no strong cross-process timing signal (this is NOT proof of constant-time behavior).");
|
|
69
|
+
// Always a pass/skip — never fails the run.
|
|
70
|
+
checks.push(pass("decaps-timing", detail));
|
|
71
|
+
return {
|
|
72
|
+
category: "timing",
|
|
73
|
+
status: "pass",
|
|
74
|
+
checks,
|
|
75
|
+
summary: signal
|
|
76
|
+
? `ADVISORY timing signal: ${(relDiff * 100).toFixed(1)}% median gap (not a verdict)`
|
|
77
|
+
: `no strong timing signal (${(relDiff * 100).toFixed(1)}% median gap, advisory)`,
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
async function measure(ctx, skB64, ctB64, trials, param) {
|
|
81
|
+
const out = [];
|
|
82
|
+
for (let i = 0; i < trials; i++) {
|
|
83
|
+
const t0 = performance.now();
|
|
84
|
+
await kemDecapsRaw(ctx.runner, param, skB64, ctB64);
|
|
85
|
+
out.push(performance.now() - t0);
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
function median(xs) {
|
|
90
|
+
if (xs.length === 0)
|
|
91
|
+
return 0;
|
|
92
|
+
const sorted = [...xs].sort((a, b) => a - b);
|
|
93
|
+
const mid = sorted.length >> 1;
|
|
94
|
+
return sorted.length % 2 === 0
|
|
95
|
+
? (sorted[mid - 1] + sorted[mid]) / 2
|
|
96
|
+
: sorted[mid];
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=timing.js.map
|