-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathtest_sign_hook.c
More file actions
599 lines (539 loc) · 22.1 KB
/
Copy pathtest_sign_hook.c
File metadata and controls
599 lines (539 loc) · 22.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
/*
* Copyright (c) The mldsa-native project authors
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
*/
/* References
* ==========
*
* - [FIPS204]
* FIPS 204 Module-Lattice-Based Digital Signature Standard
* National Institute of Standards and Technology
* https://csrc.nist.gov/pubs/fips/204/final
*/
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Expose the deterministic internal signing API and struct test_sign_hook_ctx
* (declared by the custom config in MLD_CONFIG_CONTEXT_PARAMETER_TYPE). */
#define MLD_BUILD_INTERNAL
#include "../../mldsa/mldsa_native.h"
#include "../notrandombytes/notrandombytes.h"
#include "expected_test_vectors.h"
#ifndef NTESTS
#define NTESTS 1000
#endif
/* Number of randomized iterations in test_restartable. Overridable from the
* build for longer/shorter runs. */
#ifndef MLD_SIGN_HOOK_ITERATIONS
/* Even if NTESTS < 10, we want to run the test at least once; so round up. */
#define MLD_SIGN_HOOK_ITERATIONS (((NTESTS) + 9) / 10)
#endif
/* Number of one-shot signing operations in test_distribution. Overridable from
* the build; bump this up for a more accurate attempts distribution. Kept
* independent of NTESTS so the distribution check has a fixed sample budget
* (see MLD_SIGN_HOOK_MIN_CHECK_N for the resulting tolerance and confidence).
*
* Targets where signing is expensive (e.g. full-system emulation) override this
* down via -DMLD_SIGN_HOOK_DIST_ITERATIONS. */
#ifndef MLD_SIGN_HOOK_DIST_ITERATIONS
#define MLD_SIGN_HOOK_DIST_ITERATIONS 2000
#endif
/* Expected mean number of signing attempts per signature, in thousandths (i.e.
* the true mean times 1000, kept integer to avoid floating point). ML-DSA
* signing is rejection sampling, so this is the mean 1/p of a geometric
* distribution and is parameter-set dependent.
*
* These values are obtained empirically: the mean over 3 x 100,000,000
* signatures, each with a fresh key (so the estimate is key-averaged, not tied
* to one key), which pins the mean to +-0.001; an independent BoringSSL
* measurement agrees to within 0.15%.
*
* They exceed the expected repetitions of 4.25 / 5.10 / 3.85 tabulated in
* @[FIPS204, Table 1], because that figure models only the first-stage
* rejection (the ||z|| and ||r0|| low-bits checks) and omits the second-stage
* @[FIPS204, Algorithm 7, line 28] checks (the ||ct0|| norm and the hint weight
* <= omega). */
#if MLD_CONFIG_PARAMETER_SET == 44
#define MLD_SIGN_HOOK_EXPECTED_RATIO_X1000 4361
#elif MLD_CONFIG_PARAMETER_SET == 65
#define MLD_SIGN_HOOK_EXPECTED_RATIO_X1000 5138
#elif MLD_CONFIG_PARAMETER_SET == 87
#define MLD_SIGN_HOOK_EXPECTED_RATIO_X1000 3906
#endif
/* Signature size for the configured parameter set. */
#define MLDSA_SIG_BYTES MLDSA_BYTES(MLD_CONFIG_PARAMETER_SET)
/* The distribution test only checks the measured attempts/signature ratio
* against the expected mean once it has enough samples for the check to be
* meaningful.
*
* At N = 2000, the relative standard error is ~2% (widest level), so the
* +-10% (100 per-mille) tolerance is a ~5-sigma band: a healthy implementation
* exceeds it (a spurious failure) with probability ~10^{-6} per level.
*
* Dedicated runs can raise N and lower MLD_SIGN_HOOK_RATIO_TOL_PERMILLE. */
#define MLD_SIGN_HOOK_MIN_CHECK_N 2000
/* Relative tolerance in per mille. Overridable from the build: dedicated
* high-sample runs tighten it (see above). */
#ifndef MLD_SIGN_HOOK_RATIO_TOL_PERMILLE
#define MLD_SIGN_HOOK_RATIO_TOL_PERMILLE 100
#endif
/* The signing hooks and this whole test exercise the internal signing API, so
* there is nothing to test when signing is disabled. */
#if !defined(MLD_CONFIG_NO_SIGN_API)
#include "decode_hex.h"
/*
* This test exercises the restartable-signing hooks enabled by
* MLD_CONFIG_SIGN_HOOK_RESUME, MLD_CONFIG_SIGN_HOOK_ATTEMPT and
* MLD_CONFIG_SIGN_HOOK_FINISH.
*
* The custom config (test/configs/test_sign_hook_config.h) only enables the
* hooks and forward-declares struct test_sign_hook_ctx; the context type and
* the three hook implementations live here. The attempt hook pauses signing --
* returning MLD_ERR_SIGNING_PAUSED -- after `attempts_per_call` uninterrupted
* attempts, recording the resume point in the context; the resume hook
* continues from there on the next call. attempts_per_call == -1 disables
* pausing (one-shot signing).
*/
/* Histogram size. Bucket i (0-based) counts signatures that took i+1 attempts;
* the last bucket also counts every signature of >= MLD_SIGN_HOOK_HIST_N
* attempts. */
#ifndef MLD_SIGN_HOOK_HIST_N
#define MLD_SIGN_HOOK_HIST_N 30
#endif
/* Statistics accumulated across all signing operations that share a context,
* maintained by the attempt and finish hooks. */
struct test_sign_hook_stats
{
uint64_t signatures; /* completed signatures (finish-hook calls) */
uint64_t attempts; /* attempts actually performed */
uint64_t histogram[MLD_SIGN_HOOK_HIST_N]; /* attempts per signature */
};
/* Per-operation state for the signing hooks, carried via the context parameter.
* The test sets attempts_per_call / record_stats before each signing operation;
* the hooks maintain the rest. */
struct test_sign_hook_ctx
{
int attempts_per_call; /* uninterrupted attempts per call before pausing;
* -1 = never pause (one-shot) */
int paused_attempt; /* attempt the next call resumes from; reset to 0 */
int final_attempt; /* attempt at which signing succeeded; -1 until
* finish runs */
int record_stats; /* if nonzero, this operation contributes to `stats`;
* lets the test count each logical signature once
* despite re-signing */
struct test_sign_hook_stats stats; /* run-wide statistics */
};
/*
* Signing hooks (declared by the config, defined here). Resume returns the
* attempt to continue from; attempt pauses after attempts_per_call
* uninterrupted attempts and otherwise counts the attempt; finish records the
* completed signature.
*/
uint16_t mld_sign_hook_resume(struct test_sign_hook_ctx *context)
{
/* Resume from where the previous call paused (0 on a fresh op). */
return (uint16_t)context->paused_attempt;
}
int mld_sign_hook_attempt(uint16_t attempt, struct test_sign_hook_ctx *context)
{
/* Having resumed at paused_attempt, run attempts_per_call attempts
* uninterrupted, then pause: when `attempt` reaches paused_attempt +
* attempts_per_call, record it as the new resume point and pause. -1 means
* never pause. */
if (context->attempts_per_call >= 0 &&
(int)attempt == context->paused_attempt + context->attempts_per_call)
{
context->paused_attempt = (int)attempt;
return 1; /* pause before this attempt */
}
/* Count only attempts that actually proceed (and only when this operation
* opted in), so the statistics are independent of how the work is split
* across calls. */
if (context->record_stats)
{
context->stats.attempts++;
}
return 0; /* proceed */
}
void mld_sign_hook_finish(uint16_t attempt, struct test_sign_hook_ctx *context)
{
if (context->record_stats)
{
/* A signature that succeeds at attempt index `attempt` took attempt + 1
* attempts; bucket it (last bucket is saturating). */
int n = (int)attempt + 1;
int bucket =
(n < MLD_SIGN_HOOK_HIST_N) ? (n - 1) : (MLD_SIGN_HOOK_HIST_N - 1);
context->stats.signatures++;
context->stats.histogram[bucket]++;
}
/* Record the successful attempt and reset the resume point so a subsequent
* operation starts fresh. */
context->final_attempt = (int)attempt;
context->paused_attempt = 0;
}
#define CHECK(x) \
do \
{ \
if (!(x)) \
{ \
fprintf(stderr, "ERROR (%s,%d)\n", __FILE__, __LINE__); \
return 1; \
} \
} while (0)
/*
* Accessors for struct test_sign_hook_ctx. The test only touches the context
* through these, so its layout can be restructured without changing the tests.
*/
/* Initialize a fresh context: zero statistics, no pending operation. */
static void test_sign_ctx_init(struct test_sign_hook_ctx *ctx)
{
memset(ctx, 0, sizeof(*ctx));
}
/* Begin a signing operation: pause every `attempts_per_call` attempts (-1 =
* never), and record statistics for this operation iff `record_stats`. A value
* of 0 would ask the attempt hook to pause before the very first attempt with
* no progress -- livelock -- so we clamp it up to 1. */
static void test_sign_ctx_begin_op(struct test_sign_hook_ctx *ctx,
int attempts_per_call, int record_stats)
{
if (attempts_per_call == 0)
{
attempts_per_call = 1;
}
ctx->attempts_per_call = attempts_per_call;
ctx->paused_attempt = 0;
ctx->final_attempt = -1;
ctx->record_stats = record_stats;
}
static uint64_t test_sign_ctx_signatures(const struct test_sign_hook_ctx *ctx)
{
return ctx->stats.signatures;
}
static uint64_t test_sign_ctx_attempts(const struct test_sign_hook_ctx *ctx)
{
return ctx->stats.attempts;
}
static uint64_t test_sign_ctx_histogram(const struct test_sign_hook_ctx *ctx,
int i)
{
return ctx->stats.histogram[i];
}
/*
* Core helper: sign (m, pre) with secret key `sk` and randomness `rnd`, pausing
* every `attempts_per_call` attempts (-1 = never pause), looping over the
* paused calls until the signature completes. The completed (fixed-size)
* signature is written to sig and -- if `expected` is non-NULL -- checked to
* equal expected/MLDSA_SIG_BYTES.
*
* `ctx` is the shared hook context: its statistics accumulate across calls, so
* the same context is threaded through every test. Statistics are recorded for
* this operation only when `record_stats` is nonzero, so each logical signature
* is counted once even though the test re-signs it several ways.
*
* Returns 0 on success, 1 on a signing error or a mismatch against `expected`.
*/
static int sign_and_compare(struct test_sign_hook_ctx *ctx,
int attempts_per_call, int record_stats,
uint8_t sig[MLDSA_SIG_BYTES],
const uint8_t *expected, const uint8_t *m,
size_t mlen, const uint8_t *pre, size_t prelen,
const uint8_t *rnd, const uint8_t *sk)
{
int rc;
test_sign_ctx_begin_op(ctx, attempts_per_call, record_stats);
for (;;)
{
rc = mld_signature_internal(sig, m, mlen, pre, prelen, rnd, sk,
0 /* externalmu */, ctx);
if (rc == 0)
{
break;
}
if (rc == MLD_ERR_SIGNING_PAUSED)
{
continue; /* resume from the recorded attempt */
}
fprintf(stderr, "ERROR: signing failed with rc=%d\n", rc);
return 1;
}
if (expected != NULL && memcmp(sig, expected, MLDSA_SIG_BYTES) != 0)
{
fprintf(stderr, "ERROR: signature mismatch (attempts_per_call=%d)\n",
attempts_per_call);
return 1;
}
return 0;
}
/*
* Build the pure-ML-DSA domain-separation prefix for context string
* `ctx`/`ctxlen` using mldsa-native's own API. Returns the prefix length, or 0
* on error.
*/
static size_t make_pre(uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES],
const uint8_t *ctx, size_t ctxlen)
{
return mld_prepare_domain_separation_prefix(pre, NULL, 0, ctx, ctxlen,
MLD_PREHASH_NONE);
}
/*
* Smoke test: run the core helper against the known test vector. Signing the
* test-vector message with the test-vector key and randomness must reproduce
* the recorded signature, both one-shot and single-step.
*/
static int test_known_answer(struct test_sign_hook_ctx *ctx)
{
uint8_t sig[MLDSA_SIG_BYTES];
uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES];
size_t prelen =
make_pre(pre, (const uint8_t *)TEST_VECTOR_CTX, TEST_VECTOR_CTX_LEN);
CHECK(prelen != 0);
/* Statistics are gathered only by the distribution test, so neither run here
* records. */
CHECK(sign_and_compare(ctx, -1, 0 /* don't record */, sig, test_vector_sig,
(const uint8_t *)TEST_VECTOR_MSG, TEST_VECTOR_MSG_LEN,
pre, prelen, test_vector_rnd, test_vector_sk) == 0);
CHECK(sign_and_compare(ctx, 1, 0 /* don't record */, sig, test_vector_sig,
(const uint8_t *)TEST_VECTOR_MSG, TEST_VECTOR_MSG_LEN,
pre, prelen, test_vector_rnd, test_vector_sk) == 0);
printf("Known-answer smoke test PASSED.\n");
return 0;
}
/*
* Restartable-signing equivalence test. Uses the fixed test-vector message and
* key; for each of `iterations` rounds, pick fresh signing randomness, produce
* the signature one-shot (the reference), then re-sign with the same randomness
* and check that we obtain the same signature both (a) single-step (one attempt
* per call) and (b) with a random number of attempts per call.
*/
static int test_restartable(struct test_sign_hook_ctx *ctx, int iterations)
{
uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES];
size_t prelen =
make_pre(pre, (const uint8_t *)TEST_VECTOR_CTX, TEST_VECTOR_CTX_LEN);
int i;
CHECK(prelen != 0);
for (i = 0; i < iterations; i++)
{
uint8_t rnd[MLDSA_RNDBYTES];
uint8_t ref_sig[MLDSA_SIG_BYTES];
uint8_t sig[MLDSA_SIG_BYTES];
uint8_t rand_byte;
int rand_apc;
/* Fresh signing randomness, chosen at runtime. The reference and the
* re-signs below all use the same message, key and randomness. */
CHECK(randombytes(rnd, sizeof(rnd)) == 0);
CHECK(randombytes(&rand_byte, 1) == 0);
/* Random attempts-per-call in [1, 4], biased toward 1 so that most
* iterations actually exercise multiple pause/resume cycles. The mean
* number of attempts per signature is ~4-5, so a uniform draw over [1, 4]
* would leave apc=3, 4 mostly completing in one call and collapsing to
* the one-shot baseline. Distribution: P(1)=1/2, P(2)=1/4, P(3)=P(4)=1/8.
*/
{
unsigned int b = (unsigned int)rand_byte % 8u;
if (b < 4u)
{
rand_apc = 1;
}
else if (b < 6u)
{
rand_apc = 2;
}
else if (b < 7u)
{
rand_apc = 3;
}
else
{
rand_apc = 4;
}
}
/* Reference signature, produced one-shot. Statistics are gathered only by
* the distribution test, so this does not record. */
CHECK(sign_and_compare(ctx, -1, 0 /* don't record */, ref_sig, NULL,
(const uint8_t *)TEST_VECTOR_MSG,
TEST_VECTOR_MSG_LEN, pre, prelen, rnd,
test_vector_sk) == 0);
/* (a) Single-step: pause after every attempt. */
CHECK(sign_and_compare(ctx, 1, 0 /* don't record */, sig, ref_sig,
(const uint8_t *)TEST_VECTOR_MSG,
TEST_VECTOR_MSG_LEN, pre, prelen, rnd,
test_vector_sk) == 0);
/* (b) Random number of attempts per call. */
CHECK(sign_and_compare(ctx, rand_apc, 0 /* don't record */, sig, ref_sig,
(const uint8_t *)TEST_VECTOR_MSG,
TEST_VECTOR_MSG_LEN, pre, prelen, rnd,
test_vector_sk) == 0);
}
printf("Restartable signing equivalence test PASSED (%d iteration(s)).\n",
iterations);
return 0;
}
/*
* Distribution test: run `iterations` uninterrupted (one-shot) signing
* operations, each with a fresh key and fresh signing randomness, recording
* statistics for every one. Drawing a new key each iteration makes the measured
* mean an estimate of the key-averaged expected attempts per signature (the
* rejection probability is mildly key-dependent via the r0- and hint-checks),
* not a single-key conditional mean. Run with a large iteration count for an
* accurate picture.
*
* This is the only test that generates keys, so it is compiled out under
* MLD_CONFIG_NO_KEYPAIR_API; the other two use the fixed test-vector key.
*/
#if !defined(MLD_CONFIG_NO_KEYPAIR_API)
static int test_distribution(struct test_sign_hook_ctx *ctx, int iterations)
{
uint8_t pre[MLD_DOMAIN_SEPARATION_MAX_BYTES];
size_t prelen =
make_pre(pre, (const uint8_t *)TEST_VECTOR_CTX, TEST_VECTOR_CTX_LEN);
int i;
CHECK(prelen != 0);
for (i = 0; i < iterations; i++)
{
uint8_t kgseed[MLDSA_SEEDBYTES];
uint8_t rnd[MLDSA_RNDBYTES];
uint8_t pk[MLDSA_PUBLICKEYBYTES(MLD_CONFIG_PARAMETER_SET)];
uint8_t sk[MLDSA_SECRETKEYBYTES(MLD_CONFIG_PARAMETER_SET)];
uint8_t sig[MLDSA_SIG_BYTES];
/* Fresh key and fresh signing randomness each iteration. keypair_internal
* takes the context parameter (MLD_CONFIG_CONTEXT_PARAMETER is set) but
* does not invoke the signing hooks, so passing `ctx` here is inert. */
CHECK(randombytes(kgseed, sizeof(kgseed)) == 0);
CHECK(mld_keypair_internal(pk, sk, kgseed, ctx) == 0);
CHECK(randombytes(rnd, sizeof(rnd)) == 0);
CHECK(sign_and_compare(ctx, -1, 1 /* record */, sig, NULL,
(const uint8_t *)TEST_VECTOR_MSG,
TEST_VECTOR_MSG_LEN, pre, prelen, rnd, sk) == 0);
}
{
/* Measured attempts/signature ratio, in thousandths (integer), against the
* expected geometric mean; both shown to three decimals. */
uint64_t a = test_sign_ctx_attempts(ctx);
uint64_t s = test_sign_ctx_signatures(ctx);
uint64_t ratio_x1000 = (s != 0) ? (1000u * a + s / 2) / s : 0;
printf(" Measured attempts/signature: %llu.%03llu (expected %d.%03d)\n",
(unsigned long long)(ratio_x1000 / 1000),
(unsigned long long)(ratio_x1000 % 1000),
MLD_SIGN_HOOK_EXPECTED_RATIO_X1000 / 1000,
MLD_SIGN_HOOK_EXPECTED_RATIO_X1000 % 1000);
/* With enough samples, check that ratio against the expected mean. All
* integer: compare 1000*attempts against EXPECTED_RATIO_X1000*signatures,
* allowing a +-TOL_PERMILLE per-mille relative band. */
if (iterations >= MLD_SIGN_HOOK_MIN_CHECK_N)
{
uint64_t lhs = 1000u * a;
uint64_t mid = (uint64_t)MLD_SIGN_HOOK_EXPECTED_RATIO_X1000 * s;
uint64_t tol = (uint64_t)MLD_SIGN_HOOK_RATIO_TOL_PERMILLE * mid / 1000u;
uint64_t diff = (lhs > mid) ? (lhs - mid) : (mid - lhs);
if (diff > tol)
{
int exp_int = MLD_SIGN_HOOK_EXPECTED_RATIO_X1000 / 1000;
int exp_frac = MLD_SIGN_HOOK_EXPECTED_RATIO_X1000 % 1000;
int tol_int = MLD_SIGN_HOOK_RATIO_TOL_PERMILLE / 10;
int tol_frac = MLD_SIGN_HOOK_RATIO_TOL_PERMILLE % 10;
/* Report the measured value on stderr too: on failure the harness
* surfaces stderr, not stdout, so include it here to make the failure
* diagnosable (and reproducible via the printed PRNG seed). */
fprintf(stderr,
"ERROR: attempts/signature ratio out of range: measured "
"%llu.%03llu, expected %d.%03d +- %d.%d%%\n",
(unsigned long long)(ratio_x1000 / 1000),
(unsigned long long)(ratio_x1000 % 1000), exp_int, exp_frac,
tol_int, tol_frac);
return 1;
}
}
}
printf("Distribution test PASSED (%d signature(s)).\n", iterations);
return 0;
}
#endif /* !MLD_CONFIG_NO_KEYPAIR_API */
/* Print the run-wide statistics accumulated in the shared context. The
* histogram is shown both numerically and as a bar chart, where each bar is
* `*` repeated round(100 * count / signatures) times (i.e. percent of all
* signatures that took that many attempts). */
static void print_stats(const struct test_sign_hook_ctx *ctx)
{
uint64_t total = test_sign_ctx_signatures(ctx);
int i;
printf("\nSigning statistics:\n");
printf(" Signatures: %llu\n", (unsigned long long)total);
printf(" Attempts: %llu\n",
(unsigned long long)test_sign_ctx_attempts(ctx));
printf(" Attempts-per-signature histogram (bar = %% of signatures):\n");
for (i = 0; i < MLD_SIGN_HOOK_HIST_N; i++)
{
uint64_t count = test_sign_ctx_histogram(ctx, i);
const char *rel = (i == MLD_SIGN_HOOK_HIST_N - 1) ? ">=" : " ";
/* Bar length: percent of all signatures, rounded to nearest integer. */
int bar = (total != 0) ? (int)((100 * count + total / 2) / total) : 0;
int j;
printf(" [%s%2d|%6llu]: ", rel, i + 1, (unsigned long long)count);
for (j = 0; j < bar; j++)
{
printf("*");
}
printf("\n");
}
}
/* Bytes of PRNG seed accepted on the command line (argv[1] = "seed=HEX"). */
#define MLD_SIGN_HOOK_SEED_BYTES 32
#if defined(main)
int main(int argc, char *argv[]);
#endif
int main(int argc, char *argv[])
{
int r = 0;
/* A single context shared across all tests, so the statistics maintained by
* the hooks accumulate over the entire run. */
struct test_sign_hook_ctx ctx;
test_sign_ctx_init(&ctx);
/* Optional argv[1] = "seed=HEX": a hex seed for the (testing-only) PRNG,
* printed so a run is reproducible by re-passing it. Absent, the default
* pi-digit seed keeps the run deterministic. */
if (argc > 1)
{
unsigned char *seed = decode_hex("seed", MLD_SIGN_HOOK_SEED_BYTES, argv[1]);
int i;
if (seed == NULL)
{
return 1; /* decode_hex already printed a usage message */
}
randombytes_seed(seed, MLD_SIGN_HOOK_SEED_BYTES);
printf("PRNG seed (hex): ");
for (i = 0; i < MLD_SIGN_HOOK_SEED_BYTES; i++)
{
printf("%02x", seed[i]);
}
printf("\n");
}
else
{
printf("PRNG seed: default (deterministic); pass seed=HEX to randomize\n");
}
r |= test_known_answer(&ctx);
r |= test_restartable(&ctx, MLD_SIGN_HOOK_ITERATIONS);
#if !defined(MLD_CONFIG_NO_KEYPAIR_API)
r |= test_distribution(&ctx, MLD_SIGN_HOOK_DIST_ITERATIONS);
#endif
if (r)
{
return 1;
}
print_stats(&ctx);
printf("\nAll good! Restartable signing matches one-shot signing.\n");
return 0;
}
#else /* !MLD_CONFIG_NO_SIGN_API */
#if defined(main)
int main(void);
#endif
int main(void)
{
printf("Signing API disabled; nothing to test.\n");
return 0;
}
#endif /* MLD_CONFIG_NO_SIGN_API */