Skip to content

Commit f300f02

Browse files
committed
[WIP] Reintroduce struct definitions for mlk_poly{mat,vec}
Signed-off-by: Hanno Becker <[email protected]>
1 parent c318c61 commit f300f02

File tree

26 files changed

+225
-200
lines changed

26 files changed

+225
-200
lines changed

.github/workflows/all.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ jobs:
4646
permissions:
4747
contents: 'read'
4848
id-token: 'write'
49-
needs: [ base, nix ]
5049
uses: ./.github/workflows/cbmc.yml
5150
secrets: inherit
5251
oqs_integration:

mlkem/src/indcpa.c

Lines changed: 84 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,11 @@
5959
* Implements @[FIPS203, Algorithm 13 (K-PKE.KeyGen), L19]
6060
*
6161
**************************************************/
62-
static void mlk_pack_pk(uint8_t r[MLKEM_INDCPA_PUBLICKEYBYTES], mlk_polyvec pk,
62+
static void mlk_pack_pk(uint8_t r[MLKEM_INDCPA_PUBLICKEYBYTES],
63+
const mlk_polyvec *pk,
6364
const uint8_t seed[MLKEM_SYMBYTES])
6465
{
65-
mlk_assert_bound_2d(pk, MLKEM_K, MLKEM_N, 0, MLKEM_Q);
66+
mlk_assert_bound_2d(pk->vec, MLKEM_K, MLKEM_N, 0, MLKEM_Q);
6667
mlk_polyvec_tobytes(r, pk);
6768
mlk_memcpy(r + MLKEM_POLYVECBYTES, seed, MLKEM_SYMBYTES);
6869
}
@@ -83,7 +84,7 @@ static void mlk_pack_pk(uint8_t r[MLKEM_INDCPA_PUBLICKEYBYTES], mlk_polyvec pk,
8384
* Implements @[FIPS203, Algorithm 14 (K-PKE.Encrypt), L2-3]
8485
*
8586
**************************************************/
86-
static void mlk_unpack_pk(mlk_polyvec pk, uint8_t seed[MLKEM_SYMBYTES],
87+
static void mlk_unpack_pk(mlk_polyvec *pk, uint8_t seed[MLKEM_SYMBYTES],
8788
const uint8_t packedpk[MLKEM_INDCPA_PUBLICKEYBYTES])
8889
{
8990
mlk_polyvec_frombytes(pk, packedpk);
@@ -108,9 +109,10 @@ static void mlk_unpack_pk(mlk_polyvec pk, uint8_t seed[MLKEM_SYMBYTES],
108109
* Implements @[FIPS203, Algorithm 13 (K-PKE.KeyGen), L20]
109110
*
110111
**************************************************/
111-
static void mlk_pack_sk(uint8_t r[MLKEM_INDCPA_SECRETKEYBYTES], mlk_polyvec sk)
112+
static void mlk_pack_sk(uint8_t r[MLKEM_INDCPA_SECRETKEYBYTES],
113+
const mlk_polyvec *sk)
112114
{
113-
mlk_assert_bound_2d(sk, MLKEM_K, MLKEM_N, 0, MLKEM_Q);
115+
mlk_assert_bound_2d(sk->vec, MLKEM_K, MLKEM_N, 0, MLKEM_Q);
114116
mlk_polyvec_tobytes(r, sk);
115117
}
116118

@@ -128,7 +130,7 @@ static void mlk_pack_sk(uint8_t r[MLKEM_INDCPA_SECRETKEYBYTES], mlk_polyvec sk)
128130
* Implements @[FIPS203, Algorithm 15 (K-PKE.Decrypt), L5]
129131
*
130132
**************************************************/
131-
static void mlk_unpack_sk(mlk_polyvec sk,
133+
static void mlk_unpack_sk(mlk_polyvec *sk,
132134
const uint8_t packedsk[MLKEM_INDCPA_SECRETKEYBYTES])
133135
{
134136
mlk_polyvec_frombytes(sk, packedsk);
@@ -149,8 +151,8 @@ static void mlk_unpack_sk(mlk_polyvec sk,
149151
* Implements @[FIPS203, Algorithm 14 (K-PKE.Encrypt), L22-23]
150152
*
151153
**************************************************/
152-
static void mlk_pack_ciphertext(uint8_t r[MLKEM_INDCPA_BYTES], mlk_polyvec b,
153-
mlk_poly *v)
154+
static void mlk_pack_ciphertext(uint8_t r[MLKEM_INDCPA_BYTES],
155+
const mlk_polyvec *b, mlk_poly *v)
154156
{
155157
mlk_polyvec_compress_du(r, b);
156158
mlk_poly_compress_dv(r + MLKEM_POLYVECCOMPRESSEDBYTES_DU, v);
@@ -170,7 +172,7 @@ static void mlk_pack_ciphertext(uint8_t r[MLKEM_INDCPA_BYTES], mlk_polyvec b,
170172
* Implements @[FIPS203, Algorithm 15 (K-PKE.Decrypt), L1-4]
171173
*
172174
**************************************************/
173-
static void mlk_unpack_ciphertext(mlk_polyvec b, mlk_poly *v,
175+
static void mlk_unpack_ciphertext(mlk_polyvec *b, mlk_poly *v,
174176
const uint8_t c[MLKEM_INDCPA_BYTES])
175177
{
176178
mlk_polyvec_decompress_du(b, c);
@@ -183,28 +185,29 @@ static void mlk_unpack_ciphertext(mlk_polyvec b, mlk_poly *v,
183185
*
184186
* We don't inline this into gen_matrix to avoid having to split the CBMC
185187
* proof for gen_matrix based on MLK_USE_NATIVE_NTT_CUSTOM_ORDER. */
186-
static void mlk_polymat_permute_bitrev_to_custom(mlk_polymat a)
188+
static void mlk_polymat_permute_bitrev_to_custom(mlk_polymat *a)
187189
__contract__(
188190
/* We don't specify that this should be a permutation, but only
189191
* that it does not change the bound established at the end of mlk_gen_matrix. */
190192
requires(memory_no_alias(a, sizeof(mlk_polymat)))
191-
requires(forall(x, 0, MLKEM_K * MLKEM_K,
192-
array_bound(a[x].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))
193+
requires(forall(x, 0, MLKEM_K, forall(y, 0, MLKEM_K,
194+
array_bound(a->vec[x].vec[y].coeffs, 0, MLKEM_N, 0, MLKEM_Q))))
193195
assigns(object_whole(a))
194-
ensures(forall(x, 0, MLKEM_K * MLKEM_K,
195-
array_bound(a[x].coeffs, 0, MLKEM_N, 0, MLKEM_Q))))
196+
ensures(forall(x, 0, MLKEM_K, forall(y, 0, MLKEM_K,
197+
array_bound(a->vec[x].vec[y].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))))
196198
{
197199
#if defined(MLK_USE_NATIVE_NTT_CUSTOM_ORDER)
198200
unsigned i;
199201
for (i = 0; i < MLKEM_K * MLKEM_K; i++)
200202
__loop__(
201203
assigns(i, object_whole(a))
202204
invariant(i <= MLKEM_K * MLKEM_K)
203-
invariant(forall(x, 0, MLKEM_K * MLKEM_K,
204-
array_bound(a[x].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))
205+
invariant(forall(x, 0, MLKEM_K, forall(y, 0, MLKEM_K,
206+
array_bound(a->vec[x].vec[y].coeffs, 0, MLKEM_N, 0, MLKEM_Q))))
205207
)
206208
{
207-
mlk_poly_permute_bitrev_to_custom(a[i].coeffs);
209+
mlk_poly_permute_bitrev_to_custom(
210+
a->vec[i / MLKEM_K].vec[i % MLKEM_K].coeffs);
208211
}
209212
#else /* MLK_USE_NATIVE_NTT_CUSTOM_ORDER */
210213
/* Nothing to do */
@@ -220,7 +223,7 @@ __contract__(
220223
*
221224
* Not static for benchmarking */
222225
MLK_INTERNAL_API
223-
void mlk_gen_matrix(mlk_polymat a, const uint8_t seed[MLKEM_SYMBYTES],
226+
void mlk_gen_matrix(mlk_polymat *a, const uint8_t seed[MLKEM_SYMBYTES],
224227
int transposed)
225228
{
226229
unsigned i, j;
@@ -253,7 +256,11 @@ void mlk_gen_matrix(mlk_polymat a, const uint8_t seed[MLKEM_SYMBYTES],
253256
}
254257
}
255258

256-
mlk_poly_rej_uniform_x4(&a[i], &a[i + 1], &a[i + 2], &a[i + 3], seed_ext);
259+
mlk_poly_rej_uniform_x4(&a->vec[i / MLKEM_K].vec[i % MLKEM_K],
260+
&a->vec[(i + 1) / MLKEM_K].vec[(i + 1) % MLKEM_K],
261+
&a->vec[(i + 2) / MLKEM_K].vec[(i + 2) % MLKEM_K],
262+
&a->vec[(i + 3) / MLKEM_K].vec[(i + 3) % MLKEM_K],
263+
seed_ext);
257264
}
258265
#else /* !MLK_CONFIG_SERIAL_FIPS202_ONLY */
259266
/* When using serial FIPS202, sample all entries individually. */
@@ -281,7 +288,7 @@ void mlk_gen_matrix(mlk_polymat a, const uint8_t seed[MLKEM_SYMBYTES],
281288
seed_ext[0][MLKEM_SYMBYTES + 1] = x;
282289
}
283290

284-
mlk_poly_rej_uniform(&a[i], seed_ext[0]);
291+
mlk_poly_rej_uniform(&a->vec[i / MLKEM_K].vec[i % MLKEM_K], seed_ext[0]);
285292
}
286293

287294
mlk_assert(i == MLKEM_K * MLKEM_K);
@@ -314,15 +321,16 @@ void mlk_gen_matrix(mlk_polymat a, const uint8_t seed[MLKEM_SYMBYTES],
314321
* Specification: Implements @[FIPS203, Section 2.4.7, Eq (2.12), (2.13)]
315322
*
316323
**************************************************/
317-
static void mlk_matvec_mul(mlk_polyvec out, const mlk_polymat a,
318-
const mlk_polyvec v, const mlk_polyvec_mulcache vc)
324+
static void mlk_matvec_mul(mlk_polyvec *out, const mlk_polymat *a,
325+
const mlk_polyvec *v, const mlk_polyvec_mulcache *vc)
319326
__contract__(
320327
requires(memory_no_alias(out, sizeof(mlk_polyvec)))
321328
requires(memory_no_alias(a, sizeof(mlk_polymat)))
322329
requires(memory_no_alias(v, sizeof(mlk_polyvec)))
323330
requires(memory_no_alias(vc, sizeof(mlk_polyvec_mulcache)))
324-
requires(forall(k0, 0, MLKEM_K * MLKEM_K,
325-
array_bound(a[k0].coeffs, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT)))
331+
requires(forall(k0, 0, MLKEM_K,
332+
forall(k1, 0, MLKEM_K,
333+
array_bound(a->vec[k0].vec[k1].coeffs, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT))))
326334
assigns(object_whole(out)))
327335
{
328336
unsigned i;
@@ -331,7 +339,7 @@ __contract__(
331339
assigns(i, object_whole(out))
332340
invariant(i <= MLKEM_K))
333341
{
334-
mlk_polyvec_basemul_acc_montgomery_cached(&out[i], &a[MLKEM_K * i], v, vc);
342+
mlk_polyvec_basemul_acc_montgomery_cached(&out->vec[i], &a->vec[i], v, vc);
335343
}
336344
}
337345

@@ -370,47 +378,49 @@ void mlk_indcpa_keypair_derand(uint8_t pk[MLKEM_INDCPA_PUBLICKEYBYTES],
370378
*/
371379
MLK_CT_TESTING_DECLASSIFY(publicseed, MLKEM_SYMBYTES);
372380

373-
mlk_gen_matrix(a, publicseed, 0 /* no transpose */);
381+
mlk_gen_matrix(&a, publicseed, 0 /* no transpose */);
374382

375383
#if MLKEM_K == 2
376-
mlk_poly_getnoise_eta1_4x(&skpv[0], &skpv[1], &e[0], &e[1], noiseseed, 0, 1,
377-
2, 3);
384+
mlk_poly_getnoise_eta1_4x(&skpv.vec[0], &skpv.vec[1], &e.vec[0], &e.vec[1],
385+
noiseseed, 0, 1, 2, 3);
378386
#elif MLKEM_K == 3
379387
/*
380388
* Only the first three output buffers are needed.
381389
* The laster parameter is a dummy that's overwritten later.
382390
*/
383-
mlk_poly_getnoise_eta1_4x(&skpv[0], &skpv[1], &skpv[2],
384-
&pkpv[0] /* irrelevant */, noiseseed, 0, 1, 2,
391+
mlk_poly_getnoise_eta1_4x(&skpv.vec[0], &skpv.vec[1], &skpv.vec[2],
392+
&pkpv.vec[0] /* irrelevant */, noiseseed, 0, 1, 2,
385393
0xFF /* irrelevant */);
386394
/* Same here */
387-
mlk_poly_getnoise_eta1_4x(&e[0], &e[1], &e[2], &pkpv[0] /* irrelevant */,
388-
noiseseed, 3, 4, 5, 0xFF /* irrelevant */);
395+
mlk_poly_getnoise_eta1_4x(&e.vec[0], &e.vec[1], &e.vec[2],
396+
&pkpv.vec[0] /* irrelevant */, noiseseed, 3, 4, 5,
397+
0xFF /* irrelevant */);
389398
#elif MLKEM_K == 4
390-
mlk_poly_getnoise_eta1_4x(&skpv[0], &skpv[1], &skpv[2], &skpv[3], noiseseed,
391-
0, 1, 2, 3);
392-
mlk_poly_getnoise_eta1_4x(&e[0], &e[1], &e[2], &e[3], noiseseed, 4, 5, 6, 7);
393-
#endif
399+
mlk_poly_getnoise_eta1_4x(&skpv.vec[0], &skpv.vec[1], &skpv.vec[2],
400+
&skpv.vec[3], noiseseed, 0, 1, 2, 3);
401+
mlk_poly_getnoise_eta1_4x(&e.vec[0], &e.vec[1], &e.vec[2], &e.vec[3],
402+
noiseseed, 4, 5, 6, 7);
403+
#endif /* MLKEM_K == 4 */
394404

395-
mlk_polyvec_ntt(skpv);
396-
mlk_polyvec_ntt(e);
405+
mlk_polyvec_ntt(&skpv);
406+
mlk_polyvec_ntt(&e);
397407

398-
mlk_polyvec_mulcache_compute(skpv_cache, skpv);
399-
mlk_matvec_mul(pkpv, a, skpv, skpv_cache);
400-
mlk_polyvec_tomont(pkpv);
408+
mlk_polyvec_mulcache_compute(&skpv_cache, &skpv);
409+
mlk_matvec_mul(&pkpv, &a, &skpv, &skpv_cache);
410+
mlk_polyvec_tomont(&pkpv);
401411

402-
mlk_polyvec_add(pkpv, e);
403-
mlk_polyvec_reduce(pkpv);
404-
mlk_polyvec_reduce(skpv);
412+
mlk_polyvec_add(&pkpv, &e);
413+
mlk_polyvec_reduce(&pkpv);
414+
mlk_polyvec_reduce(&skpv);
405415

406-
mlk_pack_sk(sk, skpv);
407-
mlk_pack_pk(pk, pkpv, publicseed);
416+
mlk_pack_sk(sk, &skpv);
417+
mlk_pack_pk(pk, &pkpv, publicseed);
408418

409419
/* Specification: Partially implements
410420
* @[FIPS203, Section 3.3, Destruction of intermediate values] */
411421
mlk_zeroize(buf, sizeof(buf));
412422
mlk_zeroize(coins_with_domain_separator, sizeof(coins_with_domain_separator));
413-
mlk_zeroize(a, sizeof(a));
423+
mlk_zeroize(&a, sizeof(a));
414424
mlk_zeroize(&e, sizeof(e));
415425
mlk_zeroize(&skpv, sizeof(skpv));
416426
mlk_zeroize(&skpv_cache, sizeof(skpv_cache));
@@ -436,7 +446,7 @@ void mlk_indcpa_enc(uint8_t c[MLKEM_INDCPA_BYTES],
436446
mlk_poly v, k, epp;
437447
mlk_polyvec_mulcache sp_cache;
438448

439-
mlk_unpack_pk(pkpv, seed, pk);
449+
mlk_unpack_pk(&pkpv, seed, pk);
440450
mlk_poly_frommsg(&k, m);
441451

442452
/*
@@ -447,44 +457,47 @@ void mlk_indcpa_enc(uint8_t c[MLKEM_INDCPA_BYTES],
447457
*/
448458
MLK_CT_TESTING_DECLASSIFY(seed, MLKEM_SYMBYTES);
449459

450-
mlk_gen_matrix(at, seed, 1 /* transpose */);
460+
mlk_gen_matrix(&at, seed, 1 /* transpose */);
451461

452462
#if MLKEM_K == 2
453-
mlk_poly_getnoise_eta1122_4x(&sp[0], &sp[1], &ep[0], &ep[1], coins, 0, 1, 2,
454-
3);
463+
mlk_poly_getnoise_eta1122_4x(&sp.vec[0], &sp.vec[1], &ep.vec[0], &ep.vec[1],
464+
coins, 0, 1, 2, 3);
455465
mlk_poly_getnoise_eta2(&epp, coins, 4);
456466
#elif MLKEM_K == 3
457467
/*
458468
* In this call, only the first three output buffers are needed.
459469
* The last parameter is a dummy that's overwritten later.
460470
*/
461-
mlk_poly_getnoise_eta1_4x(&sp[0], &sp[1], &sp[2], &b[0], coins, 0, 1, 2,
462-
0xFF);
471+
mlk_poly_getnoise_eta1_4x(&sp.vec[0], &sp.vec[1], &sp.vec[2], &b.vec[0],
472+
coins, 0, 1, 2, 0xFF);
463473
/* The fourth output buffer in this call _is_ used. */
464-
mlk_poly_getnoise_eta2_4x(&ep[0], &ep[1], &ep[2], &epp, coins, 3, 4, 5, 6);
474+
mlk_poly_getnoise_eta2_4x(&ep.vec[0], &ep.vec[1], &ep.vec[2], &epp, coins, 3,
475+
4, 5, 6);
465476
#elif MLKEM_K == 4
466-
mlk_poly_getnoise_eta1_4x(&sp[0], &sp[1], &sp[2], &sp[3], coins, 0, 1, 2, 3);
467-
mlk_poly_getnoise_eta2_4x(&ep[0], &ep[1], &ep[2], &ep[3], coins, 4, 5, 6, 7);
477+
mlk_poly_getnoise_eta1_4x(&sp.vec[0], &sp.vec[1], &sp.vec[2], &sp.vec[3],
478+
coins, 0, 1, 2, 3);
479+
mlk_poly_getnoise_eta2_4x(&ep.vec[0], &ep.vec[1], &ep.vec[2], &ep.vec[3],
480+
coins, 4, 5, 6, 7);
468481
mlk_poly_getnoise_eta2(&epp, coins, 8);
469-
#endif
482+
#endif /* MLKEM_K == 4 */
470483

471-
mlk_polyvec_ntt(sp);
484+
mlk_polyvec_ntt(&sp);
472485

473-
mlk_polyvec_mulcache_compute(sp_cache, sp);
474-
mlk_matvec_mul(b, at, sp, sp_cache);
475-
mlk_polyvec_basemul_acc_montgomery_cached(&v, pkpv, sp, sp_cache);
486+
mlk_polyvec_mulcache_compute(&sp_cache, &sp);
487+
mlk_matvec_mul(&b, &at, &sp, &sp_cache);
488+
mlk_polyvec_basemul_acc_montgomery_cached(&v, &pkpv, &sp, &sp_cache);
476489

477-
mlk_polyvec_invntt_tomont(b);
490+
mlk_polyvec_invntt_tomont(&b);
478491
mlk_poly_invntt_tomont(&v);
479492

480-
mlk_polyvec_add(b, ep);
493+
mlk_polyvec_add(&b, &ep);
481494
mlk_poly_add(&v, &epp);
482495
mlk_poly_add(&v, &k);
483496

484-
mlk_polyvec_reduce(b);
497+
mlk_polyvec_reduce(&b);
485498
mlk_poly_reduce(&v);
486499

487-
mlk_pack_ciphertext(c, b, &v);
500+
mlk_pack_ciphertext(c, &b, &v);
488501

489502
/* Specification: Partially implements
490503
* @[FIPS203, Section 3.3, Destruction of intermediate values] */
@@ -493,7 +506,7 @@ void mlk_indcpa_enc(uint8_t c[MLKEM_INDCPA_BYTES],
493506
mlk_zeroize(&sp_cache, sizeof(sp_cache));
494507
mlk_zeroize(&b, sizeof(b));
495508
mlk_zeroize(&v, sizeof(v));
496-
mlk_zeroize(at, sizeof(at));
509+
mlk_zeroize(&at, sizeof(at));
497510
mlk_zeroize(&k, sizeof(k));
498511
mlk_zeroize(&ep, sizeof(ep));
499512
mlk_zeroize(&epp, sizeof(epp));
@@ -511,12 +524,12 @@ void mlk_indcpa_dec(uint8_t m[MLKEM_INDCPA_MSGBYTES],
511524
mlk_poly v, sb;
512525
mlk_polyvec_mulcache b_cache;
513526

514-
mlk_unpack_ciphertext(b, &v, c);
515-
mlk_unpack_sk(skpv, sk);
527+
mlk_unpack_ciphertext(&b, &v, c);
528+
mlk_unpack_sk(&skpv, sk);
516529

517-
mlk_polyvec_ntt(b);
518-
mlk_polyvec_mulcache_compute(b_cache, b);
519-
mlk_polyvec_basemul_acc_montgomery_cached(&sb, skpv, b, b_cache);
530+
mlk_polyvec_ntt(&b);
531+
mlk_polyvec_mulcache_compute(&b_cache, &b);
532+
mlk_polyvec_basemul_acc_montgomery_cached(&sb, &skpv, &b, &b_cache);
520533
mlk_poly_invntt_tomont(&sb);
521534

522535
mlk_poly_sub(&v, &sb);

mlkem/src/indcpa.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@
3939
*
4040
**************************************************/
4141
MLK_INTERNAL_API
42-
void mlk_gen_matrix(mlk_polymat a, const uint8_t seed[MLKEM_SYMBYTES],
42+
void mlk_gen_matrix(mlk_polymat *a, const uint8_t seed[MLKEM_SYMBYTES],
4343
int transposed)
4444
__contract__(
4545
requires(memory_no_alias(a, sizeof(mlk_polymat)))
4646
requires(memory_no_alias(seed, MLKEM_SYMBYTES))
4747
requires(transposed == 0 || transposed == 1)
4848
assigns(object_whole(a))
49-
ensures(forall(x, 0, MLKEM_K * MLKEM_K,
50-
array_bound(a[x].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))
49+
ensures(forall(x, 0, MLKEM_K, forall(y, 0, MLKEM_K,
50+
array_bound(a->vec[x].vec[y].coeffs, 0, MLKEM_N, 0, MLKEM_Q))))
5151
);
5252

5353
#define mlk_indcpa_keypair_derand MLK_NAMESPACE_K(indcpa_keypair_derand)

mlkem/src/kem.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ int crypto_kem_check_pk(const uint8_t pk[MLKEM_INDCCA_PUBLICKEYBYTES])
4646
mlk_polyvec p;
4747
uint8_t p_reencoded[MLKEM_POLYVECBYTES];
4848

49-
mlk_polyvec_frombytes(p, pk);
50-
mlk_polyvec_reduce(p);
51-
mlk_polyvec_tobytes(p_reencoded, p);
49+
mlk_polyvec_frombytes(&p, pk);
50+
mlk_polyvec_reduce(&p);
51+
mlk_polyvec_tobytes(p_reencoded, &p);
5252

5353
/* We use a constant-time memcmp here to avoid having to
5454
* declassify the PK before the PCT has succeeded. */

0 commit comments

Comments
 (0)