diff --git a/lib/crypto.rce b/lib/crypto.rce index 39f6f663..55e6af74 100644 --- a/lib/crypto.rce +++ b/lib/crypto.rce @@ -182,6 +182,17 @@ fn seal(key: List[i64], nonce: List[i64], ad: List[i64], pt: List[i64]) -> text let tag = slice(hmac(slice(copy(ks), 32, 64), cat(cat(copy(nonce), ad), copy(ct))), 0, 16) return tohex(cat(ct, tag)) +# Equality of two byte lists with no early exit: the OR of all byte XORs is +# tested once at the end. Only the lengths are public (a length mismatch +# answers at once). Constant fuel for any contents of equal length. +fn ct_eq(a: List[i64], b: List[i64]) -> bool + if a.len() != b.len() + return false + var acc: i64 = 0 + for i in 0..a.len() + acc = acc | (a[i] ^ b[i]) + return acc == 0 + # The plaintext bytes, or [-1] when the tag does not verify. fn open(key: List[i64], nonce: List[i64], ad: List[i64], sealed: text) -> List[i64] let b = unhex(sealed) @@ -191,19 +202,19 @@ fn open(key: List[i64], nonce: List[i64], ad: List[i64], sealed: text) -> List[i let tag = slice(copy(b), b.len() - 16, b.len()) let ks = hkdf([], copy(key), tobytes("rce-aead-v0"), 64) let want = slice(hmac(slice(copy(ks), 32, 64), cat(cat(copy(nonce), ad), copy(ct))), 0, 16) - if tohex(want) != tohex(tag) + if not ct_eq(want, tag) return [-1] return chacha20(slice(copy(ks), 0, 32), nonce, ct) +# Value of one lowercase hex digit (0 for any other character, as before), +# by arithmetic only: no digit table scan and no branch on the digit. The +# range tests use the sign of a difference: ((c - lo) | (hi - c)) >> 63 is +# all ones exactly when c is outside lo..hi. fn hexval(c: text) -> i64 - let ds = "0123456789abcdef".chars() - var v: i64 = 0 - var k: i64 = 0 - for d in ds - if d == c - v = k - k += 1 - return v + let b = c[0] as i64 + let dm = (((b - 48) | (57 - b)) >> 63) ^ (0 - 1) + let am = (((b - 97) | (102 - b)) >> 63) ^ (0 - 1) + return (dm & (b - 48)) | (am & (b - 87)) fn unhex(h: text) -> List[i64] let cs = h.chars() @@ -214,12 +225,24 @@ fn unhex(h: text) -> List[i64] i += 2 return out +# ASCII code of the lowercase hex digit of n in 0..15: 48 + n, plus 39 when +# n > 9 (mask from the sign of 9 - n). No table index. +fn hexdig(n: i64) -> i64 = 48 + n + (39 & ((9 - n) >> 63)) + +# Hex text of a byte list. Elements must be bytes: anything outside 0..255 +# traps, as an out-of-range table index did before. The trap comes from +# utf8() of a guard element that is 256 exactly when the OR of all elements +# has a bit outside 0..255, so there is no branch on the data. fn tohex(b: List[i64]) -> text - let ds = "0123456789abcdef".chars() - var s = "" + var codes: List[i64] = [] + var acc: i64 = 0 for x in b - s = s + copy(ds[(x >> 4) as usize]) + copy(ds[(x & 15) as usize]) - return s + acc = acc | x + codes.push(hexdig(x >> 4)) + codes.push(hexdig(x & 15)) + let t = acc >> 8 + let g = [((t | (0 - t)) >> 63 & 1) << 8].utf8() + return codes.utf8() # GF(2^255 - 19) in ten 26-bit limbs (radix 2^26, 2^260 = 608 mod p) in # i64: limb products stay below 2^58 before carrying. @@ -313,6 +336,21 @@ fn unpack(b: List[i64]) -> List[i64] o[li] = o[li] | (bit << (k % 26)) return o +# Conditional swap of RFC 7748 5.1 (cswap) without a branch: for the mask m +# (0 or all ones, m = 0 - bit) the swap of a and b is a ^= d, b ^= d with +# d = m & (a ^ b). Every limb is processed whatever the bit. +fn cdiff(m: i64, a: List[i64], b: List[i64]) -> List[i64] + var d: List[i64] = [] + for i in 0..10 + d.push(m & (a[i] ^ b[i])) + return d + +fn fxor(a: List[i64], d: List[i64]) -> List[i64] + var o: List[i64] = [] + for i in 0..10 + o.push(a[i] ^ d[i]) + return o + # X25519(k, u) of RFC 7748 over 32-byte hex strings. fn x25519(kh: text, uh: text) -> text var z = unhex(kh) @@ -327,13 +365,13 @@ fn x25519(kh: text, uh: text) -> text for s in 0..255 let i = 254 - s let r = (z[(i >> 3) as usize] >> (i & 7)) & 1 - if r == 1 - let t1 = copy(a) - a = copy(b) - b = t1 - let t2 = copy(c) - c = copy(d) - d = t2 + let m = 0 - r + let sab = cdiff(m, copy(a), copy(b)) + let scd = cdiff(m, copy(c), copy(d)) + a = fxor(a, copy(sab)) + b = fxor(b, sab) + c = fxor(c, copy(scd)) + d = fxor(d, scd) var e = fadd(copy(a), copy(c)) a = fsub(copy(a), copy(c)) c = fadd(copy(b), copy(d)) @@ -352,13 +390,13 @@ fn x25519(kh: text, uh: text) -> text a = fmul(copy(d), copy(f)) d = fmul(copy(b), copy(x)) b = fmul(copy(e), copy(e)) - if r == 1 - let t1 = copy(a) - a = copy(b) - b = t1 - let t2 = copy(c) - c = copy(d) - d = t2 + let m2 = 0 - r + let sab2 = cdiff(m2, copy(a), copy(b)) + let scd2 = cdiff(m2, copy(c), copy(d)) + a = fxor(a, copy(sab2)) + b = fxor(b, sab2) + c = fxor(c, copy(scd2)) + d = fxor(d, scd2) let ci = finv(copy(c)) return tohex(pack(fmul(copy(a), ci))) @@ -731,7 +769,27 @@ fn pt_table(p: Pt) -> List[Pt] fn nib(s: List[i64], i: i64) -> usize = ((s[(i >> 1) as usize] >> (4 * (i & 1))) & 15) as usize -# s * p, s a 32-byte little-endian scalar, 4-bit fixed window +# tb[n] for n in 0..15 by a full scan: every entry is read and masked, the +# entry whose index equals n (mask all ones: (j ^ n) - 1 is negative only +# when j ^ n = 0) is the one kept. No index depends on n. +fn pt_select(tb: List[Pt], n: i64) -> Pt + var x = fe(0) + var y = fe(0) + var z = fe(0) + var t = fe(0) + for j in 0..16 + let m = ((j as i64 ^ n) - 1) >> 63 + for l in 0..10 + x[l] = x[l] | (m & tb[j].x[l]) + y[l] = y[l] | (m & tb[j].y[l]) + z[l] = z[l] | (m & tb[j].z[l]) + t[l] = t[l] | (m & tb[j].t[l]) + return Pt(x: x, y: y, z: z, t: t) + +# s * p, s a 32-byte little-endian scalar, 4-bit fixed window. The window +# entry is chosen by pt_select (full scan), so no table index depends on s; +# s is secret in key generation and signing. (pt_mul2 below is verification +# only: both scalars are public there, and it keeps the direct index.) fn pt_mul(s: List[i64], p: Pt) -> Pt let tb = pt_table(p) var r = pt_zero() @@ -740,7 +798,7 @@ fn pt_mul(s: List[i64], p: Pt) -> Pt if k > 0 for _ in 0..4 r = pt_dbl(copy(r)) - r = pt_add(copy(r), copy(tb[nib(copy(s), i)])) + r = pt_add(copy(r), pt_select(copy(tb), nib(copy(s), i) as i64)) return r # s * p + t * q (Straus, shared doublings) @@ -799,15 +857,28 @@ fn pt_dec(b: List[i64]) -> Dec fn ed_l() -> List[i64] = [237, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0] -# a >= b on equal-length little-endian byte lists +# a - b on equal-length little-endian byte lists, as the difference modulo +# 256^n and the final borrow (1 when a < b). The borrow is the sign bit of +# each limb difference: no branch, same work for all values. +fn sub_borrow(a: List[i64], b: List[i64]) -> List[i64] + var o: List[i64] = [] + var br: i64 = 0 + for j in 0..a.len() + let v = a[j] - b[j] - br + br = (v >> 63) & 1 + o.push(v & 255) + o.push(br) + return o + +# a >= b on equal-length little-endian byte lists, with no early exit fn bge(a: List[i64], b: List[i64]) -> bool - for k in 0..a.len() - let i = a.len() - 1 - k - if a[i] != b[i] - return a[i] > b[i] - return true + let d = sub_borrow(a, b) + return d[d.len() - 1] == 0 -# x mod L for a little-endian byte list x of any length, 32 bytes out +# x mod L for a little-endian byte list x of any length, 32 bytes out. +# Shift-and-subtract over the bits of x (a public count); each step +# computes r - L with its borrow and keeps r or r - L by a mask, so the +# work is the same whether or not the subtraction applies. fn sc_reduce(x: List[i64]) -> List[i64] let l = ed_l() var r: List[i64] = [] @@ -822,16 +893,10 @@ fn sc_reduce(x: List[i64]) -> List[i64] let v = r[j] * 2 + c r[j] = v & 255 c = v >> 8 - if bge(copy(r), copy(l)) - var br: i64 = 0 - for j in 0..33 - let v = r[j] - l[j] - br - if v < 0 - r[j] = v + 256 - br = 1 - else - r[j] = v - br = 0 + let d = sub_borrow(copy(r), copy(l)) + let keep = 0 - d[33] + for j in 0..33 + r[j] = d[j] ^ (keep & (r[j] ^ d[j])) k += 1 return slice(r, 0, 32) diff --git a/lib/hpke.rce b/lib/hpke.rce index bfec5cce..d6e921c0 100644 --- a/lib/hpke.rce +++ b/lib/hpke.rce @@ -10,20 +10,47 @@ module hpke # A.1 (base mode) and the RFC 9420 crypto-basics.json EncryptWithLabel # vector for suite 1 as host steps in tests/hpke_rce.rs. -fn aes_sbox() -> List[i64] = [99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22] +# AES S-box by arithmetic: the inverse in GF(2^8) (a^254, 15 multiplications +# whose bit pattern is the public constant 254) followed by the FIPS 197 +# affine map. No table is indexed by the (secret) byte and nothing branches +# on it. gmul is the shift-and-add product with masks in place of branches. +fn gmul(a: i64, b: i64) -> i64 + var p: i64 = 0 + var x = a + var y = b + for _ in 0..8 + p = p ^ (x & (0 - (y & 1))) + x = ((x << 1) ^ (27 & (0 - (x >> 7)))) & 255 + y = y >> 1 + return p + +fn ginv(a: i64) -> i64 + var r: i64 = 1 + for k in 0..8 + r = gmul(r, r) + if ((254 >> (7 - k as i64)) & 1) == 1 + r = gmul(r, a) + return r + +fn rotl8(v: i64, n: i64) -> i64 = ((v << n) | (v >> (8 - n))) & 255 + +fn sbox(x: i64) -> i64 + let i = ginv(x) + return i ^ rotl8(i, 1) ^ rotl8(i, 2) ^ rotl8(i, 3) ^ rotl8(i, 4) ^ 99 -fn xt(b: i64) -> i64 = ((b << 1) ^ (if b >= 128 then 27 else 0)) & 255 + +# multiply by x in GF(2^8): the reduction is a mask from the top bit, no branch +fn xt(b: i64) -> i64 = ((b << 1) ^ (27 & (0 - (b >> 7)))) & 255 # the 176-byte expanded key of a 16-byte AES-128 key fn aes_expand(key: List[i64]) -> List[i64] - let sb = aes_sbox() var w = copy(key) var rc: i64 = 1 var i: usize = 16 while i < 176 bound 160 var t = [w[i - 4], w[i - 3], w[i - 2], w[i - 1]] if i % 16 == 0 - t = [sb[t[1] as usize] ^ rc, sb[t[2] as usize], sb[t[3] as usize], sb[t[0] as usize]] + t = [sbox(t[1]) ^ rc, sbox(t[2]), sbox(t[3]), sbox(t[0])] rc = xt(rc) for j in 0..4 w.push(w[i - 16 + j] ^ t[j]) @@ -31,7 +58,6 @@ fn aes_expand(key: List[i64]) -> List[i64] return w fn aes_block(rk: List[i64], inp: List[i64]) -> List[i64] - let sb = aes_sbox() var s: List[i64] = [] for i in 0..16 s.push(inp[i] ^ rk[i]) @@ -40,7 +66,7 @@ fn aes_block(rk: List[i64], inp: List[i64]) -> List[i64] var t: List[i64] = [] for c in 0..4 for row in 0..4 - t.push(sb[s[((c + row) % 4) * 4 + row] as usize]) + t.push(sbox(s[((c + row) % 4) * 4 + row])) # MixColumns, except in the last round if r < 10 var m: List[i64] = [] @@ -66,17 +92,16 @@ fn gf_mul(x: List[i64], y: List[i64]) -> List[i64] z.push(0) var v = copy(y) for i in 0..128 - if ((x[i / 8] >> (7 - (i % 8) as i64)) & 1) == 1 - for j in 0..16 - z[j] = z[j] ^ v[j] + let xm = 0 - ((x[i / 8] >> (7 - (i % 8) as i64)) & 1) + for j in 0..16 + z[j] = z[j] ^ (v[j] & xm) let lsb = v[15] & 1 var j: usize = 15 while j > 0 bound 16 v[j] = (v[j] >> 1) | ((v[j - 1] & 1) << 7) j -= 1 v[0] = v[0] >> 1 - if lsb == 1 - v[0] = v[0] ^ 225 + v[0] = v[0] ^ (225 & (0 - lsb)) return z fn ghash(h: List[i64], aad: List[i64], ct: List[i64]) -> List[i64] @@ -133,12 +158,23 @@ fn gcm_seal(key: List[i64], iv: List[i64], aad: List[i64], pt: List[i64]) -> Lis tag.push(s[j] ^ ek[j]) return cat(ct, tag) +# byte-list equality with no early exit (OR of the XORs, tested once); a +# copy of crypto.ct_eq so this file also checks against an embedded crypto +# that predates it. Only the lengths are public. +fn hp_ct_eq(a: List[i64], b: List[i64]) -> bool + if a.len() != b.len() + return false + var acc: i64 = 0 + for i in 0..a.len() + acc = acc | (a[i] ^ b[i]) + return acc == 0 + # the plaintext, or [-1] when the tag does not verify fn gcm_open(key: List[i64], iv: List[i64], aad: List[i64], sealed: List[i64]) -> List[i64] if sealed.len() < 16 return [-1] let pt = gcm_ctr(aes_expand(copy(key)), copy(iv), slice(copy(sealed), 0, sealed.len() - 16)) - if tohex(gcm_seal(key, iv, aad, copy(pt))) == tohex(sealed) + if hp_ct_eq(gcm_seal(key, iv, aad, copy(pt)), sealed) return pt return [-1] @@ -184,20 +220,39 @@ fn hp_nonce(base: List[i64], seq: i64) -> List[i64] n[11 - k] = n[11 - k] ^ ((seq >> (8 * k as i64)) & 255) return n -# SetupBaseS + Seal: "enc.ciphertext" (hex) to recipient public key pkr, +# RFC 9180 7.1.4: the DH output must not be the all-zero value (the peer sent +# a low-order point); the OR of all bytes is tested once at the end, so the +# test does not branch per byte. Only the abort (a public event) branches. +fn hp_allzero(b: List[i64]) -> bool + var acc: i64 = 0 + for x in b + acc = acc | x + return acc == 0 + +# SetupBaseS + Seal: "enc.ciphertext" (hex) to recipient public key pkr ("" +# when pkr is not 32 bytes or the DH output is all zero, RFC 9180 7.1.4), # with the ephemeral private key ske (from logged random bytes), message # number seq of the context fn hpke_seal(pkr: text, ske: text, info: text, aad: text, pt: text, seq: i64) -> text + if unhex(copy(pkr)).len() != 32 + return "" let enc = pubkey(copy(ske)) let dh = unhex(x25519(ske, copy(pkr))) + if hp_allzero(copy(dh)) + return "" let kn = hp_key_nonce(hp_shared(dh, cat(unhex(copy(enc)), unhex(pkr))), unhex(info)) let ct = gcm_seal(slice(copy(kn), 0, 16), hp_nonce(slice(kn, 16, 28), seq), unhex(aad), unhex(pt)) return enc + "." + tohex(ct) -# SetupBaseR + Open: the plaintext (hex), or "" when it does not open +# SetupBaseR + Open: the plaintext (hex), or "" when it does not open (also for +# an enc that is not 32 bytes or gives an all-zero DH output, RFC 9180 7.1.4) fn hpke_open(skr: text, enc: text, info: text, aad: text, ct: text, seq: i64) -> text + if unhex(copy(enc)).len() != 32 + return "" let pkr = pubkey(copy(skr)) let dh = unhex(x25519(skr, copy(enc))) + if hp_allzero(copy(dh)) + return "" let kn = hp_key_nonce(hp_shared(dh, cat(unhex(enc), unhex(pkr))), unhex(info)) let pt = gcm_open(slice(copy(kn), 0, 16), hp_nonce(slice(kn, 16, 28), seq), unhex(aad), unhex(ct)) if pt.len() == 1 and pt[0] == -1 diff --git a/lib/pq.rce b/lib/pq.rce index 234ba3d3..97bba54c 100644 --- a/lib/pq.rce +++ b/lib/pq.rce @@ -120,6 +120,22 @@ fn shake256(m: List[i64], n: usize) -> List[i64] = keccak(136, 31, m, n) const Q: i64 = 3329 const KK: usize = 3 +# Division by Q = 3329 without a division instruction (the KyberSlash lesson: +# a variable-latency divide of secret-derived values leaks). For +# QM = ceil(2^40 / Q) = 330282857 the error term is e = QM * Q - 2^40 = 3177, +# so (n * QM) >> 40 = floor(n / Q) exactly for every 0 <= n < 2^40 / e +# = 346,084,868. Every use here has n below 2^25 (largest: the sum of two +# products of values below Q in ntt_mul, about 22.2M; compress input +# (x << d) + 1664 at d = 11 is below 6.9M). n * QM stays below 2^54. +# `check`s in tests/crypto/mlkem_arith_checks.rce confirm it exhaustively +# over the compress domain and on boundary values. +const QM: i64 = 330282857 + +fn qdiv(n: i64) -> i64 = (n * QM) >> 40 + +# n mod Q for 0 <= n < 346,084,868 +fn qmod(n: i64) -> i64 = n - qdiv(n) * Q + fn mk_zetas() -> List[i64] = [1, 1729, 2580, 3289, 2642, 630, 1897, 848, 1062, 1919, 193, 797, 2786, 3260, 569, 1746, 296, 2447, 1339, 1476, 3046, 56, 2240, 1333, 1426, 2094, 535, 2882, 2393, 2879, 1974, 821, 289, 331, 3253, 1756, 1197, 2304, 2277, 2055, 650, 1977, 2513, 632, 2865, 33, 1320, 1915, 2319, 1435, 807, 452, 1438, 2868, 1534, 2402, 2647, 2617, 1481, 648, 2474, 3110, 1227, 910, 17, 2761, 583, 2649, 1637, 723, 2288, 1100, 1409, 2662, 3281, 233, 756, 2156, 3015, 3050, 1703, 1651, 2789, 1789, 1847, 952, 1461, 2687, 939, 2308, 2437, 2388, 733, 2337, 268, 641, 1584, 2298, 2037, 3220, 375, 2549, 2090, 1645, 1063, 319, 2773, 757, 2099, 561, 2466, 2594, 2804, 1092, 403, 1026, 1143, 2150, 2775, 886, 1722, 1212, 1874, 1029, 2110, 2935, 885, 2154] fn mk_gammas() -> List[i64] = [17, 3312, 2761, 568, 583, 2746, 2649, 680, 1637, 1692, 723, 2606, 2288, 1041, 1100, 2229, 1409, 1920, 2662, 667, 3281, 48, 233, 3096, 756, 2573, 2156, 1173, 3015, 314, 3050, 279, 1703, 1626, 1651, 1678, 2789, 540, 1789, 1540, 1847, 1482, 952, 2377, 1461, 1868, 2687, 642, 939, 2390, 2308, 1021, 2437, 892, 2388, 941, 733, 2596, 2337, 992, 268, 3061, 641, 2688, 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109, 375, 2954, 2549, 780, 2090, 1239, 1645, 1684, 1063, 2266, 319, 3010, 2773, 556, 757, 2572, 2099, 1230, 561, 2768, 2466, 863, 2594, 735, 2804, 525, 1092, 2237, 403, 2926, 1026, 2303, 1143, 2186, 2150, 1179, 2775, 554, 886, 2443, 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300, 2110, 1219, 2935, 394, 885, 2444, 2154, 1175] @@ -141,9 +157,9 @@ fn ntt(p: List[i64]) -> List[i64] let z = zs[k] k += 1 for j in start..(start + len) - let t = (z * f[j + len]) % Q - f[j + len] = (f[j] - t + Q) % Q - f[j] = (f[j] + t) % Q + let t = qmod(z * f[j + len]) + f[j + len] = qmod(f[j] - t + Q) + f[j] = qmod(f[j] + t) start += 2 * len len = len / 2 return f @@ -160,12 +176,12 @@ fn intt(p: List[i64]) -> List[i64] k -= 1 for j in start..(start + len) let t = f[j] - f[j] = (t + f[j + len]) % Q - f[j + len] = (z * ((f[j + len] - t + Q) % Q)) % Q + f[j] = qmod(t + f[j + len]) + f[j + len] = qmod(z * qmod(f[j + len] - t + Q)) start += 2 * len len = len * 2 for j in 0..256 - f[j] = (f[j] * 3303) % Q + f[j] = qmod(f[j] * 3303) return f # multiply two NTT-domain polynomials (FIPS 203 Alg. 11 and 12) @@ -177,20 +193,20 @@ fn ntt_mul(f: List[i64], g: List[i64]) -> List[i64] let a1 = f[2 * i + 1] let b0 = g[2 * i] let b1 = g[2 * i + 1] - h.push((a0 * b0 + ((a1 * b1) % Q) * gs[i]) % Q) - h.push((a0 * b1 + a1 * b0) % Q) + h.push(qmod(a0 * b0 + qmod(a1 * b1) * gs[i])) + h.push(qmod(a0 * b1 + a1 * b0)) return h fn padd(a: List[i64], b: List[i64]) -> List[i64] var c: List[i64] = [] for i in 0..a.len() - c.push((a[i] + b[i]) % Q) + c.push(qmod(a[i] + b[i])) return c fn psub(a: List[i64], b: List[i64]) -> List[i64] var c: List[i64] = [] for i in 0..a.len() - c.push((a[i] - b[i] + Q) % Q) + c.push(qmod(a[i] - b[i] + Q)) return c fn poly(v: List[i64], i: usize) -> List[i64] = slice(v, 256 * i, 256 * (i + 1)) @@ -228,7 +244,7 @@ fn cbd2(s: List[i64], b: i64) -> List[i64] let bits = (byte >> (4 * (i % 2) as i64)) & 15 let a = (bits & 1) + ((bits >> 1) & 1) let c = ((bits >> 2) & 1) + ((bits >> 3) & 1) - f.push((a - c + Q) % Q) + f.push(qmod(a - c + Q)) return f fn byte_encode(f: List[i64], d: i64) -> List[i64] @@ -256,7 +272,7 @@ fn byte_decode(b: List[i64], d: i64, cnt: usize) -> List[i64] p += 1 nb += 8 let v = acc & m - out.push(if d == 12 then v % Q else v) + out.push(if d == 12 then qmod(v) else v) acc = acc >> d nb -= d return out @@ -264,7 +280,7 @@ fn byte_decode(b: List[i64], d: i64, cnt: usize) -> List[i64] fn compress(f: List[i64], d: i64) -> List[i64] var out: List[i64] = [] for x in f - out.push((((x << d) + 1664) / Q) & ((1 << d) - 1)) + out.push(qdiv((x << d) + 1664) & ((1 << d) - 1)) return out fn decompress(f: List[i64], d: i64) -> List[i64] @@ -349,28 +365,74 @@ fn mlkem_keygen(d: text, z: text) -> text let dkp = slice(copy(kp), 384 * KK + 32, kp.len()) return tohex(copy(ek)) + "." + tohex(cat(cat3(dkp, copy(ek), sha3_256(copy(ek))), unhex(z))) -# ML-KEM.Encaps_internal (Alg. 17): "ciphertext.shared" in hex +# byte-list equality with no early exit (OR of the XORs, tested once); a copy +# of crypto.ct_eq so this file also checks against an embedded crypto that +# predates it. Only the lengths are public. +fn kem_ct_eq(a: List[i64], b: List[i64]) -> bool + if a.len() != b.len() + return false + var acc: i64 = 0 + for i in 0..a.len() + acc = acc | (a[i] ^ b[i]) + return acc == 0 + +# OR of the XORs of two equal-length byte lists: 0 exactly when they are +# equal. No branch, no early exit; the caller has checked the lengths. +fn kem_ct_diff(a: List[i64], b: List[i64]) -> i64 + var acc: i64 = 0 + for i in 0..a.len() + acc = acc | (a[i] ^ b[i]) + return acc + +# ML-KEM.Encaps_internal (Alg. 17): "ciphertext.shared" in hex, or "" when an +# input check of FIPS 203 7.2 fails: ek must have 384k + 32 bytes (type check) +# and ByteEncode12(ByteDecode12(t)) must reproduce its first 384k bytes +# (modulus check: every 12-bit coefficient below Q); m must have 32 bytes. +# Both ek and m are public here, so the checks may branch. fn mlkem_encaps(ek: text, m: text) -> text let e = unhex(ek) - let g = sha3_512(cat(unhex(copy(m)), sha3_256(copy(e)))) + let mb = unhex(copy(m)) + if e.len() != 384 * KK + 32 or mb.len() != 32 + return "" + let t = slice(copy(e), 0, 384 * KK) + if not kem_ct_eq(byte_encode(byte_decode(copy(t), 12, 256 * KK), 12), t) + return "" + let g = sha3_512(cat(mb, sha3_256(copy(e)))) let c = pke_encrypt(e, unhex(m), slice(copy(g), 32, 64)) return tohex(c) + "." + tohex(slice(g, 0, 32)) -# ML-KEM.Decaps_internal (Alg. 18): the shared secret, implicit rejection +# ML-KEM.Decaps_internal (Alg. 18): the shared secret with implicit +# rejection, or "" when an input check of FIPS 203 7.3 fails: the ciphertext +# must have 32(du k + dv) = 1088 bytes, dk must have 768k + 96 bytes, and +# H(ek inside dk) must equal the stored hash. Those checks depend on the +# lengths and on the stored key, not on the ciphertext's validity, so they +# may branch. A failed check is a refusal, never a key: a caller must not +# feed "" onward as a secret. +# The re-encryption comparison and the choice between the real key and the +# rejection key are branch-free: the key is kbar ^ (mask & (K ^ kbar)) with +# mask all ones exactly when the ciphertexts are equal. fn mlkem_decaps(dk: text, c: text) -> text let d = unhex(dk) let ct = unhex(c) + if d.len() != 768 * KK + 96 or ct.len() != 32 * (10 * KK + 4) + return "" let dkp = slice(copy(d), 0, 384 * KK) let ek = slice(copy(d), 384 * KK, 768 * KK + 32) let h = slice(copy(d), 768 * KK + 32, 768 * KK + 64) let z = slice(copy(d), 768 * KK + 64, 768 * KK + 96) + if not kem_ct_eq(sha3_256(copy(ek)), copy(h)) + return "" let m = pke_decrypt(dkp, copy(ct)) let g = sha3_512(cat(copy(m), h)) let kbar = shake256(cat(z, copy(ct)), 32) let c2 = pke_encrypt(ek, m, slice(copy(g), 32, 64)) - if tohex(c2) == tohex(ct) - return tohex(slice(g, 0, 32)) - return tohex(kbar) + let acc = kem_ct_diff(c2, ct) + let differ = ((acc | (0 - acc)) >> 63) & 1 + let eq = differ - 1 + var key: List[i64] = [] + for i in 0..32 + key.push(kbar[i] ^ (eq & (g[i] ^ kbar[i]))) + return tohex(key) # ---- PQXDH ---- # Signal's PQXDH over X25519, SHA-256 and ML-KEM-768. The initiator holds @@ -396,7 +458,12 @@ fn pqxdh_dh_resp(ikb: text, spkb: text, ika_pub: text, eka_pub: text) -> text let dh3 = x25519(spkb, eka_pub) return dh1 + dh2 + dh3 -fn pqxdh_sk(dh: text, ss: text) -> text = tohex(hkdf([], cat(cat(ff32(), unhex(dh)), unhex(ss)), tobytes(PQXDH_INFO), 32)) +# "" when ss or dh is empty: mlkem_decaps answers "" for an input it refuses +# (FIPS 203 7.3), and an empty secret must never reach the key derivation. +fn pqxdh_sk(dh: text, ss: text) -> text + if ss.len() == 0 or dh.len() == 0 + return "" + return tohex(hkdf([], cat(cat(ff32(), unhex(dh)), unhex(ss)), tobytes(PQXDH_INFO), 32)) const PQXDH_INFO: text = "rce-pqxdh-v1 X25519 SHA-256 ML-KEM-768" diff --git a/scripts/ct_check.sh b/scripts/ct_check.sh new file mode 100755 index 00000000..36b724fd --- /dev/null +++ b/scripts/ct_check.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# Checks for the constant-time work on crypto, pq and hpke. +# +# tests/crypto/*_checks.rce `check` lines (official vectors and properties). +# tests/crypto/*_fuel.rce probe functions, see below. +# +# The first line of each file may read `# needs: crypto pq hpke`: those +# library files (their own `check` lines removed) are put in front of the +# test file, and the result is run as one program. Each file has its own +# comptime fuel budget, so heavy vector sets are separate files. +# +# Fuel tests. A `_fuel.rce` file defines zero-parameter functions named +# `probe__`. The file is emitted as Python by `rce emit python` +# and run with `--fuel-trace` (spec 26.11: one tick per evaluated +# expression, statement and call). Every probe of one group must use +# exactly the same fuel. A group is called with different secret inputs, so +# equal fuel means the number of evaluated steps does not depend on them. +# This is SOURCE-LEVEL, constant-fuel evidence only. It says nothing about +# the latency of the host's arithmetic, list indexing or cache behaviour, +# so it does not show wall-clock constant time. +# +# Set RCE to the rce binary. Set ONLY to a substring to select test files. +set -e +RCE=${RCE:-rce} +cd "$(dirname "$0")/.." +tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT +pass=0; fail=0; groups=0 +for f in tests/crypto/*_checks.rce tests/crypto/*_fuel.rce; do + [ -f "$f" ] || continue + case "$f" in *"${ONLY:-}"*) ;; *) continue ;; esac + needs=$(sed -n '1s/^# needs: //p' "$f") + o="$tmp/$(basename "$f")" + { echo "module t"; for n in $needs; do grep -v '^module \|^check ' "lib/$n.rce"; echo; done; cat "$f"; } > "$o" + case "$f" in + *_checks.rce) + if "$RCE" test "$o" > "$o.out" 2>&1; then + echo "ok $f: $(grep -o '[0-9]* checks' "$o.out" | head -1)"; pass=$((pass+1)) + else + echo "FAIL $f"; cat "$o.out"; fail=$((fail+1)) + fi;; + *_fuel.rce) + "$RCE" emit python "$o" > "$o.py" + python3 "$o.py" --fuel-trace > "$o.out" 2>&1 || { echo "FAIL $f: run error"; tail -5 "$o.out"; fail=$((fail+1)); continue; } + if python3 - "$o.out" "$f" <<'PY' +import sys, re, collections +g = collections.defaultdict(list) +name = None +for line in open(sys.argv[1]): + m = re.match(r'fn (probe_(\w+?)_\d+) = ', line) + if m: name = (m.group(2), m.group(1)); continue + m = re.match(r'fuel (\d+)', line) + if m and name: g[name[0]].append((name[1], int(m.group(1)))); name = None +bad = 0 +for grp, v in sorted(g.items()): + fs = {x[1] for x in v} + if len(v) < 2 or len(fs) != 1: + bad += 1; print(" GROUP %s: fuel %s" % (grp, [(n, k) for n, k in v])) + else: + print(" group %s: %d probes, fuel %d each" % (grp, len(v), fs.pop())) +sys.exit(1 if bad or not g else 0) +PY + then echo "ok $f"; pass=$((pass+1)); else echo "FAIL $f"; fail=$((fail+1)); fi;; + esac +done +echo "ct_check: $pass files passed, $fail failed" +[ "$fail" = 0 ] diff --git a/tests/crypto/aes_sbox_checks.rce b/tests/crypto/aes_sbox_checks.rce new file mode 100644 index 00000000..5095c417 --- /dev/null +++ b/tests/crypto/aes_sbox_checks.rce @@ -0,0 +1,15 @@ +# needs: crypto hpke +# +# AES S-box by arithmetic against the FIPS 197 table (figure 7), all 256 inputs, plus xt and gmul. +fn ref_sbox() -> List[i64] = [99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22] +fn all_sbox() -> bool + let t = ref_sbox() + var ok = true + for x in 0..256 + ok = ok and sbox(x as i64) == t[x] + return ok +check ref_sbox().len() == 256 and ref_sbox()[0] == 99 and ref_sbox()[255] == 22 +check all_sbox() +check xt(128) == 27 and xt(127) == 254 and xt(255) == 229 and xt(0) == 0 and xt(1) == 2 +check gmul(87, 131) == 193 and gmul(87, 19) == 254 and gmul(0, 77) == 0 and gmul(1, 77) == 77 +check ginv(0) == 0 and gmul(83, ginv(83)) == 1 and gmul(202, ginv(202)) == 1 diff --git a/tests/crypto/ed25519_1_pub_checks.rce b/tests/crypto/ed25519_1_pub_checks.rce new file mode 100644 index 00000000..ba54e3d7 --- /dev/null +++ b/tests/crypto/ed25519_1_pub_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST 1: public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_pubkey("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60") == "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a" diff --git a/tests/crypto/ed25519_1_sign_checks.rce b/tests/crypto/ed25519_1_sign_checks.rce new file mode 100644 index 00000000..83675b5c --- /dev/null +++ b/tests/crypto/ed25519_1_sign_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST 1: public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_sign("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", []) == "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b" diff --git a/tests/crypto/ed25519_1_verify_checks.rce b/tests/crypto/ed25519_1_verify_checks.rce new file mode 100644 index 00000000..6fa4791f --- /dev/null +++ b/tests/crypto/ed25519_1_verify_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST 1: public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_verify("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", [], "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b") diff --git a/tests/crypto/ed25519_2_pub_checks.rce b/tests/crypto/ed25519_2_pub_checks.rce new file mode 100644 index 00000000..b2a33912 --- /dev/null +++ b/tests/crypto/ed25519_2_pub_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST 2: public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_pubkey("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb") == "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c" diff --git a/tests/crypto/ed25519_2_sign_checks.rce b/tests/crypto/ed25519_2_sign_checks.rce new file mode 100644 index 00000000..18330e6d --- /dev/null +++ b/tests/crypto/ed25519_2_sign_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST 2: public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_sign("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", unhex("72")) == "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00" diff --git a/tests/crypto/ed25519_2_verify_checks.rce b/tests/crypto/ed25519_2_verify_checks.rce new file mode 100644 index 00000000..c8938fca --- /dev/null +++ b/tests/crypto/ed25519_2_verify_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST 2: public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_verify("3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", unhex("72"), "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00") diff --git a/tests/crypto/ed25519_3_pub_checks.rce b/tests/crypto/ed25519_3_pub_checks.rce new file mode 100644 index 00000000..6845422f --- /dev/null +++ b/tests/crypto/ed25519_3_pub_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST 3: public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_pubkey("c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7") == "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025" diff --git a/tests/crypto/ed25519_3_sign_checks.rce b/tests/crypto/ed25519_3_sign_checks.rce new file mode 100644 index 00000000..2a37fe07 --- /dev/null +++ b/tests/crypto/ed25519_3_sign_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST 3: public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_sign("c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7", unhex("af82")) == "6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a" diff --git a/tests/crypto/ed25519_3_verify_checks.rce b/tests/crypto/ed25519_3_verify_checks.rce new file mode 100644 index 00000000..16c656c0 --- /dev/null +++ b/tests/crypto/ed25519_3_verify_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST 3: public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_verify("fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025", unhex("af82"), "6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a") diff --git a/tests/crypto/ed25519_4_pub_checks.rce b/tests/crypto/ed25519_4_pub_checks.rce new file mode 100644 index 00000000..617e6334 --- /dev/null +++ b/tests/crypto/ed25519_4_pub_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST SHA(abc): public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_pubkey("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42") == "ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf" diff --git a/tests/crypto/ed25519_4_sign_checks.rce b/tests/crypto/ed25519_4_sign_checks.rce new file mode 100644 index 00000000..af614956 --- /dev/null +++ b/tests/crypto/ed25519_4_sign_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST SHA(abc): public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_sign("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42", unhex("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f")) == "dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704" diff --git a/tests/crypto/ed25519_4_verify_checks.rce b/tests/crypto/ed25519_4_verify_checks.rce new file mode 100644 index 00000000..c4676e20 --- /dev/null +++ b/tests/crypto/ed25519_4_verify_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, RFC 8032 7.1 TEST SHA(abc): public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_verify("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf", unhex("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"), "dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704") diff --git a/tests/crypto/ed25519_5_pub_checks.rce b/tests/crypto/ed25519_5_pub_checks.rce new file mode 100644 index 00000000..9941ea31 --- /dev/null +++ b/tests/crypto/ed25519_5_pub_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, differential vector from OpenSSL (Python cryptography): public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_pubkey("49e389f6cf65d9b607baf9d7b36cf89ded90d6e0612d0e15e9fc0b42f4faa96e") == "9cfd675720f8205e9b5175e199f16aea155bed19238654536366b060520f046e" diff --git a/tests/crypto/ed25519_5_sign_checks.rce b/tests/crypto/ed25519_5_sign_checks.rce new file mode 100644 index 00000000..44432389 --- /dev/null +++ b/tests/crypto/ed25519_5_sign_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, differential vector from OpenSSL (Python cryptography): public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_sign("49e389f6cf65d9b607baf9d7b36cf89ded90d6e0612d0e15e9fc0b42f4faa96e", unhex("e4223ed20d7ea5")) == "ea1143083c1309b2dd4f3903bbd1e1b487c44f7d305792351a86e814106f9f928713d2787582080dc39dbbf67b89f04e2402be9e63b94419f387818512aee505" diff --git a/tests/crypto/ed25519_5_verify_checks.rce b/tests/crypto/ed25519_5_verify_checks.rce new file mode 100644 index 00000000..eac9e2f1 --- /dev/null +++ b/tests/crypto/ed25519_5_verify_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, differential vector from OpenSSL (Python cryptography): public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_verify("9cfd675720f8205e9b5175e199f16aea155bed19238654536366b060520f046e", unhex("e4223ed20d7ea5"), "ea1143083c1309b2dd4f3903bbd1e1b487c44f7d305792351a86e814106f9f928713d2787582080dc39dbbf67b89f04e2402be9e63b94419f387818512aee505") diff --git a/tests/crypto/ed25519_6_pub_checks.rce b/tests/crypto/ed25519_6_pub_checks.rce new file mode 100644 index 00000000..892c32eb --- /dev/null +++ b/tests/crypto/ed25519_6_pub_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, differential vector from OpenSSL (Python cryptography): public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_pubkey("fc84d768edabfbaff326a7528798c4679e51bf951426e73419fcc48fe3f85605") == "3474aaf9b0cfdc4852f4ecb1719a05d445835ac75802a6a32f3f0d82e04ab03d" diff --git a/tests/crypto/ed25519_6_sign_checks.rce b/tests/crypto/ed25519_6_sign_checks.rce new file mode 100644 index 00000000..081c40f4 --- /dev/null +++ b/tests/crypto/ed25519_6_sign_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, differential vector from OpenSSL (Python cryptography): public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_sign("fc84d768edabfbaff326a7528798c4679e51bf951426e73419fcc48fe3f85605", unhex("ca0df2c95aa144c1")) == "ca28454c4fc0f8c436724084d606a1a238b65bbb932e0f26d3442de6fba05ec0a14efe0293d69a130ead766cdcdc23379fc4515dce6f83acc185695ba086470e" diff --git a/tests/crypto/ed25519_6_verify_checks.rce b/tests/crypto/ed25519_6_verify_checks.rce new file mode 100644 index 00000000..ad27b593 --- /dev/null +++ b/tests/crypto/ed25519_6_verify_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519, differential vector from OpenSSL (Python cryptography): public key, signature, and verification. (one operation per file: each Ed25519 scalar multiplication uses about 15M of the 50M comptime fuel) +check ed_verify("3474aaf9b0cfdc4852f4ecb1719a05d445835ac75802a6a32f3f0d82e04ab03d", unhex("ca0df2c95aa144c1"), "ca28454c4fc0f8c436724084d606a1a238b65bbb932e0f26d3442de6fba05ec0a14efe0293d69a130ead766cdcdc23379fc4515dce6f83acc185695ba086470e") diff --git a/tests/crypto/ed25519_7_1_checks.rce b/tests/crypto/ed25519_7_1_checks.rce new file mode 100644 index 00000000..8decce7b --- /dev/null +++ b/tests/crypto/ed25519_7_1_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519 verification refusals on RFC 8032 TEST 1: a flipped message, a +check not ed_verify("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", [1], "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b") diff --git a/tests/crypto/ed25519_7_2_checks.rce b/tests/crypto/ed25519_7_2_checks.rce new file mode 100644 index 00000000..aa527c77 --- /dev/null +++ b/tests/crypto/ed25519_7_2_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519 verification refusals on RFC 8032 TEST 1: a flipped message, a +check not ed_verify("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", [], "e5564300c300ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b") diff --git a/tests/crypto/ed25519_7_3_checks.rce b/tests/crypto/ed25519_7_3_checks.rce new file mode 100644 index 00000000..1e51ace6 --- /dev/null +++ b/tests/crypto/ed25519_7_3_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519 verification refusals on RFC 8032 TEST 1: a flipped message, a +check not ed_verify("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", [], "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901554c8c7872aa064e049dbb3013fbf29380d25bf5f0595bbe24655141438e7a101b") diff --git a/tests/crypto/ed25519_7_4_checks.rce b/tests/crypto/ed25519_7_4_checks.rce new file mode 100644 index 00000000..00018055 --- /dev/null +++ b/tests/crypto/ed25519_7_4_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# Ed25519 verification refusals on RFC 8032 TEST 1: a flipped message, a +check not ed_verify("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f70751", [], "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b") diff --git a/tests/crypto/ed25519_fuel.rce b/tests/crypto/ed25519_fuel.rce new file mode 100644 index 00000000..3a347e52 --- /dev/null +++ b/tests/crypto/ed25519_fuel.rce @@ -0,0 +1,19 @@ +# needs: crypto +# Fuel of the Ed25519 secret paths does not depend on the secret: key +# derivation and signing for different seeds (and same-length messages), and +# sc_reduce for different 64-byte inputs. Before the fix the scalar +# reduction branched on its data and the window table was indexed by the +# secret scalar. Source-level evidence only: list indexing and arithmetic +# cost one step whatever the value, so fuel cannot see cache effects. +fn probe_edpub_1() -> text = ed_pubkey("0000000000000000000000000000000000000000000000000000000000000000") +fn probe_edpub_2() -> text = ed_pubkey("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") +fn probe_edpub_3() -> text = ed_pubkey("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60") +fn probe_edpub_4() -> text = ed_pubkey("c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7") +fn probe_edsign_1() -> text = ed_sign("0000000000000000000000000000000000000000000000000000000000000000", [1, 2, 3]) +fn probe_edsign_2() -> text = ed_sign("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", [0, 0, 0]) +fn probe_edsign_3() -> text = ed_sign("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", [255, 254, 253]) +# literal 64-byte operands: zero, all ones, a pattern, and L itself +fn probe_screduce_1() -> List[i64] = sc_reduce([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +fn probe_screduce_2() -> List[i64] = sc_reduce([255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]) +fn probe_screduce_3() -> List[i64] = sc_reduce([11, 48, 85, 122, 159, 196, 233, 14, 51, 88, 125, 162, 199, 236, 17, 54, 91, 128, 165, 202, 239, 20, 57, 94, 131, 168, 205, 242, 23, 60, 97, 134, 171, 208, 245, 26, 63, 100, 137, 174, 211, 248, 29, 66, 103, 140, 177, 214, 251, 32, 69, 106, 143, 180, 217, 254, 35, 72, 109, 146, 183, 220, 1, 38]) +fn probe_screduce_4() -> List[i64] = sc_reduce([237, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) diff --git a/tests/crypto/hex_checks.rce b/tests/crypto/hex_checks.rce new file mode 100644 index 00000000..302cfc1a --- /dev/null +++ b/tests/crypto/hex_checks.rce @@ -0,0 +1,21 @@ +# needs: crypto +# unhex and tohex after the arithmetic rewrite (no digit table, no branch on +# a digit). Full byte range, all 16 digits in both positions, legacy +# behaviour kept: any non lowercase-hex character reads as 0, an odd +# trailing digit is ignored, tohex of a non byte traps (not checked here). +fn all256() -> List[i64] + var o: List[i64] = [] + for i in 0..256 + o.push(i) + return o +check tohex(all256()) == "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" +check unhex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") == all256() +check tohex([]) == "" and unhex("") == [] +check unhex("0123456789abcdef") == [1, 35, 69, 103, 137, 171, 205, 239] +check unhex("00ff7f80") == [0, 255, 127, 128] +check unhex("ABCD") == [0, 0] +check unhex("g0:/") == [0, 0] +check unhex("abc") == [171] +check hexval("0") == 0 and hexval("9") == 9 and hexval("a") == 10 and hexval("f") == 15 +check hexval("/") == 0 and hexval(":") == 0 and hexval("`") == 0 and hexval("g") == 0 and hexval("A") == 0 +check tohex(unhex("deadbeef00ff")) == "deadbeef00ff" diff --git a/tests/crypto/hex_fuel.rce b/tests/crypto/hex_fuel.rce new file mode 100644 index 00000000..ea7fee4e --- /dev/null +++ b/tests/crypto/hex_fuel.rce @@ -0,0 +1,11 @@ +# needs: crypto +# unhex and tohex use the same fuel for different digits and bytes of one +# length (including the digit class boundaries 9/a, f/g). +fn probe_unhex_1() -> List[i64] = unhex("00000000000000000000000000000000") +fn probe_unhex_2() -> List[i64] = unhex("ffffffffffffffffffffffffffffffff") +fn probe_unhex_3() -> List[i64] = unhex("09afaf90090faf9009afaf90090faf90") +fn probe_unhex_4() -> List[i64] = unhex("a5c3d2e1f0b4960123456789abcdef01") +fn probe_tohex_1() -> text = tohex([0, 0, 0, 0, 0, 0, 0, 0]) +fn probe_tohex_2() -> text = tohex([255, 255, 255, 255, 255, 255, 255, 255]) +fn probe_tohex_3() -> text = tohex([9, 10, 15, 16, 159, 160, 175, 176]) +fn probe_tohex_4() -> text = tohex([1, 35, 69, 103, 137, 171, 205, 239]) diff --git a/tests/crypto/hpke_10_checks.rce b/tests/crypto/hpke_10_checks.rce new file mode 100644 index 00000000..18a50f1c --- /dev/null +++ b/tests/crypto/hpke_10_checks.rce @@ -0,0 +1,6 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. Refusals. +# RFC 9180 7.1.4: an all-zero DH output aborts. u = 0 and u = 1 are low-order points (X25519 gives all zero for u = 0); a 31-byte key is refused. +check x25519("52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736", "0000000000000000000000000000000000000000000000000000000000000000") == "0000000000000000000000000000000000000000000000000000000000000000" +check hpke_seal("0000000000000000000000000000000000000000000000000000000000000000", "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736", "4f6465206f6e2061204772656369616e2055726e", "436f756e742d30", "4265617574792069732074727574682c20747275746820626561757479", 0) == "" +check hpke_seal("3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c", "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736", "4f6465206f6e2061204772656369616e2055726e", "436f756e742d30", "4265617574792069732074727574682c20747275746820626561757479", 0) == "" diff --git a/tests/crypto/hpke_11_checks.rce b/tests/crypto/hpke_11_checks.rce new file mode 100644 index 00000000..57efe2d8 --- /dev/null +++ b/tests/crypto/hpke_11_checks.rce @@ -0,0 +1,6 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. Refusals on open. +# all-zero DH on the receiving side +check hpke_open("4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8", "0000000000000000000000000000000000000000000000000000000000000000", "4f6465206f6e2061204772656369616e2055726e", "436f756e742d30", "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a", 0) == "" +check hpke_open("4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8", "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf44", "4f6465206f6e2061204772656369616e2055726e", "436f756e742d30", "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a", 0) == "" +check hp_allzero([0, 0, 0]) and not hp_allzero([0, 0, 1]) and not hp_allzero([128, 0, 0]) diff --git a/tests/crypto/hpke_1_checks.rce b/tests/crypto/hpke_1_checks.rce new file mode 100644 index 00000000..c280fe4d --- /dev/null +++ b/tests/crypto/hpke_1_checks.rce @@ -0,0 +1,5 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. Key derivation steps (no ladder). +check hp_derive_sk("7268600d403fce431561aef583ee1613527cff655c1343f29812e66706df3234") == "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736" +check hp_derive_sk("6db9df30aa07dd42ee5e8181afdb977e538f5e1fec8a06223f33f7013e525037") == "4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8" +check tohex(hp_key_nonce(unhex("fe0e18c9f024ce43799ae393c7e8fe8fce9d218875e8227b0187c04e7d2ea1fc"), unhex("4f6465206f6e2061204772656369616e2055726e"))) == "4531685d41d65f03dc48f6b8302c05b056d890e5accaaf011cff4b7d" diff --git a/tests/crypto/hpke_2_checks.rce b/tests/crypto/hpke_2_checks.rce new file mode 100644 index 00000000..27968a5b --- /dev/null +++ b/tests/crypto/hpke_2_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. Ephemeral public key (one ladder). +check pubkey("52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736") == "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431" diff --git a/tests/crypto/hpke_3_checks.rce b/tests/crypto/hpke_3_checks.rce new file mode 100644 index 00000000..e6a543f8 --- /dev/null +++ b/tests/crypto/hpke_3_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. Recipient public key (one ladder). +check pubkey("4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8") == "3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d" diff --git a/tests/crypto/hpke_4_checks.rce b/tests/crypto/hpke_4_checks.rce new file mode 100644 index 00000000..2d4e2e8e --- /dev/null +++ b/tests/crypto/hpke_4_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. Sender DH and ExtractAndExpand (one ladder). +check tohex(hp_shared(unhex(x25519("52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736", "3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d")), cat(unhex("37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431"), unhex("3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d")))) == "fe0e18c9f024ce43799ae393c7e8fe8fce9d218875e8227b0187c04e7d2ea1fc" diff --git a/tests/crypto/hpke_5_checks.rce b/tests/crypto/hpke_5_checks.rce new file mode 100644 index 00000000..b72eedc2 --- /dev/null +++ b/tests/crypto/hpke_5_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. Recipient DH and ExtractAndExpand (one ladder). +check tohex(hp_shared(unhex(x25519("4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8", "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431")), cat(unhex("37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431"), unhex("3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d")))) == "fe0e18c9f024ce43799ae393c7e8fe8fce9d218875e8227b0187c04e7d2ea1fc" diff --git a/tests/crypto/hpke_6_checks.rce b/tests/crypto/hpke_6_checks.rce new file mode 100644 index 00000000..8efb5395 --- /dev/null +++ b/tests/crypto/hpke_6_checks.rce @@ -0,0 +1,10 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. AES-128-GCM Seal for the first four messages and their nonces (sequence numbers 0 to 3). +check tohex(gcm_seal(unhex("4531685d41d65f03dc48f6b8302c05b0"), hp_nonce(unhex("56d890e5accaaf011cff4b7d"), 0), unhex("436f756e742d30"), unhex("4265617574792069732074727574682c20747275746820626561757479"))) == "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a" +check tohex(hp_nonce(unhex("56d890e5accaaf011cff4b7d"), 0)) == "56d890e5accaaf011cff4b7d" +check tohex(gcm_seal(unhex("4531685d41d65f03dc48f6b8302c05b0"), hp_nonce(unhex("56d890e5accaaf011cff4b7d"), 1), unhex("436f756e742d31"), unhex("4265617574792069732074727574682c20747275746820626561757479"))) == "af2d7e9ac9ae7e270f46ba1f975be53c09f8d875bdc8535458c2494e8a6eab251c03d0c22a56b8ca42c2063b84" +check tohex(hp_nonce(unhex("56d890e5accaaf011cff4b7d"), 1)) == "56d890e5accaaf011cff4b7c" +check tohex(gcm_seal(unhex("4531685d41d65f03dc48f6b8302c05b0"), hp_nonce(unhex("56d890e5accaaf011cff4b7d"), 2), unhex("436f756e742d32"), unhex("4265617574792069732074727574682c20747275746820626561757479"))) == "498dfcabd92e8acedc281e85af1cb4e3e31c7dc394a1ca20e173cb72516491588d96a19ad4a683518973dcc180" +check tohex(hp_nonce(unhex("56d890e5accaaf011cff4b7d"), 2)) == "56d890e5accaaf011cff4b7f" +check tohex(gcm_seal(unhex("4531685d41d65f03dc48f6b8302c05b0"), hp_nonce(unhex("56d890e5accaaf011cff4b7d"), 3), unhex("436f756e742d33"), unhex("4265617574792069732074727574682c20747275746820626561757479"))) == "6b0f4cd351730cd25993d8ad0f11bff1ef2c3a957cb4d8694bb06c60a2937385da1b47a11595dd7a9a28f76c26" +check tohex(hp_nonce(unhex("56d890e5accaaf011cff4b7d"), 3)) == "56d890e5accaaf011cff4b7e" diff --git a/tests/crypto/hpke_7_checks.rce b/tests/crypto/hpke_7_checks.rce new file mode 100644 index 00000000..277454e0 --- /dev/null +++ b/tests/crypto/hpke_7_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. Full SetupBaseS + Seal, message 0. +check hpke_seal("3948cfe0ad1ddb695d780e59077195da6c56506b027329794ab02bca80815c4d", "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736", "4f6465206f6e2061204772656369616e2055726e", "436f756e742d30", "4265617574792069732074727574682c20747275746820626561757479", 0) == "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431.f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a" diff --git a/tests/crypto/hpke_8_checks.rce b/tests/crypto/hpke_8_checks.rce new file mode 100644 index 00000000..7f5338f0 --- /dev/null +++ b/tests/crypto/hpke_8_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. Full SetupBaseR + Open, message 0. +check hpke_open("4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8", "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431", "4f6465206f6e2061204772656369616e2055726e", "436f756e742d30", "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a", 0) == "4265617574792069732074727574682c20747275746820626561757479" diff --git a/tests/crypto/hpke_9_checks.rce b/tests/crypto/hpke_9_checks.rce new file mode 100644 index 00000000..88e97441 --- /dev/null +++ b/tests/crypto/hpke_9_checks.rce @@ -0,0 +1,6 @@ +# needs: crypto hpke +# RFC 9180 A.1 (DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM, base mode) from vectors/hpke-base-x25519-sha256-aes128gcm.json. Tampered tag, wrong aad, tampered open: refused. +check gcm_open(unhex("4531685d41d65f03dc48f6b8302c05b0"), unhex("56d890e5accaaf011cff4b7d"), unhex("436f756e742d30"), unhex("f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a")) == unhex("4265617574792069732074727574682c20747275746820626561757479") +check gcm_open(unhex("4531685d41d65f03dc48f6b8302c05b0"), unhex("56d890e5accaaf011cff4b7d"), unhex("436f756e742d30"), unhex("f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c5100")) == [-1] +check gcm_open(unhex("4531685d41d65f03dc48f6b8302c05b0"), unhex("56d890e5accaaf011cff4b7d"), unhex("436f756e742d31"), unhex("f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a")) == [-1] +check hpke_open("4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8", "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431", "4f6465206f6e2061204772656369616e2055726e", "436f756e742d30", "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c5100", 0) == "" diff --git a/tests/crypto/hpke_fuel.rce b/tests/crypto/hpke_fuel.rce new file mode 100644 index 00000000..d9c33f4b --- /dev/null +++ b/tests/crypto/hpke_fuel.rce @@ -0,0 +1,21 @@ +# needs: crypto hpke +# Fuel of AES-128 and GCM does not depend on the key or the data (same +# lengths): before the fix the S-box lookup was an index by the secret byte, +# xt and GF(2^128) multiplication branched on secret bits. Source-level +# evidence only: a table index costs one fuel step for any index, so fuel +# could not see the old S-box leak; it does see the old branches. +fn probe_aesblock_1() -> List[i64] = aes_block(aes_expand([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +fn probe_aesblock_2() -> List[i64] = aes_block(aes_expand([255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]), [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]) +fn probe_aesblock_3() -> List[i64] = aes_block(aes_expand([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), [1, 14, 27, 40, 53, 66, 79, 92, 105, 118, 131, 144, 157, 170, 183, 196]) +fn probe_aesblock_4() -> List[i64] = aes_block(aes_expand([7, 36, 65, 94, 123, 152, 181, 210, 239, 12, 41, 70, 99, 128, 157, 186]), [240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]) +fn probe_gcmseal_1() -> List[i64] = gcm_seal([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +fn probe_gcmseal_2() -> List[i64] = gcm_seal([255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [255, 255, 255, 255, 255], [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]) +fn probe_gcmseal_3() -> List[i64] = gcm_seal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22], [1, 14, 27, 40, 53], [1, 14, 27, 40, 53, 66, 79, 92, 105, 118, 131, 144, 157, 170, 183, 196]) +fn probe_gcmseal_4() -> List[i64] = gcm_seal([7, 36, 65, 94, 123, 152, 181, 210, 239, 12, 41, 70, 99, 128, 157, 186], [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33], [240, 241, 242, 243, 244], [240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]) +fn probe_xt_1() -> i64 = xt(0) +fn probe_xt_2() -> i64 = xt(127) +fn probe_xt_3() -> i64 = xt(128) +fn probe_xt_4() -> i64 = xt(255) +fn probe_gfmul_1() -> List[i64] = gf_mul([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 14, 27, 40, 53, 66, 79, 92, 105, 118, 131, 144, 157, 170, 183, 196]) +fn probe_gfmul_2() -> List[i64] = gf_mul([255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], [7, 36, 65, 94, 123, 152, 181, 210, 239, 12, 41, 70, 99, 128, 157, 186]) +fn probe_gfmul_3() -> List[i64] = gf_mul([1, 14, 27, 40, 53, 66, 79, 92, 105, 118, 131, 144, 157, 170, 183, 196], [240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]) diff --git a/tests/crypto/mlkem_1_decaps_checks.rce b/tests/crypto/mlkem_1_decaps_checks.rce new file mode 100644 index 00000000..c7d6aae2 --- /dev/null +++ b/tests/crypto/mlkem_1_decaps_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto pq +# ML-KEM-768 known answers (FIPS 203 internal algorithms, seeds d, z, m given), generated with the independent Python package kyber-py 1.2.0 (a FIPS 203 implementation): vector 1. One operation per file (comptime fuel). +check mlkem_decaps("4b3ba9a92a8f271a46a8e76f5b16b8d2ca8e68b829446c7beb1490283a82bb69a982568d0df51c8d61020b632c5c6727f5c70a7506afbc4b25bc0b7b3f9525c0aa8050e791e98c18d2886d82a3b0729085a701c0c4648dd3218d4c057562b59168d38714b69422a08b065cad1e485a091350fa0c0b2fb8cec2905c58a3ae61d13794347fc82422466281b3b6a6e59304c64159ad376553f3a1a9f71b55322a4fb11651777a22801d9047c5c233a898866b4889a7619ba565aa731d989ca201035ee81f3c0342bf96cbbdd94ddde04ea6c44dc978a04aeb0d64d30414e308d6207d399776e80c820f50b3f74cadfc76c24166324e81b3c35aa976bacdf63585db6133de1728365367d038c2e6d934789871cf80aeae59875ad54a80f41c0117c512345d58cb521d200dbfd230568a9108700be2820315a271dc4a5524d7c63f08a7ed2172f8dc1e7087959cb88e599056389abfe9003d5678768f023fcf198fc2d59da004272fdb9c02f1ba1447c7e61956a9d88b64eb5037428df4aa6391344281c21b6fb84ec3f115cd856ee6cc00e4d95b7cc98d010b51db8b2bc3b43d8c981ff37259334b17b10986a39a4c988431b7e033473a63d672bb8ad3798364ae00923e9392094b93c877b1ce896b4af5934c6dd460c0bc729bab7f5b169a37180ad27404ea40280cd55f58a25a1e63c5cc566a6cb229a5c34ef654c6b71425bd57acafc940f5c3959286186f709057e110d48811a577820a88bd6dea298921b381ac77f13abc360cb59b33142064c3b9a56c748bbc7e7620ae3ab868b913f18764017987c068020a3a8c9e295114830f8f996284a37b73f476919a17d8fc3dd8c9b025b0a87264a5584009fbf45221840623e13430baa4c2d3bc7d478634dc9552b49b5497c400703bf75798dc73ce4d730ae9f358734532eae47f11f7cb44d415ba9c96a7335aa8b42ed1661b2b803613777b0828af4bb486be776ebf46ad493c8126493407098ca0e41e198409617aab404c9a5a83468f9a681eacbd96b671a0898496652c7b11be78208979b310ade80205035ce2bb33706426852097291510d0984d36b349a48c76b6e9489ae0c0fd419310486690a72680d16acb8921b40a0f82f5a95c457d8a16021c919d1a23b39f6ac470e1c8d547b02751b1c2040827733cf6e9018694bfd7eacd1e07b7a7c83e22076a318b895b06108b6499a719af9552495ff642de91698e3459e8a8b8d3711fdf9c8b7e56517f600c47e6b9aeb50c65c0943cc741c8f3b4b91b74708354b2d185c211663367483201717169a13f7ba20eb7601d716ee5637d3083605c027fdd08029f06063dd2b8b9f3ae0850a1b92299e30b718df44341923896ea808da925bd3bc337fbc018f2cfcdac1adee304ede55764e58165a237b8f9ae4144928c7597af9065a63b13e3d87dedd096e44701f01b50fe235834ac63ca0a584e060fbf717cc7d8c01dba13e6a7048fbb259d57cbfcca4bf4e5c077ca73f42c17f91773cabc6c0ad933e6c60d8d719a944705f4d816e66594a334c1ec4227eef444c48c7b726273ef134c5e1b2165e6532f832b41b0665e6c5cd996859800420de8546b0b96f4d3380049793fe30db3497de3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d94f62e0847061a998f6feb39bafa6d6e36bd2fc0d2c907d17ac58893c3b39d807b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2", "fc6b55a3f161f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17460124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1eb9") == "7978e047c85028661f34053866c991c11926a9c112aabcc02fab609ef8a700f3" diff --git a/tests/crypto/mlkem_1_encaps_checks.rce b/tests/crypto/mlkem_1_encaps_checks.rce new file mode 100644 index 00000000..f30fd1ea --- /dev/null +++ b/tests/crypto/mlkem_1_encaps_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto pq +# ML-KEM-768 known answers (FIPS 203 internal algorithms, seeds d, z, m given), generated with the independent Python package kyber-py 1.2.0 (a FIPS 203 implementation): vector 1. One operation per file (comptime fuel). +check mlkem_encaps("e3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d9", "fcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c5177f") == "fc6b55a3f161f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17460124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1eb9.7978e047c85028661f34053866c991c11926a9c112aabcc02fab609ef8a700f3" diff --git a/tests/crypto/mlkem_1_keygen_checks.rce b/tests/crypto/mlkem_1_keygen_checks.rce new file mode 100644 index 00000000..9c351c35 --- /dev/null +++ b/tests/crypto/mlkem_1_keygen_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto pq +# ML-KEM-768 known answers (FIPS 203 internal algorithms, seeds d, z, m given), generated with the independent Python package kyber-py 1.2.0 (a FIPS 203 implementation): vector 1. One operation per file (comptime fuel). +check mlkem_keygen("96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7", "b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2") == "e3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d9.4b3ba9a92a8f271a46a8e76f5b16b8d2ca8e68b829446c7beb1490283a82bb69a982568d0df51c8d61020b632c5c6727f5c70a7506afbc4b25bc0b7b3f9525c0aa8050e791e98c18d2886d82a3b0729085a701c0c4648dd3218d4c057562b59168d38714b69422a08b065cad1e485a091350fa0c0b2fb8cec2905c58a3ae61d13794347fc82422466281b3b6a6e59304c64159ad376553f3a1a9f71b55322a4fb11651777a22801d9047c5c233a898866b4889a7619ba565aa731d989ca201035ee81f3c0342bf96cbbdd94ddde04ea6c44dc978a04aeb0d64d30414e308d6207d399776e80c820f50b3f74cadfc76c24166324e81b3c35aa976bacdf63585db6133de1728365367d038c2e6d934789871cf80aeae59875ad54a80f41c0117c512345d58cb521d200dbfd230568a9108700be2820315a271dc4a5524d7c63f08a7ed2172f8dc1e7087959cb88e599056389abfe9003d5678768f023fcf198fc2d59da004272fdb9c02f1ba1447c7e61956a9d88b64eb5037428df4aa6391344281c21b6fb84ec3f115cd856ee6cc00e4d95b7cc98d010b51db8b2bc3b43d8c981ff37259334b17b10986a39a4c988431b7e033473a63d672bb8ad3798364ae00923e9392094b93c877b1ce896b4af5934c6dd460c0bc729bab7f5b169a37180ad27404ea40280cd55f58a25a1e63c5cc566a6cb229a5c34ef654c6b71425bd57acafc940f5c3959286186f709057e110d48811a577820a88bd6dea298921b381ac77f13abc360cb59b33142064c3b9a56c748bbc7e7620ae3ab868b913f18764017987c068020a3a8c9e295114830f8f996284a37b73f476919a17d8fc3dd8c9b025b0a87264a5584009fbf45221840623e13430baa4c2d3bc7d478634dc9552b49b5497c400703bf75798dc73ce4d730ae9f358734532eae47f11f7cb44d415ba9c96a7335aa8b42ed1661b2b803613777b0828af4bb486be776ebf46ad493c8126493407098ca0e41e198409617aab404c9a5a83468f9a681eacbd96b671a0898496652c7b11be78208979b310ade80205035ce2bb33706426852097291510d0984d36b349a48c76b6e9489ae0c0fd419310486690a72680d16acb8921b40a0f82f5a95c457d8a16021c919d1a23b39f6ac470e1c8d547b02751b1c2040827733cf6e9018694bfd7eacd1e07b7a7c83e22076a318b895b06108b6499a719af9552495ff642de91698e3459e8a8b8d3711fdf9c8b7e56517f600c47e6b9aeb50c65c0943cc741c8f3b4b91b74708354b2d185c211663367483201717169a13f7ba20eb7601d716ee5637d3083605c027fdd08029f06063dd2b8b9f3ae0850a1b92299e30b718df44341923896ea808da925bd3bc337fbc018f2cfcdac1adee304ede55764e58165a237b8f9ae4144928c7597af9065a63b13e3d87dedd096e44701f01b50fe235834ac63ca0a584e060fbf717cc7d8c01dba13e6a7048fbb259d57cbfcca4bf4e5c077ca73f42c17f91773cabc6c0ad933e6c60d8d719a944705f4d816e66594a334c1ec4227eef444c48c7b726273ef134c5e1b2165e6532f832b41b0665e6c5cd996859800420de8546b0b96f4d3380049793fe30db3497de3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d94f62e0847061a998f6feb39bafa6d6e36bd2fc0d2c907d17ac58893c3b39d807b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2" diff --git a/tests/crypto/mlkem_1_reject_checks.rce b/tests/crypto/mlkem_1_reject_checks.rce new file mode 100644 index 00000000..92214789 --- /dev/null +++ b/tests/crypto/mlkem_1_reject_checks.rce @@ -0,0 +1,4 @@ +# needs: crypto pq +# ML-KEM-768 known answers (FIPS 203 internal algorithms, seeds d, z, m given), generated with the independent Python package kyber-py 1.2.0 (a FIPS 203 implementation): vector 1. One operation per file (comptime fuel). +# a ciphertext with one flipped byte: implicit rejection key +check mlkem_decaps("4b3ba9a92a8f271a46a8e76f5b16b8d2ca8e68b829446c7beb1490283a82bb69a982568d0df51c8d61020b632c5c6727f5c70a7506afbc4b25bc0b7b3f9525c0aa8050e791e98c18d2886d82a3b0729085a701c0c4648dd3218d4c057562b59168d38714b69422a08b065cad1e485a091350fa0c0b2fb8cec2905c58a3ae61d13794347fc82422466281b3b6a6e59304c64159ad376553f3a1a9f71b55322a4fb11651777a22801d9047c5c233a898866b4889a7619ba565aa731d989ca201035ee81f3c0342bf96cbbdd94ddde04ea6c44dc978a04aeb0d64d30414e308d6207d399776e80c820f50b3f74cadfc76c24166324e81b3c35aa976bacdf63585db6133de1728365367d038c2e6d934789871cf80aeae59875ad54a80f41c0117c512345d58cb521d200dbfd230568a9108700be2820315a271dc4a5524d7c63f08a7ed2172f8dc1e7087959cb88e599056389abfe9003d5678768f023fcf198fc2d59da004272fdb9c02f1ba1447c7e61956a9d88b64eb5037428df4aa6391344281c21b6fb84ec3f115cd856ee6cc00e4d95b7cc98d010b51db8b2bc3b43d8c981ff37259334b17b10986a39a4c988431b7e033473a63d672bb8ad3798364ae00923e9392094b93c877b1ce896b4af5934c6dd460c0bc729bab7f5b169a37180ad27404ea40280cd55f58a25a1e63c5cc566a6cb229a5c34ef654c6b71425bd57acafc940f5c3959286186f709057e110d48811a577820a88bd6dea298921b381ac77f13abc360cb59b33142064c3b9a56c748bbc7e7620ae3ab868b913f18764017987c068020a3a8c9e295114830f8f996284a37b73f476919a17d8fc3dd8c9b025b0a87264a5584009fbf45221840623e13430baa4c2d3bc7d478634dc9552b49b5497c400703bf75798dc73ce4d730ae9f358734532eae47f11f7cb44d415ba9c96a7335aa8b42ed1661b2b803613777b0828af4bb486be776ebf46ad493c8126493407098ca0e41e198409617aab404c9a5a83468f9a681eacbd96b671a0898496652c7b11be78208979b310ade80205035ce2bb33706426852097291510d0984d36b349a48c76b6e9489ae0c0fd419310486690a72680d16acb8921b40a0f82f5a95c457d8a16021c919d1a23b39f6ac470e1c8d547b02751b1c2040827733cf6e9018694bfd7eacd1e07b7a7c83e22076a318b895b06108b6499a719af9552495ff642de91698e3459e8a8b8d3711fdf9c8b7e56517f600c47e6b9aeb50c65c0943cc741c8f3b4b91b74708354b2d185c211663367483201717169a13f7ba20eb7601d716ee5637d3083605c027fdd08029f06063dd2b8b9f3ae0850a1b92299e30b718df44341923896ea808da925bd3bc337fbc018f2cfcdac1adee304ede55764e58165a237b8f9ae4144928c7597af9065a63b13e3d87dedd096e44701f01b50fe235834ac63ca0a584e060fbf717cc7d8c01dba13e6a7048fbb259d57cbfcca4bf4e5c077ca73f42c17f91773cabc6c0ad933e6c60d8d719a944705f4d816e66594a334c1ec4227eef444c48c7b726273ef134c5e1b2165e6532f832b41b0665e6c5cd996859800420de8546b0b96f4d3380049793fe30db3497de3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d94f62e0847061a998f6feb39bafa6d6e36bd2fc0d2c907d17ac58893c3b39d807b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2", "fc6b55a3f160f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17460124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1eb9") == "07e22558b7231f159364cf00f3e38559caa9bb5dcbd5afe5eb1fd8ba7bdaf016" diff --git a/tests/crypto/mlkem_2_decaps_checks.rce b/tests/crypto/mlkem_2_decaps_checks.rce new file mode 100644 index 00000000..415a97d3 --- /dev/null +++ b/tests/crypto/mlkem_2_decaps_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto pq +# ML-KEM-768 known answers (FIPS 203 internal algorithms, seeds d, z, m given), generated with the independent Python package kyber-py 1.2.0 (a FIPS 203 implementation): vector 2. One operation per file (comptime fuel). +check mlkem_decaps("0ddb564034a3e659af272a360e4626cea12f0929ac1b3458637c87ab027d56e28ed5890a9878cb1894589c27a702d07375e14266a40a58fa0e71d7cbb1aa872fdb5ab5a5a6165b473690659256059c4508b80babbea42a3058cc1acb227d293afc98114c32655ba267a49c91fac78806c246d3779a99f50c6f4b3d94295e4fb853d8e24a073996ea7c2d7c10394bf44601e67fd583263ef99a97639d426a4825ac8e6c938718531feaa0169e6b85b4c728d9589589e7a611b371baea289e848448e3acead99dce3bb3996074d4079dade4caf7a169aaf44268c5098d83a7e2c1a5946c1f7daaadbe449fb839287193247d6237b5b49126375abc4156fd7ca4ab581e02188e647720ee857e9e48af3d5a08c38b7bf61a4da2a0180c6447138c4adc4b99c6a6902a863a3c5b95460b6e911368a704ae3f0003aa4a34a0a566a891bbecf98e7fccb90f19bea6f30675360e930bce86b0ae9e231251b77dddc7af9079624e71c65b12717612b1ccb91dac1c1f6d52cdf49835c78834a3a7c82e86406263c47f6ac249c64a40f3c11ad581c5747a5db27a341724510931d3b1550e04a17d455e08c3a3a1b30b8425203021629b4535fdf67fc0d49790937ef9562da9a97d0e78c95b74b0ba239e430349c8009c35f9428a41676eea917e4213a3c203fa247eec0cae0a1a8f9fdb59c573aa8b52bdc0ba03ca7334cc6373ff351e4ce6c2ee3c66c4998c9d9b48e4327310655d47c0c226c98a92a6ca7dec5147b37d69bacd0d9a97997508bd3b3784023a1973804010b5b80c8e35a36419b9cfbd19c6d3121af1327b2435c9e690a2f22b70c0e9645cf24349038dd3d94afa996efc8a27ca8a00989b575ff0b0f081a8b044c9cd194d0f956c5ef5a663523259e3bb4aac46908406175c15e42b6b8631a2f4ba8a8b867acd975b8f1a44e7da1d28c9a5f1628b83c865f12b8859ca922f5b7492b7a58f5886cd7a09fb36acfc8684dcdbbdc58919a867a062d35a7bc0cbb8f5b2ffc78f31252fa0e817f796477db15fc7670657254fd8b6a6dcb66ae8c798b7a86bd053241bc4bd57a03356809a5bababa452561b3935da859a8e7685b6b803ee301ede7354eae355a5940c4ea7b5048b1faec13dce35c8640ca81db89ef62a4d3082addb967e25da46e05ab70fd5ade9e83cf72c955c7932235acdeb323c717ba537288a416b8ec2d47bea3200974cc3213c449dd191a834caabf40e1dd197edf798dd01c61f498211ccca6fa351115b6adc21c8143019fcd590f9288ffd066cafc628573c068171bc65209c4540595c78955482ca45e0c533c02818a30791f462b522338715598f8b57d1e886e5867f0c425151f5647c4342928a9ef9a9a3068671c752453357739d2871f4b55ca9093272d0088be06e743b5893704ad5029aa210ce746b968c6931ca693cabb9a233c148a0acc0db810b08d28ec906c124fa0f1b5b34a74259733986d37746d6e04c2b9a3e1c906bf3d0b61ec6747775766b3acdba72183481192213156ea792bb1c19a15840e945821b097f24f18e8131269df904078537008a961015b950128705413a86c6304d81916f856af254888ac1a34802a6e53227c520bef6eb75a1abb2a2a9571674b111cc2d2de0b1c698554b60910c4584abd084bef0a5f97850b530b60a274aa9984116e6be6f62cd310679de7bb2ff339fb5688a168570460039cf865a02864b08c07bedb2124dd9314ff3942847201bb00f43ca56bde0b2e20c0a94ca16ce554a11ccb750ca5173ea715ec63f35b449cb121a5cf5a33054085f145949b4a36be0a7c63a44c7990ef6f49e3673312d979f7e5273efe48166ba4cc54a5a061c1b3a485689284354cb670eb369773cc1493baae8a5a5a73596958c8efbc1cb18d211da3a0c3f6a06d6fc92bbc522aa500bf56b682fe1abeb5753bb98010f2a12266ace0b70b1916347579a28ef2745995107da5327dc482356621923b5a2dc42cda9eacae83b24fa88bfb27c4ce6497d65127579ca37f1790851a8b750837bc03912d858abc78a3a1eea6265b08f66568d427236e4fc393f1c3d70891fb9800d1bb89471695c53b8a1d338a04ed3901fc71d2614409777a6bfab35840084f007236c0938ae40b189d4780c471c2c9930824341214bc30f799f2642a32517bca4c1851b708699094b1510bfd2d08b783cabf471c694276dec77aac38a608cf5c1ef83c5c2367bd3265b4023b007a6620c3c005820440b2a70d92a3cd9f5864f3517c9f492c22807b6a3bf5df69689e47cddc51e3a19b7e905916bcc0b88841084d91215ab368392aaa3c027005570ea2bcaaed5c16e024e01e668673cada38062b9aa4fa9377e08871ca676b4eec3be51c0596c0b6341aa73fe24cc29996ed962be3c77485082816fe18238b720d0c74128403421f67bdbc6292a63aec22206ff62ce65081cb3bba99155a028340a0cda11dad1232894905c1187b320ad1f834277c9c5b3706e93cc39112552fcdb7d8d3047621256739c02a1170e894703bbbb4179247fc8077fc2c1a1c9460d64fa73fc0698901873b7f7656d48a891e8a5b5e605140167056c66a0c97074096b101a7f99f1a3005a23a5596d4656266927bc75299232c76bbc20854dd6bc0d721c2f0bbf5497b56b13386a835f9d8b7dc5f955d3102beaf11f22a2171e06857f85c03a7b0cfe959fe55753380a2b10c583fec3a02c68129dd33db2f40106ab09e98c7c39993e0c82a819d32bfcb89203a83ea76303cca2b505923461c608392964e5e47f28dcc4a38bcd4f2534bb734a326abf51469403d6ba7d312810d6ca6bb13ec9ec0a7512094ce309387c6271d09fdc387d8eb3149da3519a43b84c714e527781ef9848769577e1a398161c2972eb25c7b38e265364c2d4c8fa7158cbb9270f3685262b77138b5ffab59ef7822f884657c1298e9be938002b5679cc7bc2d5163f7993ea7439ac556a24e278e415a8c1021c2a5a74859a94545ccaec7b2955e64a77b15f7f416815c91c0d327bc0991f40590b30725a1fb7c859ec799dc47e36c73f3abb8dd557a932286dac6436e270b5c92c985fb87a1e02abb2c85becac1e09725f26e827bc01232f1caaaab9cb482547dce19bfb94536de5399328cb3f74be6d316d9f47a0844607ed36b2a55c0b93d4bfee03c207dba2ceb23bd79738f8c0aaa8c863298a5fe8961d042140d8e06ecbe39582e2b76705a04da5958ce93073031e3a7c38bbd972ae491c81c635aab55da9001a5318ef469254c9c418602009a87e7b1cc76cf67da12368f93ba4fc774a3dbb54f39a580b8175b3833b18eefac8bf2cdb442badf65e7c2a9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2", "cd316fe79c9d711165040d3ece5406744f620c7b4a281c4b9424928c04c091ec45176eaf00a2359456b6c4b4b9b5d0d93751878a705061c9f8e369181cfccdb3a3d9fea4c277f01047513063750cfbd9c62bec7c2c00a8e2bb9c6a05f1718138b1c58401614e2cce237144c928ba8cb19eb20d0521b9496be15f738eb965a19bad76b841c2ad7b827f558e607c5fe831b62ba94df78f08822b7a13a7e8d9be695fd9205b02f6ff70ac87a1715e2757cec72419249d401c087f2bd20463f3197adcc8be0f48b26443a19abdeecef524c0d2a0787bfa088d6b8e30ca450646fb250bf81ce52985a61e1acf95d3eaa012ecca29ea79ec931510538242ed78903538d302259a02e7079ff67b55e42b039a8be2ff1c801668f8782e764325798381180402f90b25e6ae85e31e6d96e84e34a7db29257f346927ff10ea15c756b241d40472c49a6ae4b8b8c088711bef0063d38ec125ea3319b7ff751fa38f000aadc8734aecb9180ef66c6f918c541f909196b586cf9ebae7007c0f887b45583fe5a0864d747e441c0da30a2d4191516921a687b0f0695a663ddd9d1984828e111c905aece817c55c27c23eb1a8a1dcd9714dbdeb0d4efe7d6f24701e6ffacbaf5aa0b184af8766337fcf74641f27c0ec5b363cd33f2c3d8c0e58d145dbf390f9a87696d632e79bca275116eff442ba1192f5082aa1470f836105b4b83eb128bfa6e75b4a4004f9506b9cd0989f8006efea9efad9a337ca61f7600380302b9f3799d0875f018bb347f0cb621784588ffecb129eb084cbe9da6b3d263d264518a32a104108a136a3ebfa009ed0a9b06a11725a6dbfa7842c1af2db3cda12ceda79cc9d9b25eb51eca2180f43de0ecbf0d9bd8910f10a5eb9ed1638370a38f035c6256b03305250c30338a4c94c8dcfb52c97cca63d767a476955108378b65c59fd76d8e48079edba47dcc79e06fb1f6fb99e93ef5c627c94ecd61cda710f7fe5f1120405479b9e9d01abdc1d5ed4146a608f6091eb683aae66b2213c6b8309e912e4ac124d0869e3d1cd1a32665a96ae37229da7c55a1ccc3c346bbf97711b1e7c28e2900dab1cf80164d3cbe2dcaf3c36a7f5e06e6d29b2118ab5a7a99e2b72b8de4dc2c644d875f437d75d840e8be023ec6fd3bc32bcfec7e852a20739e7ee382278fafa16737c3fbee8cf952ce014b89e7f49a982ba90a523624ddc66b90a047a559ddc87470f55593c40f2d818e086e230aa4408faaf89fdc650d3bcbec816e65c2c17745b3d535479f17622d34841c213baa139328a395fbc440c8f8434081863d261db2b1ca03217aa97cd2564eed3c4e45eb4a6fa6beaff56346dd41f2751e05c3011d6479cdfb6a32aa72819144f0aa04d39d92f6f7893717027f4384f9986f42a287b0aa4322fe6f0e5e696c3889388b5d445c06c496e23d5222d2a019632f938444394dd477c45182a50812687d9cb690b06ab7993a9ce5ab217c4cd2615c77953675171aeaf3995626e08965848308ac02173c1c08970c5210e2d864884") == "e11d8cf03b99c6dea9d378e34131b17ecb3a2efa7024823d26e6c01f6fbbd5d2" diff --git a/tests/crypto/mlkem_2_encaps_checks.rce b/tests/crypto/mlkem_2_encaps_checks.rce new file mode 100644 index 00000000..700497fb --- /dev/null +++ b/tests/crypto/mlkem_2_encaps_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto pq +# ML-KEM-768 known answers (FIPS 203 internal algorithms, seeds d, z, m given), generated with the independent Python package kyber-py 1.2.0 (a FIPS 203 implementation): vector 2. One operation per file (comptime fuel). +check mlkem_encaps("a2a9571674b111cc2d2de0b1c698554b60910c4584abd084bef0a5f97850b530b60a274aa9984116e6be6f62cd310679de7bb2ff339fb5688a168570460039cf865a02864b08c07bedb2124dd9314ff3942847201bb00f43ca56bde0b2e20c0a94ca16ce554a11ccb750ca5173ea715ec63f35b449cb121a5cf5a33054085f145949b4a36be0a7c63a44c7990ef6f49e3673312d979f7e5273efe48166ba4cc54a5a061c1b3a485689284354cb670eb369773cc1493baae8a5a5a73596958c8efbc1cb18d211da3a0c3f6a06d6fc92bbc522aa500bf56b682fe1abeb5753bb98010f2a12266ace0b70b1916347579a28ef2745995107da5327dc482356621923b5a2dc42cda9eacae83b24fa88bfb27c4ce6497d65127579ca37f1790851a8b750837bc03912d858abc78a3a1eea6265b08f66568d427236e4fc393f1c3d70891fb9800d1bb89471695c53b8a1d338a04ed3901fc71d2614409777a6bfab35840084f007236c0938ae40b189d4780c471c2c9930824341214bc30f799f2642a32517bca4c1851b708699094b1510bfd2d08b783cabf471c694276dec77aac38a608cf5c1ef83c5c2367bd3265b4023b007a6620c3c005820440b2a70d92a3cd9f5864f3517c9f492c22807b6a3bf5df69689e47cddc51e3a19b7e905916bcc0b88841084d91215ab368392aaa3c027005570ea2bcaaed5c16e024e01e668673cada38062b9aa4fa9377e08871ca676b4eec3be51c0596c0b6341aa73fe24cc29996ed962be3c77485082816fe18238b720d0c74128403421f67bdbc6292a63aec22206ff62ce65081cb3bba99155a028340a0cda11dad1232894905c1187b320ad1f834277c9c5b3706e93cc39112552fcdb7d8d3047621256739c02a1170e894703bbbb4179247fc8077fc2c1a1c9460d64fa73fc0698901873b7f7656d48a891e8a5b5e605140167056c66a0c97074096b101a7f99f1a3005a23a5596d4656266927bc75299232c76bbc20854dd6bc0d721c2f0bbf5497b56b13386a835f9d8b7dc5f955d3102beaf11f22a2171e06857f85c03a7b0cfe959fe55753380a2b10c583fec3a02c68129dd33db2f40106ab09e98c7c39993e0c82a819d32bfcb89203a83ea76303cca2b505923461c608392964e5e47f28dcc4a38bcd4f2534bb734a326abf51469403d6ba7d312810d6ca6bb13ec9ec0a7512094ce309387c6271d09fdc387d8eb3149da3519a43b84c714e527781ef9848769577e1a398161c2972eb25c7b38e265364c2d4c8fa7158cbb9270f3685262b77138b5ffab59ef7822f884657c1298e9be938002b5679cc7bc2d5163f7993ea7439ac556a24e278e415a8c1021c2a5a74859a94545ccaec7b2955e64a77b15f7f416815c91c0d327bc0991f40590b30725a1fb7c859ec799dc47e36c73f3abb8dd557a932286dac6436e270b5c92c985fb87a1e02abb2c85becac1e09725f26e827bc01232f1caaaab9cb482547dce19bfb94536de5399328cb3f74be6d316d9f47a0844607ed36b2a55c0b93d4bfee03c207dba2ceb23bd79738f8c0aaa8c863298a5fe8961d042140d8e06ecbe39582e2b76705a04da5958ce93073031e3a7c38bbd972ae491c81c635aab55da9001a5318ef469254c9c418602009a87e7b1cc76cf67da12368", "a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222") == "cd316fe79c9d711165040d3ece5406744f620c7b4a281c4b9424928c04c091ec45176eaf00a2359456b6c4b4b9b5d0d93751878a705061c9f8e369181cfccdb3a3d9fea4c277f01047513063750cfbd9c62bec7c2c00a8e2bb9c6a05f1718138b1c58401614e2cce237144c928ba8cb19eb20d0521b9496be15f738eb965a19bad76b841c2ad7b827f558e607c5fe831b62ba94df78f08822b7a13a7e8d9be695fd9205b02f6ff70ac87a1715e2757cec72419249d401c087f2bd20463f3197adcc8be0f48b26443a19abdeecef524c0d2a0787bfa088d6b8e30ca450646fb250bf81ce52985a61e1acf95d3eaa012ecca29ea79ec931510538242ed78903538d302259a02e7079ff67b55e42b039a8be2ff1c801668f8782e764325798381180402f90b25e6ae85e31e6d96e84e34a7db29257f346927ff10ea15c756b241d40472c49a6ae4b8b8c088711bef0063d38ec125ea3319b7ff751fa38f000aadc8734aecb9180ef66c6f918c541f909196b586cf9ebae7007c0f887b45583fe5a0864d747e441c0da30a2d4191516921a687b0f0695a663ddd9d1984828e111c905aece817c55c27c23eb1a8a1dcd9714dbdeb0d4efe7d6f24701e6ffacbaf5aa0b184af8766337fcf74641f27c0ec5b363cd33f2c3d8c0e58d145dbf390f9a87696d632e79bca275116eff442ba1192f5082aa1470f836105b4b83eb128bfa6e75b4a4004f9506b9cd0989f8006efea9efad9a337ca61f7600380302b9f3799d0875f018bb347f0cb621784588ffecb129eb084cbe9da6b3d263d264518a32a104108a136a3ebfa009ed0a9b06a11725a6dbfa7842c1af2db3cda12ceda79cc9d9b25eb51eca2180f43de0ecbf0d9bd8910f10a5eb9ed1638370a38f035c6256b03305250c30338a4c94c8dcfb52c97cca63d767a476955108378b65c59fd76d8e48079edba47dcc79e06fb1f6fb99e93ef5c627c94ecd61cda710f7fe5f1120405479b9e9d01abdc1d5ed4146a608f6091eb683aae66b2213c6b8309e912e4ac124d0869e3d1cd1a32665a96ae37229da7c55a1ccc3c346bbf97711b1e7c28e2900dab1cf80164d3cbe2dcaf3c36a7f5e06e6d29b2118ab5a7a99e2b72b8de4dc2c644d875f437d75d840e8be023ec6fd3bc32bcfec7e852a20739e7ee382278fafa16737c3fbee8cf952ce014b89e7f49a982ba90a523624ddc66b90a047a559ddc87470f55593c40f2d818e086e230aa4408faaf89fdc650d3bcbec816e65c2c17745b3d535479f17622d34841c213baa139328a395fbc440c8f8434081863d261db2b1ca03217aa97cd2564eed3c4e45eb4a6fa6beaff56346dd41f2751e05c3011d6479cdfb6a32aa72819144f0aa04d39d92f6f7893717027f4384f9986f42a287b0aa4322fe6f0e5e696c3889388b5d445c06c496e23d5222d2a019632f938444394dd477c45182a50812687d9cb690b06ab7993a9ce5ab217c4cd2615c77953675171aeaf3995626e08965848308ac02173c1c08970c5210e2d864884.e11d8cf03b99c6dea9d378e34131b17ecb3a2efa7024823d26e6c01f6fbbd5d2" diff --git a/tests/crypto/mlkem_2_keygen_checks.rce b/tests/crypto/mlkem_2_keygen_checks.rce new file mode 100644 index 00000000..e2ff87df --- /dev/null +++ b/tests/crypto/mlkem_2_keygen_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto pq +# ML-KEM-768 known answers (FIPS 203 internal algorithms, seeds d, z, m given), generated with the independent Python package kyber-py 1.2.0 (a FIPS 203 implementation): vector 2. One operation per file (comptime fuel). +check mlkem_keygen("47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254", "9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2") == "a2a9571674b111cc2d2de0b1c698554b60910c4584abd084bef0a5f97850b530b60a274aa9984116e6be6f62cd310679de7bb2ff339fb5688a168570460039cf865a02864b08c07bedb2124dd9314ff3942847201bb00f43ca56bde0b2e20c0a94ca16ce554a11ccb750ca5173ea715ec63f35b449cb121a5cf5a33054085f145949b4a36be0a7c63a44c7990ef6f49e3673312d979f7e5273efe48166ba4cc54a5a061c1b3a485689284354cb670eb369773cc1493baae8a5a5a73596958c8efbc1cb18d211da3a0c3f6a06d6fc92bbc522aa500bf56b682fe1abeb5753bb98010f2a12266ace0b70b1916347579a28ef2745995107da5327dc482356621923b5a2dc42cda9eacae83b24fa88bfb27c4ce6497d65127579ca37f1790851a8b750837bc03912d858abc78a3a1eea6265b08f66568d427236e4fc393f1c3d70891fb9800d1bb89471695c53b8a1d338a04ed3901fc71d2614409777a6bfab35840084f007236c0938ae40b189d4780c471c2c9930824341214bc30f799f2642a32517bca4c1851b708699094b1510bfd2d08b783cabf471c694276dec77aac38a608cf5c1ef83c5c2367bd3265b4023b007a6620c3c005820440b2a70d92a3cd9f5864f3517c9f492c22807b6a3bf5df69689e47cddc51e3a19b7e905916bcc0b88841084d91215ab368392aaa3c027005570ea2bcaaed5c16e024e01e668673cada38062b9aa4fa9377e08871ca676b4eec3be51c0596c0b6341aa73fe24cc29996ed962be3c77485082816fe18238b720d0c74128403421f67bdbc6292a63aec22206ff62ce65081cb3bba99155a028340a0cda11dad1232894905c1187b320ad1f834277c9c5b3706e93cc39112552fcdb7d8d3047621256739c02a1170e894703bbbb4179247fc8077fc2c1a1c9460d64fa73fc0698901873b7f7656d48a891e8a5b5e605140167056c66a0c97074096b101a7f99f1a3005a23a5596d4656266927bc75299232c76bbc20854dd6bc0d721c2f0bbf5497b56b13386a835f9d8b7dc5f955d3102beaf11f22a2171e06857f85c03a7b0cfe959fe55753380a2b10c583fec3a02c68129dd33db2f40106ab09e98c7c39993e0c82a819d32bfcb89203a83ea76303cca2b505923461c608392964e5e47f28dcc4a38bcd4f2534bb734a326abf51469403d6ba7d312810d6ca6bb13ec9ec0a7512094ce309387c6271d09fdc387d8eb3149da3519a43b84c714e527781ef9848769577e1a398161c2972eb25c7b38e265364c2d4c8fa7158cbb9270f3685262b77138b5ffab59ef7822f884657c1298e9be938002b5679cc7bc2d5163f7993ea7439ac556a24e278e415a8c1021c2a5a74859a94545ccaec7b2955e64a77b15f7f416815c91c0d327bc0991f40590b30725a1fb7c859ec799dc47e36c73f3abb8dd557a932286dac6436e270b5c92c985fb87a1e02abb2c85becac1e09725f26e827bc01232f1caaaab9cb482547dce19bfb94536de5399328cb3f74be6d316d9f47a0844607ed36b2a55c0b93d4bfee03c207dba2ceb23bd79738f8c0aaa8c863298a5fe8961d042140d8e06ecbe39582e2b76705a04da5958ce93073031e3a7c38bbd972ae491c81c635aab55da9001a5318ef469254c9c418602009a87e7b1cc76cf67da12368.0ddb564034a3e659af272a360e4626cea12f0929ac1b3458637c87ab027d56e28ed5890a9878cb1894589c27a702d07375e14266a40a58fa0e71d7cbb1aa872fdb5ab5a5a6165b473690659256059c4508b80babbea42a3058cc1acb227d293afc98114c32655ba267a49c91fac78806c246d3779a99f50c6f4b3d94295e4fb853d8e24a073996ea7c2d7c10394bf44601e67fd583263ef99a97639d426a4825ac8e6c938718531feaa0169e6b85b4c728d9589589e7a611b371baea289e848448e3acead99dce3bb3996074d4079dade4caf7a169aaf44268c5098d83a7e2c1a5946c1f7daaadbe449fb839287193247d6237b5b49126375abc4156fd7ca4ab581e02188e647720ee857e9e48af3d5a08c38b7bf61a4da2a0180c6447138c4adc4b99c6a6902a863a3c5b95460b6e911368a704ae3f0003aa4a34a0a566a891bbecf98e7fccb90f19bea6f30675360e930bce86b0ae9e231251b77dddc7af9079624e71c65b12717612b1ccb91dac1c1f6d52cdf49835c78834a3a7c82e86406263c47f6ac249c64a40f3c11ad581c5747a5db27a341724510931d3b1550e04a17d455e08c3a3a1b30b8425203021629b4535fdf67fc0d49790937ef9562da9a97d0e78c95b74b0ba239e430349c8009c35f9428a41676eea917e4213a3c203fa247eec0cae0a1a8f9fdb59c573aa8b52bdc0ba03ca7334cc6373ff351e4ce6c2ee3c66c4998c9d9b48e4327310655d47c0c226c98a92a6ca7dec5147b37d69bacd0d9a97997508bd3b3784023a1973804010b5b80c8e35a36419b9cfbd19c6d3121af1327b2435c9e690a2f22b70c0e9645cf24349038dd3d94afa996efc8a27ca8a00989b575ff0b0f081a8b044c9cd194d0f956c5ef5a663523259e3bb4aac46908406175c15e42b6b8631a2f4ba8a8b867acd975b8f1a44e7da1d28c9a5f1628b83c865f12b8859ca922f5b7492b7a58f5886cd7a09fb36acfc8684dcdbbdc58919a867a062d35a7bc0cbb8f5b2ffc78f31252fa0e817f796477db15fc7670657254fd8b6a6dcb66ae8c798b7a86bd053241bc4bd57a03356809a5bababa452561b3935da859a8e7685b6b803ee301ede7354eae355a5940c4ea7b5048b1faec13dce35c8640ca81db89ef62a4d3082addb967e25da46e05ab70fd5ade9e83cf72c955c7932235acdeb323c717ba537288a416b8ec2d47bea3200974cc3213c449dd191a834caabf40e1dd197edf798dd01c61f498211ccca6fa351115b6adc21c8143019fcd590f9288ffd066cafc628573c068171bc65209c4540595c78955482ca45e0c533c02818a30791f462b522338715598f8b57d1e886e5867f0c425151f5647c4342928a9ef9a9a3068671c752453357739d2871f4b55ca9093272d0088be06e743b5893704ad5029aa210ce746b968c6931ca693cabb9a233c148a0acc0db810b08d28ec906c124fa0f1b5b34a74259733986d37746d6e04c2b9a3e1c906bf3d0b61ec6747775766b3acdba72183481192213156ea792bb1c19a15840e945821b097f24f18e8131269df904078537008a961015b950128705413a86c6304d81916f856af254888ac1a34802a6e53227c520bef6eb75a1abb2a2a9571674b111cc2d2de0b1c698554b60910c4584abd084bef0a5f97850b530b60a274aa9984116e6be6f62cd310679de7bb2ff339fb5688a168570460039cf865a02864b08c07bedb2124dd9314ff3942847201bb00f43ca56bde0b2e20c0a94ca16ce554a11ccb750ca5173ea715ec63f35b449cb121a5cf5a33054085f145949b4a36be0a7c63a44c7990ef6f49e3673312d979f7e5273efe48166ba4cc54a5a061c1b3a485689284354cb670eb369773cc1493baae8a5a5a73596958c8efbc1cb18d211da3a0c3f6a06d6fc92bbc522aa500bf56b682fe1abeb5753bb98010f2a12266ace0b70b1916347579a28ef2745995107da5327dc482356621923b5a2dc42cda9eacae83b24fa88bfb27c4ce6497d65127579ca37f1790851a8b750837bc03912d858abc78a3a1eea6265b08f66568d427236e4fc393f1c3d70891fb9800d1bb89471695c53b8a1d338a04ed3901fc71d2614409777a6bfab35840084f007236c0938ae40b189d4780c471c2c9930824341214bc30f799f2642a32517bca4c1851b708699094b1510bfd2d08b783cabf471c694276dec77aac38a608cf5c1ef83c5c2367bd3265b4023b007a6620c3c005820440b2a70d92a3cd9f5864f3517c9f492c22807b6a3bf5df69689e47cddc51e3a19b7e905916bcc0b88841084d91215ab368392aaa3c027005570ea2bcaaed5c16e024e01e668673cada38062b9aa4fa9377e08871ca676b4eec3be51c0596c0b6341aa73fe24cc29996ed962be3c77485082816fe18238b720d0c74128403421f67bdbc6292a63aec22206ff62ce65081cb3bba99155a028340a0cda11dad1232894905c1187b320ad1f834277c9c5b3706e93cc39112552fcdb7d8d3047621256739c02a1170e894703bbbb4179247fc8077fc2c1a1c9460d64fa73fc0698901873b7f7656d48a891e8a5b5e605140167056c66a0c97074096b101a7f99f1a3005a23a5596d4656266927bc75299232c76bbc20854dd6bc0d721c2f0bbf5497b56b13386a835f9d8b7dc5f955d3102beaf11f22a2171e06857f85c03a7b0cfe959fe55753380a2b10c583fec3a02c68129dd33db2f40106ab09e98c7c39993e0c82a819d32bfcb89203a83ea76303cca2b505923461c608392964e5e47f28dcc4a38bcd4f2534bb734a326abf51469403d6ba7d312810d6ca6bb13ec9ec0a7512094ce309387c6271d09fdc387d8eb3149da3519a43b84c714e527781ef9848769577e1a398161c2972eb25c7b38e265364c2d4c8fa7158cbb9270f3685262b77138b5ffab59ef7822f884657c1298e9be938002b5679cc7bc2d5163f7993ea7439ac556a24e278e415a8c1021c2a5a74859a94545ccaec7b2955e64a77b15f7f416815c91c0d327bc0991f40590b30725a1fb7c859ec799dc47e36c73f3abb8dd557a932286dac6436e270b5c92c985fb87a1e02abb2c85becac1e09725f26e827bc01232f1caaaab9cb482547dce19bfb94536de5399328cb3f74be6d316d9f47a0844607ed36b2a55c0b93d4bfee03c207dba2ceb23bd79738f8c0aaa8c863298a5fe8961d042140d8e06ecbe39582e2b76705a04da5958ce93073031e3a7c38bbd972ae491c81c635aab55da9001a5318ef469254c9c418602009a87e7b1cc76cf67da12368f93ba4fc774a3dbb54f39a580b8175b3833b18eefac8bf2cdb442badf65e7c2a9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2" diff --git a/tests/crypto/mlkem_2_reject_checks.rce b/tests/crypto/mlkem_2_reject_checks.rce new file mode 100644 index 00000000..dc2ca5e4 --- /dev/null +++ b/tests/crypto/mlkem_2_reject_checks.rce @@ -0,0 +1,4 @@ +# needs: crypto pq +# ML-KEM-768 known answers (FIPS 203 internal algorithms, seeds d, z, m given), generated with the independent Python package kyber-py 1.2.0 (a FIPS 203 implementation): vector 2. One operation per file (comptime fuel). +# a ciphertext with one flipped byte: implicit rejection key +check mlkem_decaps("0ddb564034a3e659af272a360e4626cea12f0929ac1b3458637c87ab027d56e28ed5890a9878cb1894589c27a702d07375e14266a40a58fa0e71d7cbb1aa872fdb5ab5a5a6165b473690659256059c4508b80babbea42a3058cc1acb227d293afc98114c32655ba267a49c91fac78806c246d3779a99f50c6f4b3d94295e4fb853d8e24a073996ea7c2d7c10394bf44601e67fd583263ef99a97639d426a4825ac8e6c938718531feaa0169e6b85b4c728d9589589e7a611b371baea289e848448e3acead99dce3bb3996074d4079dade4caf7a169aaf44268c5098d83a7e2c1a5946c1f7daaadbe449fb839287193247d6237b5b49126375abc4156fd7ca4ab581e02188e647720ee857e9e48af3d5a08c38b7bf61a4da2a0180c6447138c4adc4b99c6a6902a863a3c5b95460b6e911368a704ae3f0003aa4a34a0a566a891bbecf98e7fccb90f19bea6f30675360e930bce86b0ae9e231251b77dddc7af9079624e71c65b12717612b1ccb91dac1c1f6d52cdf49835c78834a3a7c82e86406263c47f6ac249c64a40f3c11ad581c5747a5db27a341724510931d3b1550e04a17d455e08c3a3a1b30b8425203021629b4535fdf67fc0d49790937ef9562da9a97d0e78c95b74b0ba239e430349c8009c35f9428a41676eea917e4213a3c203fa247eec0cae0a1a8f9fdb59c573aa8b52bdc0ba03ca7334cc6373ff351e4ce6c2ee3c66c4998c9d9b48e4327310655d47c0c226c98a92a6ca7dec5147b37d69bacd0d9a97997508bd3b3784023a1973804010b5b80c8e35a36419b9cfbd19c6d3121af1327b2435c9e690a2f22b70c0e9645cf24349038dd3d94afa996efc8a27ca8a00989b575ff0b0f081a8b044c9cd194d0f956c5ef5a663523259e3bb4aac46908406175c15e42b6b8631a2f4ba8a8b867acd975b8f1a44e7da1d28c9a5f1628b83c865f12b8859ca922f5b7492b7a58f5886cd7a09fb36acfc8684dcdbbdc58919a867a062d35a7bc0cbb8f5b2ffc78f31252fa0e817f796477db15fc7670657254fd8b6a6dcb66ae8c798b7a86bd053241bc4bd57a03356809a5bababa452561b3935da859a8e7685b6b803ee301ede7354eae355a5940c4ea7b5048b1faec13dce35c8640ca81db89ef62a4d3082addb967e25da46e05ab70fd5ade9e83cf72c955c7932235acdeb323c717ba537288a416b8ec2d47bea3200974cc3213c449dd191a834caabf40e1dd197edf798dd01c61f498211ccca6fa351115b6adc21c8143019fcd590f9288ffd066cafc628573c068171bc65209c4540595c78955482ca45e0c533c02818a30791f462b522338715598f8b57d1e886e5867f0c425151f5647c4342928a9ef9a9a3068671c752453357739d2871f4b55ca9093272d0088be06e743b5893704ad5029aa210ce746b968c6931ca693cabb9a233c148a0acc0db810b08d28ec906c124fa0f1b5b34a74259733986d37746d6e04c2b9a3e1c906bf3d0b61ec6747775766b3acdba72183481192213156ea792bb1c19a15840e945821b097f24f18e8131269df904078537008a961015b950128705413a86c6304d81916f856af254888ac1a34802a6e53227c520bef6eb75a1abb2a2a9571674b111cc2d2de0b1c698554b60910c4584abd084bef0a5f97850b530b60a274aa9984116e6be6f62cd310679de7bb2ff339fb5688a168570460039cf865a02864b08c07bedb2124dd9314ff3942847201bb00f43ca56bde0b2e20c0a94ca16ce554a11ccb750ca5173ea715ec63f35b449cb121a5cf5a33054085f145949b4a36be0a7c63a44c7990ef6f49e3673312d979f7e5273efe48166ba4cc54a5a061c1b3a485689284354cb670eb369773cc1493baae8a5a5a73596958c8efbc1cb18d211da3a0c3f6a06d6fc92bbc522aa500bf56b682fe1abeb5753bb98010f2a12266ace0b70b1916347579a28ef2745995107da5327dc482356621923b5a2dc42cda9eacae83b24fa88bfb27c4ce6497d65127579ca37f1790851a8b750837bc03912d858abc78a3a1eea6265b08f66568d427236e4fc393f1c3d70891fb9800d1bb89471695c53b8a1d338a04ed3901fc71d2614409777a6bfab35840084f007236c0938ae40b189d4780c471c2c9930824341214bc30f799f2642a32517bca4c1851b708699094b1510bfd2d08b783cabf471c694276dec77aac38a608cf5c1ef83c5c2367bd3265b4023b007a6620c3c005820440b2a70d92a3cd9f5864f3517c9f492c22807b6a3bf5df69689e47cddc51e3a19b7e905916bcc0b88841084d91215ab368392aaa3c027005570ea2bcaaed5c16e024e01e668673cada38062b9aa4fa9377e08871ca676b4eec3be51c0596c0b6341aa73fe24cc29996ed962be3c77485082816fe18238b720d0c74128403421f67bdbc6292a63aec22206ff62ce65081cb3bba99155a028340a0cda11dad1232894905c1187b320ad1f834277c9c5b3706e93cc39112552fcdb7d8d3047621256739c02a1170e894703bbbb4179247fc8077fc2c1a1c9460d64fa73fc0698901873b7f7656d48a891e8a5b5e605140167056c66a0c97074096b101a7f99f1a3005a23a5596d4656266927bc75299232c76bbc20854dd6bc0d721c2f0bbf5497b56b13386a835f9d8b7dc5f955d3102beaf11f22a2171e06857f85c03a7b0cfe959fe55753380a2b10c583fec3a02c68129dd33db2f40106ab09e98c7c39993e0c82a819d32bfcb89203a83ea76303cca2b505923461c608392964e5e47f28dcc4a38bcd4f2534bb734a326abf51469403d6ba7d312810d6ca6bb13ec9ec0a7512094ce309387c6271d09fdc387d8eb3149da3519a43b84c714e527781ef9848769577e1a398161c2972eb25c7b38e265364c2d4c8fa7158cbb9270f3685262b77138b5ffab59ef7822f884657c1298e9be938002b5679cc7bc2d5163f7993ea7439ac556a24e278e415a8c1021c2a5a74859a94545ccaec7b2955e64a77b15f7f416815c91c0d327bc0991f40590b30725a1fb7c859ec799dc47e36c73f3abb8dd557a932286dac6436e270b5c92c985fb87a1e02abb2c85becac1e09725f26e827bc01232f1caaaab9cb482547dce19bfb94536de5399328cb3f74be6d316d9f47a0844607ed36b2a55c0b93d4bfee03c207dba2ceb23bd79738f8c0aaa8c863298a5fe8961d042140d8e06ecbe39582e2b76705a04da5958ce93073031e3a7c38bbd972ae491c81c635aab55da9001a5318ef469254c9c418602009a87e7b1cc76cf67da12368f93ba4fc774a3dbb54f39a580b8175b3833b18eefac8bf2cdb442badf65e7c2a9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2", "cd316fe79c9c711165040d3ece5406744f620c7b4a281c4b9424928c04c091ec45176eaf00a2359456b6c4b4b9b5d0d93751878a705061c9f8e369181cfccdb3a3d9fea4c277f01047513063750cfbd9c62bec7c2c00a8e2bb9c6a05f1718138b1c58401614e2cce237144c928ba8cb19eb20d0521b9496be15f738eb965a19bad76b841c2ad7b827f558e607c5fe831b62ba94df78f08822b7a13a7e8d9be695fd9205b02f6ff70ac87a1715e2757cec72419249d401c087f2bd20463f3197adcc8be0f48b26443a19abdeecef524c0d2a0787bfa088d6b8e30ca450646fb250bf81ce52985a61e1acf95d3eaa012ecca29ea79ec931510538242ed78903538d302259a02e7079ff67b55e42b039a8be2ff1c801668f8782e764325798381180402f90b25e6ae85e31e6d96e84e34a7db29257f346927ff10ea15c756b241d40472c49a6ae4b8b8c088711bef0063d38ec125ea3319b7ff751fa38f000aadc8734aecb9180ef66c6f918c541f909196b586cf9ebae7007c0f887b45583fe5a0864d747e441c0da30a2d4191516921a687b0f0695a663ddd9d1984828e111c905aece817c55c27c23eb1a8a1dcd9714dbdeb0d4efe7d6f24701e6ffacbaf5aa0b184af8766337fcf74641f27c0ec5b363cd33f2c3d8c0e58d145dbf390f9a87696d632e79bca275116eff442ba1192f5082aa1470f836105b4b83eb128bfa6e75b4a4004f9506b9cd0989f8006efea9efad9a337ca61f7600380302b9f3799d0875f018bb347f0cb621784588ffecb129eb084cbe9da6b3d263d264518a32a104108a136a3ebfa009ed0a9b06a11725a6dbfa7842c1af2db3cda12ceda79cc9d9b25eb51eca2180f43de0ecbf0d9bd8910f10a5eb9ed1638370a38f035c6256b03305250c30338a4c94c8dcfb52c97cca63d767a476955108378b65c59fd76d8e48079edba47dcc79e06fb1f6fb99e93ef5c627c94ecd61cda710f7fe5f1120405479b9e9d01abdc1d5ed4146a608f6091eb683aae66b2213c6b8309e912e4ac124d0869e3d1cd1a32665a96ae37229da7c55a1ccc3c346bbf97711b1e7c28e2900dab1cf80164d3cbe2dcaf3c36a7f5e06e6d29b2118ab5a7a99e2b72b8de4dc2c644d875f437d75d840e8be023ec6fd3bc32bcfec7e852a20739e7ee382278fafa16737c3fbee8cf952ce014b89e7f49a982ba90a523624ddc66b90a047a559ddc87470f55593c40f2d818e086e230aa4408faaf89fdc650d3bcbec816e65c2c17745b3d535479f17622d34841c213baa139328a395fbc440c8f8434081863d261db2b1ca03217aa97cd2564eed3c4e45eb4a6fa6beaff56346dd41f2751e05c3011d6479cdfb6a32aa72819144f0aa04d39d92f6f7893717027f4384f9986f42a287b0aa4322fe6f0e5e696c3889388b5d445c06c496e23d5222d2a019632f938444394dd477c45182a50812687d9cb690b06ab7993a9ce5ab217c4cd2615c77953675171aeaf3995626e08965848308ac02173c1c08970c5210e2d864884") == "8a53845ce958d7bf1d355201ba8495bd02f8641a62a254ad91c7cc8033d9aae7" diff --git a/tests/crypto/mlkem_arith_checks.rce b/tests/crypto/mlkem_arith_checks.rce new file mode 100644 index 00000000..6a009cf0 --- /dev/null +++ b/tests/crypto/mlkem_arith_checks.rce @@ -0,0 +1,25 @@ +# needs: crypto pq +# qdiv/qmod (multiply-shift division by 3329) against the exact definitions, +# and compress against the exact rounded division of FIPS 203 (4.7), over +# the whole domain x in 0..3328 for d in {1, 4, 10, 11, 5}. +fn all_q(d: i64) -> bool + var ok = true + for x in 0..3329 + let num = (x as i64 << d) + 1664 + let exact = ((x as i64 << d) * 2 + 3329) / 6658 + ok = ok and compress([x as i64], d) == [exact & ((1 << d) - 1)] + return ok +fn all_div() -> bool + var ok = true + for n in 0..70000 + ok = ok and qdiv(n * 331) == (n * 331) / 3329 and qmod(n * 331) == (n * 331) % 3329 + return ok +check all_div() +check qdiv(0) == 0 and qdiv(3328) == 0 and qdiv(3329) == 1 and qdiv(6657) == 1 and qdiv(6658) == 2 +check qdiv(22200000) == 22200000 / 3329 and qmod(22200000) == 22200000 % 3329 +check qmod(346000000) == 346000000 % 3329 +check all_q(1) +check all_q(4) +check all_q(10) +check all_q(11) +check all_q(5) diff --git a/tests/crypto/mlkem_fuel.rce b/tests/crypto/mlkem_fuel.rce new file mode 100644 index 00000000..914b0106 --- /dev/null +++ b/tests/crypto/mlkem_fuel.rce @@ -0,0 +1,13 @@ +# needs: crypto pq +# Fuel of ML-KEM-768 decapsulation under one key: the same fuel for a valid +# ciphertext and for ciphertexts rejected by implicit rejection (a flipped +# byte at the start, middle and end). Before the fix the accept and reject +# paths used different fuel, and the old text comparison was the oracle +# KyberSlash-style attacks look for. Source-level evidence only. (Different +# KEYS are not compared: the public matrix sampling depends on the public +# seed rho.) +const DK: text = "4b3ba9a92a8f271a46a8e76f5b16b8d2ca8e68b829446c7beb1490283a82bb69a982568d0df51c8d61020b632c5c6727f5c70a7506afbc4b25bc0b7b3f9525c0aa8050e791e98c18d2886d82a3b0729085a701c0c4648dd3218d4c057562b59168d38714b69422a08b065cad1e485a091350fa0c0b2fb8cec2905c58a3ae61d13794347fc82422466281b3b6a6e59304c64159ad376553f3a1a9f71b55322a4fb11651777a22801d9047c5c233a898866b4889a7619ba565aa731d989ca201035ee81f3c0342bf96cbbdd94ddde04ea6c44dc978a04aeb0d64d30414e308d6207d399776e80c820f50b3f74cadfc76c24166324e81b3c35aa976bacdf63585db6133de1728365367d038c2e6d934789871cf80aeae59875ad54a80f41c0117c512345d58cb521d200dbfd230568a9108700be2820315a271dc4a5524d7c63f08a7ed2172f8dc1e7087959cb88e599056389abfe9003d5678768f023fcf198fc2d59da004272fdb9c02f1ba1447c7e61956a9d88b64eb5037428df4aa6391344281c21b6fb84ec3f115cd856ee6cc00e4d95b7cc98d010b51db8b2bc3b43d8c981ff37259334b17b10986a39a4c988431b7e033473a63d672bb8ad3798364ae00923e9392094b93c877b1ce896b4af5934c6dd460c0bc729bab7f5b169a37180ad27404ea40280cd55f58a25a1e63c5cc566a6cb229a5c34ef654c6b71425bd57acafc940f5c3959286186f709057e110d48811a577820a88bd6dea298921b381ac77f13abc360cb59b33142064c3b9a56c748bbc7e7620ae3ab868b913f18764017987c068020a3a8c9e295114830f8f996284a37b73f476919a17d8fc3dd8c9b025b0a87264a5584009fbf45221840623e13430baa4c2d3bc7d478634dc9552b49b5497c400703bf75798dc73ce4d730ae9f358734532eae47f11f7cb44d415ba9c96a7335aa8b42ed1661b2b803613777b0828af4bb486be776ebf46ad493c8126493407098ca0e41e198409617aab404c9a5a83468f9a681eacbd96b671a0898496652c7b11be78208979b310ade80205035ce2bb33706426852097291510d0984d36b349a48c76b6e9489ae0c0fd419310486690a72680d16acb8921b40a0f82f5a95c457d8a16021c919d1a23b39f6ac470e1c8d547b02751b1c2040827733cf6e9018694bfd7eacd1e07b7a7c83e22076a318b895b06108b6499a719af9552495ff642de91698e3459e8a8b8d3711fdf9c8b7e56517f600c47e6b9aeb50c65c0943cc741c8f3b4b91b74708354b2d185c211663367483201717169a13f7ba20eb7601d716ee5637d3083605c027fdd08029f06063dd2b8b9f3ae0850a1b92299e30b718df44341923896ea808da925bd3bc337fbc018f2cfcdac1adee304ede55764e58165a237b8f9ae4144928c7597af9065a63b13e3d87dedd096e44701f01b50fe235834ac63ca0a584e060fbf717cc7d8c01dba13e6a7048fbb259d57cbfcca4bf4e5c077ca73f42c17f91773cabc6c0ad933e6c60d8d719a944705f4d816e66594a334c1ec4227eef444c48c7b726273ef134c5e1b2165e6532f832b41b0665e6c5cd996859800420de8546b0b96f4d3380049793fe30db3497de3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d94f62e0847061a998f6feb39bafa6d6e36bd2fc0d2c907d17ac58893c3b39d807b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2" +fn probe_decaps_1() -> text = mlkem_decaps(DK, "fc6b55a3f161f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17460124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1eb9") +fn probe_decaps_2() -> text = mlkem_decaps(DK, "7c6b55a3f161f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17460124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1eb9") +fn probe_decaps_3() -> text = mlkem_decaps(DK, "fc6b55a3f161f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17468124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1eb9") +fn probe_decaps_4() -> text = mlkem_decaps(DK, "fc6b55a3f161f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17460124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1e39") diff --git a/tests/crypto/mlkem_input_checks.rce b/tests/crypto/mlkem_input_checks.rce new file mode 100644 index 00000000..c3899ec4 --- /dev/null +++ b/tests/crypto/mlkem_input_checks.rce @@ -0,0 +1,11 @@ +# needs: crypto pq +# FIPS 203 7.2 and 7.3 input checks: each failing input is refused with "" (cheap +# refusals only; the valid paths are in mlkem_N_*_checks.rce). +check mlkem_encaps("e3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6", "fcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c5177f") == "" +check mlkem_encaps("010d5339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d9", "fcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c5177f") == "" +check mlkem_encaps("e3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d9", "fcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c517") == "" +check mlkem_encaps("e3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d900", "fcf0a6c700dd13e274b6fba8deea8dd9b26e4eedde3495717cac8408c9c5177f") == "" +check mlkem_decaps("4b3ba9a92a8f271a46a8e76f5b16b8d2ca8e68b829446c7beb1490283a82bb69a982568d0df51c8d61020b632c5c6727f5c70a7506afbc4b25bc0b7b3f9525c0aa8050e791e98c18d2886d82a3b0729085a701c0c4648dd3218d4c057562b59168d38714b69422a08b065cad1e485a091350fa0c0b2fb8cec2905c58a3ae61d13794347fc82422466281b3b6a6e59304c64159ad376553f3a1a9f71b55322a4fb11651777a22801d9047c5c233a898866b4889a7619ba565aa731d989ca201035ee81f3c0342bf96cbbdd94ddde04ea6c44dc978a04aeb0d64d30414e308d6207d399776e80c820f50b3f74cadfc76c24166324e81b3c35aa976bacdf63585db6133de1728365367d038c2e6d934789871cf80aeae59875ad54a80f41c0117c512345d58cb521d200dbfd230568a9108700be2820315a271dc4a5524d7c63f08a7ed2172f8dc1e7087959cb88e599056389abfe9003d5678768f023fcf198fc2d59da004272fdb9c02f1ba1447c7e61956a9d88b64eb5037428df4aa6391344281c21b6fb84ec3f115cd856ee6cc00e4d95b7cc98d010b51db8b2bc3b43d8c981ff37259334b17b10986a39a4c988431b7e033473a63d672bb8ad3798364ae00923e9392094b93c877b1ce896b4af5934c6dd460c0bc729bab7f5b169a37180ad27404ea40280cd55f58a25a1e63c5cc566a6cb229a5c34ef654c6b71425bd57acafc940f5c3959286186f709057e110d48811a577820a88bd6dea298921b381ac77f13abc360cb59b33142064c3b9a56c748bbc7e7620ae3ab868b913f18764017987c068020a3a8c9e295114830f8f996284a37b73f476919a17d8fc3dd8c9b025b0a87264a5584009fbf45221840623e13430baa4c2d3bc7d478634dc9552b49b5497c400703bf75798dc73ce4d730ae9f358734532eae47f11f7cb44d415ba9c96a7335aa8b42ed1661b2b803613777b0828af4bb486be776ebf46ad493c8126493407098ca0e41e198409617aab404c9a5a83468f9a681eacbd96b671a0898496652c7b11be78208979b310ade80205035ce2bb33706426852097291510d0984d36b349a48c76b6e9489ae0c0fd419310486690a72680d16acb8921b40a0f82f5a95c457d8a16021c919d1a23b39f6ac470e1c8d547b02751b1c2040827733cf6e9018694bfd7eacd1e07b7a7c83e22076a318b895b06108b6499a719af9552495ff642de91698e3459e8a8b8d3711fdf9c8b7e56517f600c47e6b9aeb50c65c0943cc741c8f3b4b91b74708354b2d185c211663367483201717169a13f7ba20eb7601d716ee5637d3083605c027fdd08029f06063dd2b8b9f3ae0850a1b92299e30b718df44341923896ea808da925bd3bc337fbc018f2cfcdac1adee304ede55764e58165a237b8f9ae4144928c7597af9065a63b13e3d87dedd096e44701f01b50fe235834ac63ca0a584e060fbf717cc7d8c01dba13e6a7048fbb259d57cbfcca4bf4e5c077ca73f42c17f91773cabc6c0ad933e6c60d8d719a944705f4d816e66594a334c1ec4227eef444c48c7b726273ef134c5e1b2165e6532f832b41b0665e6c5cd996859800420de8546b0b96f4d3380049793fe30db3497de3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d94f62e0847061a998f6feb39bafa6d6e36bd2fc0d2c907d17ac58893c3b39d807b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8", "fc6b55a3f161f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17460124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1eb9") == "" +check mlkem_decaps("4b3ba9a92a8f271a46a8e76f5b16b8d2ca8e68b829446c7beb1490283a82bb69a982568d0df51c8d61020b632c5c6727f5c70a7506afbc4b25bc0b7b3f9525c0aa8050e791e98c18d2886d82a3b0729085a701c0c4648dd3218d4c057562b59168d38714b69422a08b065cad1e485a091350fa0c0b2fb8cec2905c58a3ae61d13794347fc82422466281b3b6a6e59304c64159ad376553f3a1a9f71b55322a4fb11651777a22801d9047c5c233a898866b4889a7619ba565aa731d989ca201035ee81f3c0342bf96cbbdd94ddde04ea6c44dc978a04aeb0d64d30414e308d6207d399776e80c820f50b3f74cadfc76c24166324e81b3c35aa976bacdf63585db6133de1728365367d038c2e6d934789871cf80aeae59875ad54a80f41c0117c512345d58cb521d200dbfd230568a9108700be2820315a271dc4a5524d7c63f08a7ed2172f8dc1e7087959cb88e599056389abfe9003d5678768f023fcf198fc2d59da004272fdb9c02f1ba1447c7e61956a9d88b64eb5037428df4aa6391344281c21b6fb84ec3f115cd856ee6cc00e4d95b7cc98d010b51db8b2bc3b43d8c981ff37259334b17b10986a39a4c988431b7e033473a63d672bb8ad3798364ae00923e9392094b93c877b1ce896b4af5934c6dd460c0bc729bab7f5b169a37180ad27404ea40280cd55f58a25a1e63c5cc566a6cb229a5c34ef654c6b71425bd57acafc940f5c3959286186f709057e110d48811a577820a88bd6dea298921b381ac77f13abc360cb59b33142064c3b9a56c748bbc7e7620ae3ab868b913f18764017987c068020a3a8c9e295114830f8f996284a37b73f476919a17d8fc3dd8c9b025b0a87264a5584009fbf45221840623e13430baa4c2d3bc7d478634dc9552b49b5497c400703bf75798dc73ce4d730ae9f358734532eae47f11f7cb44d415ba9c96a7335aa8b42ed1661b2b803613777b0828af4bb486be776ebf46ad493c8126493407098ca0e41e198409617aab404c9a5a83468f9a681eacbd96b671a0898496652c7b11be78208979b310ade80205035ce2bb33706426852097291510d0984d36b349a48c76b6e9489ae0c0fd419310486690a72680d16acb8921b40a0f82f5a95c457d8a16021c919d1a23b39f6ac470e1c8d547b02751b1c2040827733cf6e9018694bfd7eacd1e07b7a7c83e22076a318b895b06108b6499a719af9552495ff642de91698e3459e8a8b8d3711fdf9c8b7e56517f600c47e6b9aeb50c65c0943cc741c8f3b4b91b74708354b2d185c211663367483201717169a13f7ba20eb7601d716ee5637d3083605c027fdd08029f06063dd2b8b9f3ae0850a1b92299e30b718df44341923896ea808da925bd3bc337fbc018f2cfcdac1adee304ede55764e58165a237b8f9ae4144928c7597af9065a63b13e3d87dedd096e44701f01b50fe235834ac63ca0a584e060fbf717cc7d8c01dba13e6a7048fbb259d57cbfcca4bf4e5c077ca73f42c17f91773cabc6c0ad933e6c60d8d719a944705f4d816e66594a334c1ec4227eef444c48c7b726273ef134c5e1b2165e6532f832b41b0665e6c5cd996859800420de8546b0b96f4d3380049793fe30db3497de3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d94f62e0847061a998f6feb39bafa6d6e36bd2fc0d2c907d17ac58893c3b39d807b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2", "fc6b55a3f161f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17460124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1e") == "" +check mlkem_decaps("4b3ba9a92a8f271a46a8e76f5b16b8d2ca8e68b829446c7beb1490283a82bb69a982568d0df51c8d61020b632c5c6727f5c70a7506afbc4b25bc0b7b3f9525c0aa8050e791e98c18d2886d82a3b0729085a701c0c4648dd3218d4c057562b59168d38714b69422a08b065cad1e485a091350fa0c0b2fb8cec2905c58a3ae61d13794347fc82422466281b3b6a6e59304c64159ad376553f3a1a9f71b55322a4fb11651777a22801d9047c5c233a898866b4889a7619ba565aa731d989ca201035ee81f3c0342bf96cbbdd94ddde04ea6c44dc978a04aeb0d64d30414e308d6207d399776e80c820f50b3f74cadfc76c24166324e81b3c35aa976bacdf63585db6133de1728365367d038c2e6d934789871cf80aeae59875ad54a80f41c0117c512345d58cb521d200dbfd230568a9108700be2820315a271dc4a5524d7c63f08a7ed2172f8dc1e7087959cb88e599056389abfe9003d5678768f023fcf198fc2d59da004272fdb9c02f1ba1447c7e61956a9d88b64eb5037428df4aa6391344281c21b6fb84ec3f115cd856ee6cc00e4d95b7cc98d010b51db8b2bc3b43d8c981ff37259334b17b10986a39a4c988431b7e033473a63d672bb8ad3798364ae00923e9392094b93c877b1ce896b4af5934c6dd460c0bc729bab7f5b169a37180ad27404ea40280cd55f58a25a1e63c5cc566a6cb229a5c34ef654c6b71425bd57acafc940f5c3959286186f709057e110d48811a577820a88bd6dea298921b381ac77f13abc360cb59b33142064c3b9a56c748bbc7e7620ae3ab868b913f18764017987c068020a3a8c9e295114830f8f996284a37b73f476919a17d8fc3dd8c9b025b0a87264a5584009fbf45221840623e13430baa4c2d3bc7d478634dc9552b49b5497c400703bf75798dc73ce4d730ae9f358734532eae47f11f7cb44d415ba9c96a7335aa8b42ed1661b2b803613777b0828af4bb486be776ebf46ad493c8126493407098ca0e41e198409617aab404c9a5a83468f9a681eacbd96b671a0898496652c7b11be78208979b310ade80205035ce2bb33706426852097291510d0984d36b349a48c76b6e9489ae0c0fd419310486690a72680d16acb8921b40a0f82f5a95c457d8a16021c919d1a23b39f6ac470e1c8d547b02751b1c2040827733cf6e9018694bfd7eacd1e07b7a7c83e22076a318b895b06108b6499a719af9552495ff642de91698e3459e8a8b8d3711fdf9c8b7e56517f600c47e6b9aeb50c65c0943cc741c8f3b4b91b74708354b2d185c211663367483201717169a13f7ba20eb7601d716ee5637d3083605c027fdd08029f06063dd2b8b9f3ae0850a1b92299e30b718df44341923896ea808da925bd3bc337fbc018f2cfcdac1adee304ede55764e58165a237b8f9ae4144928c7597af9065a63b13e3d87dedd096e44701f01b50fe235834ac63ca0a584e060fbf717cc7d8c01dba13e6a7048fbb259d57cbfcca4bf4e5c077ca73f42c17f91773cabc6c0ad933e6c60d8d719a944705f4d816e66594a334c1ec4227eef444c48c7b726273ef134c5e1b2165e6532f832b41b0665e6c5cd996859800420de8546b0b96f4d3380049793fe30db3497de3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d94f62e0847061a998f7feb39bafa6d6e36bd2fc0d2c907d17ac58893c3b39d807b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d2", "fc6b55a3f161f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17460124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1eb9") == "" +check mlkem_decaps("4b3ba9a92a8f271a46a8e76f5b16b8d2ca8e68b829446c7beb1490283a82bb69a982568d0df51c8d61020b632c5c6727f5c70a7506afbc4b25bc0b7b3f9525c0aa8050e791e98c18d2886d82a3b0729085a701c0c4648dd3218d4c057562b59168d38714b69422a08b065cad1e485a091350fa0c0b2fb8cec2905c58a3ae61d13794347fc82422466281b3b6a6e59304c64159ad376553f3a1a9f71b55322a4fb11651777a22801d9047c5c233a898866b4889a7619ba565aa731d989ca201035ee81f3c0342bf96cbbdd94ddde04ea6c44dc978a04aeb0d64d30414e308d6207d399776e80c820f50b3f74cadfc76c24166324e81b3c35aa976bacdf63585db6133de1728365367d038c2e6d934789871cf80aeae59875ad54a80f41c0117c512345d58cb521d200dbfd230568a9108700be2820315a271dc4a5524d7c63f08a7ed2172f8dc1e7087959cb88e599056389abfe9003d5678768f023fcf198fc2d59da004272fdb9c02f1ba1447c7e61956a9d88b64eb5037428df4aa6391344281c21b6fb84ec3f115cd856ee6cc00e4d95b7cc98d010b51db8b2bc3b43d8c981ff37259334b17b10986a39a4c988431b7e033473a63d672bb8ad3798364ae00923e9392094b93c877b1ce896b4af5934c6dd460c0bc729bab7f5b169a37180ad27404ea40280cd55f58a25a1e63c5cc566a6cb229a5c34ef654c6b71425bd57acafc940f5c3959286186f709057e110d48811a577820a88bd6dea298921b381ac77f13abc360cb59b33142064c3b9a56c748bbc7e7620ae3ab868b913f18764017987c068020a3a8c9e295114830f8f996284a37b73f476919a17d8fc3dd8c9b025b0a87264a5584009fbf45221840623e13430baa4c2d3bc7d478634dc9552b49b5497c400703bf75798dc73ce4d730ae9f358734532eae47f11f7cb44d415ba9c96a7335aa8b42ed1661b2b803613777b0828af4bb486be776ebf46ad493c8126493407098ca0e41e198409617aab404c9a5a83468f9a681eacbd96b671a0898496652c7b11be78208979b310ade80205035ce2bb33706426852097291510d0984d36b349a48c76b6e9489ae0c0fd419310486690a72680d16acb8921b40a0f82f5a95c457d8a16021c919d1a23b39f6ac470e1c8d547b02751b1c2040827733cf6e9018694bfd7eacd1e07b7a7c83e22076a318b895b06108b6499a719af9552495ff642de91698e3459e8a8b8d3711fdf9c8b7e56517f600c47e6b9aeb50c65c0943cc741c8f3b4b91b74708354b2d185c211663367483201717169a13f7ba20eb7601d716ee5637d3083605c027fdd08029f06063dd2b8b9f3ae0850a1b92299e30b718df44341923896ea808da925bd3bc337fbc018f2cfcdac1adee304ede55764e58165a237b8f9ae4144928c7597af9065a63b13e3d87dedd096e44701f01b50fe235834ac63ca0a584e060fbf717cc7d8c01dba13e6a7048fbb259d57cbfcca4bf4e5c077ca73f42c17f91773cabc6c0ad933e6c60d8d719a944705f4d816e66594a334c1ec4227eef444c48c7b726273ef134c5e1b2165e6532f832b41b0665e6c5cd996859800420de8546b0b96f4d3380049793fe30db3497de3045339f1a2afb86da9661621006834dca9dd1954bbe67c375a2662c0413efbcbd0915085f4b50ed667cfaab06786c21665cf4de397a1ba87ca3006e07957d7923b17faae0135c993430b5dc0717ab4ba50dc0302d4a7333c3f8627c0a532aa4506a5686a73343c9d9d6896d53285d9d82d92613a9a453ec518a27dc75d23017e02d3a7ebf6a946180d55b0c27d773a43f67c7aba87d83b53069415fbc3bc7ad251963b75fef9724b7a77600b2b92471861379de38a476acc72765379bde22093611425e876fdc79c8749c3ab07258c590fbdea21a4db26f84a4611931e2bfc631156b3a876c4a4a84b7687ca906937cc0286b455c424754e035c8537509d4db81e84372bb37a4bf95288a7da9953571c9320a843b0125da75e850c1272323253c594534936c2f8b9dbb728e4faba58d7945f5ba45a7a888c1517e57c4672fcb214818397115836d30f579a75d8129fa1c47f0bc44a8e06a756f23422c6af37337b0791167a2899257b72d9e1a9f9551226f2b7baa8c3c705be6b80abadf8c60c897cd9041769f592ce667e57c99417e79f87426a253b8b5b28b0e1699a1596851ddc36532446a355c78396117380044f5b2c4a5cc3bd139f5688416d635d3824a83e2768637c5a22c1b4396a65cdd04f2a478fb4ab8754e19bc4c08781909febc6880f207eb3125776a0c4d6e6b68fe62124d512653c17364132bd1046118456a8725b55921ea9e59a921c8a36163ea765c7d5924fb11323cc0b576df7ceb72768f8894445fb98cb83c1db3c5d0c86c073e5697e90b3faaa9c3632c2bff2b39e263a3d0142fe1a12180bb2ff54016262352e731006f853ce915873013a202a60c17789055777f40373bf42a29dc134bb9c2362259aba18939c3921c0505dace8005c42abbb43553de05fd9da3d6b8834077caf9441af7181a4110886a1165ad3f19a9e7a98443b9e9309623ff3b209d98a3ce75ee8bb411731118056650c380ac5b3364c70b7d1794acd38cc97a900e830cf65a69de04c29103a2cce832a68028a87395029d44512a3a228a54172d7c0613371b196609ef4a7b499156c740d52d61e68412f6fc04be66173e702a10b4169eb52aef69078e38ba2d74bcd68d4719e937f884aadf367a725b02aa499359de1194e920829a72d67e059600497e2051f989b6e12bb42eca454e2bb5a8a13408ed8548b8b04d9f7ab3498994817489eacad16ec9f3d49b5fde4925cb86de1c3751bd9a8a73633768c2eb0d721f13a518a015351a122a3183c0eb1b8a6ccc13fb62b24ba1d615430de3a7d25d13c3bb3c5fb1522a593240e035a91537dd999641c37a0da3b2c83f8c0a8eb0b17e958f7cc15f9e64123d5194185405d6cc6193608d4121a28246c78cb14d0032fdf008048127cdd641f9a5194a5642479d8ade648aee8666cdb3830976b50b79a8be524c4014b8f4c9c20fc546647753fa8025f91871b54c110bfb0a177f04ba5a85a0d70395c490156531d6c681dcd3b8aaea08970f330e4b55dfdcb96cc0a5a70651d82cb63abb971a543a0ce2776eac49bc0964c9a90aee4e910fbdb470a4940c5a9b7e007156411346da8a9085587614697bc2949012a8a934a64c144a71c0a19d40966469ea3aca3806a2e7693be47e91e24da2194ae676e2828882d1daac6d94f62e0847061a998f6feb39bafa6d6e36bd2fc0d2c907d17ac58893c3b39d807b413f47d13ee2fe6c845b2ee141af81de858df4ec549a58b7970bb96645bc8d200", "fc6b55a3f161f4619abded241ae70c9c24832aa498ace8140997b3014b56abb7ed7ab0706b752c077cfaafb274ae162edea026793309c622226d3050bd6f5395ca83f6f39c526b04a4218eec51aa10c5848ee3e390037784a6f5d24f68f2010bacece1b5687c2bc63b771eac982e672319863bade560617ac52504c212dd674438ada6acbe9a2b075182be7798453ce3d52fa21b9b3be8b4a9d6c04b5e0dd84a614e0f0cdd2607f32fcd3a564286db5610306c922e72fb94bb29339190e6aef2b8010f4b89a6ede2d9bfd3ab179f8ba127e153e3cafe80c8219174a77d6c17a31b91ed83eef5244eda93eccaa879c2aa2c37ade51e4477d84ed94dd70983e9f21bdebba242d0bd999dd54b97e2897c02946b89c90e781ca81775bac6b46a5944b93fb8371d14095a4aebffd3d75baaf9ae7354bd74c192356be9103b11aeb9798e8775b85e415f06961365e771fd4eff36ef5b371810646ead29f95080ac7d8cb188645ef169def3de5033b7967fff07f66b81d17df9bd9a168c807840f9b27d2b894e3878534d23126313547fe3abfa1d5228f4c347aebcdee595ae3fd4b074c908d29cc069ac2f7bda11c791ec3eb11f42674f220961502489295d2d41792d794bffc3e5cf42e0620d503e5d9da003b5a5b2d192ec175acf9f1aee82128ce7a58923208295006561f51e725c8ef4fd454f17460124d22d04d3627702e06f1f39c3f13ed6c1772d59016a880f7e9083850736b719358a8ea27eacfd33d5e1e9416831d104d9c8f1d3cab5f4b9a3d7b7a0ddd68c7ef51741764e3fdb88a1b66ad972de9352f0e84d3e978315686854dfbef26186552539d12c5e0806689e41dd0562b70722be26b8e292f9ec1783a183a747409ad208fdd71d56a97c9a2f49505f3c72e830e8bd7ad57a619771c00a9f1607828bdeefdfe35beea99b3121950f6794acaa9adfae29a717ca28b6ed5ca38200fb9c614a37a1ee018bc2d81de977f1fba9394362bf792f6153fa86409e79e7a545eb9912293d7607d2776adfa90a2b761e1da69cbbbdc8f90ffe49c3c79b211fe6eb1611e586597894ac0dfa031b64e6d13ea7309f111c630190f06976d7e345899f3721323e09bccffb9618f891a28d139c03cd055095fb5d1026c1295769800d5e8a5b9890fc28fa02e6ed2310662600aa58f140b48524d8b0ecaa2f3ba84498ae4d4e26abf9fda339a73d9bc6c85f462a11e1e51d0b8b2028fc74d381d1ace50c9a44d8225133523d3814fb13cd0c43c76eead3b53fdf0988217f8dd9a1b208b198abdcbcb6408b6938869402e1e016c6b0a905946157038dc900e8ac0f2b7b76cd421803f806a7f726ae2a34e3afe9833b193c707ac41e984d01ee6538f5317e9d05ff043f32970b365fe96cff98d3425a5034ce72c2cc25031e1c8aebe514b44acc08939dafa84a87d119c042e186a699a2b21a99f1d51364fb7e3574b7dd9558066b10e936d92aada8aa335e360c92fc8411daa669f95b8a62a3523a6ff158caa4ad2702dc30a0ecbb1eb9") == "" diff --git a/tests/crypto/pqxdh_checks.rce b/tests/crypto/pqxdh_checks.rce new file mode 100644 index 00000000..d37fe2fe --- /dev/null +++ b/tests/crypto/pqxdh_checks.rce @@ -0,0 +1,5 @@ +# needs: crypto pq +# pqxdh_sk refuses an empty shared secret or DH (a refused ML-KEM decapsulation answers "") and still derives for real inputs. +check pqxdh_sk("00", "") == "" and pqxdh_sk("", "00") == "" +check pqxdh_sk("0011", "22").len() == 64 +check pqxdh_sk("0011", "22") != pqxdh_sk("0011", "23") diff --git a/tests/crypto/scalar_checks.rce b/tests/crypto/scalar_checks.rce new file mode 100644 index 00000000..f895dcac --- /dev/null +++ b/tests/crypto/scalar_checks.rce @@ -0,0 +1,13 @@ +# needs: crypto +# sc_reduce and sc_muladd against Python big integers mod L (L = 2^252 + 27742317777372353535851937790883648493), and bge/sub_borrow edge cases. +check tohex(sc_reduce(unhex("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"))) == "0000000000000000000000000000000000000000000000000000000000000000" +check tohex(sc_reduce(unhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))) == "000f9c44e31106a447938568a71b0ed065bef517d273ecce3d9a307c1b419903" +check tohex(sc_reduce(unhex("66fa58bffff9c74ca1d03cf9c40f1c50443f7a9bea221b21675e2de0d5f0c155c7fded92511dfe013cf2dbad381facd12c774a1130342d612ca65a89fb857993"))) == "b6d80d5d5cd05909041e4bad3623b5aca5c08161270d33e5bc7aade5bdf40506" +check tohex(sc_reduce(unhex("b88b91a4fc072714aeca32f288b68ae1615b88e6e38fd417d8016ab59297c6cea5031f572a288e47e5eda59db937a4fbaafbcd07093af49ae7288a6893dbb26e"))) == "fbb34f1dbba5dab2ec1a151e1b373dccb4cc1e493fd2fb460336a1d426241a09" +check tohex(sc_muladd(unhex("8795b3c8b3e3ad968a8ebc51a68b54da3d7ae4e5d980e309f8b55adff2e61c0e"), unhex("91117b973cc06ff5b24b4eb5b71b4134398b5229be6f3121a6f16e2d41a44903"), unhex("e310c971617b79c249b0ceaee41391ae8799647711b806bdd2cd82fa69713d03"))) == "796664bd8182f8ea9f87efa0bc8fb93f4d53e5761464af9a2b572a5cb3929403" +check tohex(sc_muladd(unhex("088cfb124c91210850ce9d3891950dedd66031054306ae4a4b380598f6cfd104"), unhex("2856cb327f087eccf1a3d08dc676c587fa6e756876d6ad9a9cac4aa4e72ec103"), unhex("685783e24ac2151b89e80e8710ade4f1cf379f1bee00e75a545147a27dadd902"))) == "6bda375025fe9f4c6ec82e06c9c5bd42ec116f43342939f01c7085f6dc64d705" +check tohex(sc_muladd(unhex("2c3a4249d77070058649dbd822dcaf7957586fce428cfb2ca88b94741eda8b07"), unhex("e0742a39c093f74e973aa693920fee62b9306a58f5888be0edcb2fcd0712020b"), unhex("e8bae6dd5c5a1cfd276b4f78d2673541931f058c0426c67c7285d8f5657ed60a"))) == "e146d59466dcc4c9199c687fd761ca4111f88def1f4ea920455777bbec1f4108" +check bge(unhex("ed"), unhex("ed")) and bge(unhex("ee"), unhex("ed")) and not bge(unhex("ec"), unhex("ed")) +check bge(unhex("0001"), unhex("ff00")) and not bge(unhex("ff00"), unhex("0001")) +check tohex(sc_reduce(ed_l())) == "0000000000000000000000000000000000000000000000000000000000000000" +check tohex(sc_reduce(unhex("ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"))) == "ecd3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010" diff --git a/tests/crypto/tag_checks.rce b/tests/crypto/tag_checks.rce new file mode 100644 index 00000000..e7dfe6e5 --- /dev/null +++ b/tests/crypto/tag_checks.rce @@ -0,0 +1,27 @@ +# needs: crypto pq hpke +# Tag and ciphertext comparisons (ct_eq, hp_ct_eq, kem_ct_eq) and the AEAD +# and GCM open paths that use them. +fn k0() -> List[i64] = unhex("0101") +fn n0() -> List[i64] = unhex("000000000000000000000001") +fn sealed0() -> text = seal(k0(), n0(), [], tobytes("hello")) +# flip one bit of the hex text at character position p +fn flip(s: text, i: usize) -> text + var b = unhex(s) + b[i] = b[i] ^ 1 + return tohex(b) +check ct_eq([], []) +check ct_eq([1, 2, 3], [1, 2, 3]) +check not ct_eq([1, 2, 3], [1, 2, 4]) +check not ct_eq([0, 2, 3], [1, 2, 3]) +check not ct_eq([1, 2], [1, 2, 3]) +check not ct_eq([1, 2, 3], [1, 2]) +check not ct_eq([255, 0], [0, 255]) +check hp_ct_eq([7, 8], [7, 8]) and not hp_ct_eq([7, 8], [7, 9]) and not hp_ct_eq([7], [7, 8]) +check kem_ct_eq([7, 8], [7, 8]) and not kem_ct_eq([7, 8], [7, 9]) and not kem_ct_eq([7], [7, 8]) +check open(k0(), n0(), [], sealed0()) == tobytes("hello") +# a flipped bit in the ciphertext (bytes 0, 4) or the tag (bytes 5, 12, 20) is refused +check open(k0(), n0(), [], flip(sealed0(), 0)) == [-1] +check open(k0(), n0(), [], flip(sealed0(), 4)) == [-1] +check open(k0(), n0(), [], flip(sealed0(), 5)) == [-1] +check open(k0(), n0(), [], flip(sealed0(), 12)) == [-1] +check open(k0(), n0(), [], flip(sealed0(), 20)) == [-1] diff --git a/tests/crypto/tag_fuel.rce b/tests/crypto/tag_fuel.rce new file mode 100644 index 00000000..6ff10650 --- /dev/null +++ b/tests/crypto/tag_fuel.rce @@ -0,0 +1,30 @@ +# needs: crypto pq hpke +# Constant fuel of the tag comparisons: the same fuel whether the first, +# the middle or the last byte differs, or none does. +fn k0() -> List[i64] = unhex("0101") +fn n0() -> List[i64] = unhex("000000000000000000000001") +# literal operands (unhex would add digit-dependent fuel of its own) +fn r16() -> List[i64] = [0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255] +fn same() -> List[i64] = [0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255] +fn d0() -> List[i64] = [1, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255] +fn d8() -> List[i64] = [0, 17, 34, 51, 68, 85, 102, 119, 137, 153, 170, 187, 204, 221, 238, 255] +fn d15() -> List[i64] = [0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 254] +fn probe_cteq_1() -> bool = ct_eq(same(), r16()) +fn probe_cteq_2() -> bool = ct_eq(d0(), r16()) +fn probe_cteq_3() -> bool = ct_eq(d8(), r16()) +fn probe_cteq_4() -> bool = ct_eq(d15(), r16()) +fn probe_hpcteq_1() -> bool = hp_ct_eq(same(), r16()) +fn probe_hpcteq_2() -> bool = hp_ct_eq(d0(), r16()) +fn probe_hpcteq_3() -> bool = hp_ct_eq(d15(), r16()) +fn probe_kemcteq_1() -> bool = kem_ct_eq(same(), r16()) +fn probe_kemcteq_2() -> bool = kem_ct_eq(d0(), r16()) +fn probe_kemcteq_3() -> bool = kem_ct_eq(d15(), r16()) +fn sealed0() -> text = seal(k0(), n0(), [], tobytes("hello")) +fn flip(s: text, i: usize) -> text + var b = unhex(s) + b[i] = b[i] ^ 1 + return tohex(b) +# open with a bad tag: same fuel whichever tag byte is wrong +fn probe_openbad_1() -> List[i64] = open(k0(), n0(), [], flip(sealed0(), 5)) +fn probe_openbad_2() -> List[i64] = open(k0(), n0(), [], flip(sealed0(), 12)) +fn probe_openbad_3() -> List[i64] = open(k0(), n0(), [], flip(sealed0(), 20)) diff --git a/tests/crypto/x25519_1_checks.rce b/tests/crypto/x25519_1_checks.rce new file mode 100644 index 00000000..312ce1c1 --- /dev/null +++ b/tests/crypto/x25519_1_checks.rce @@ -0,0 +1,5 @@ +# needs: crypto +# X25519 vectors (shard 1; one comptime fuel budget of 50M holds about three ladders). RFC 7748 5.2, iterated test round 1, 6.1; then differential vectors from the Python `cryptography` package (OpenSSL). +check x25519("a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4", "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c") == "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552" +check x25519("4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d", "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493") == "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957" +check x25519("0900000000000000000000000000000000000000000000000000000000000000", "0900000000000000000000000000000000000000000000000000000000000000") == "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079" diff --git a/tests/crypto/x25519_2_checks.rce b/tests/crypto/x25519_2_checks.rce new file mode 100644 index 00000000..896fa209 --- /dev/null +++ b/tests/crypto/x25519_2_checks.rce @@ -0,0 +1,5 @@ +# needs: crypto +# X25519 vectors (shard 2; one comptime fuel budget of 50M holds about three ladders). RFC 7748 5.2, iterated test round 1, 6.1; then differential vectors from the Python `cryptography` package (OpenSSL). +check pubkey("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a") == "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a" +check pubkey("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb") == "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f" +check x25519("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f") == "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" diff --git a/tests/crypto/x25519_3_checks.rce b/tests/crypto/x25519_3_checks.rce new file mode 100644 index 00000000..40598c37 --- /dev/null +++ b/tests/crypto/x25519_3_checks.rce @@ -0,0 +1,5 @@ +# needs: crypto +# X25519 vectors (shard 3; one comptime fuel budget of 50M holds about three ladders). RFC 7748 5.2, iterated test round 1, 6.1; then differential vectors from the Python `cryptography` package (OpenSSL). +check x25519("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb", "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a") == "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" +check x25519("d1a5ac9a015fac2ef7b341673635512a1511f41fe37d111b267f039eec5d4f58", "cc7135557388557c65a1f6d7017c06f3325bf9034f96cbc241ce45fa13772c2d") == "0eb85b16d4046cbaab755c5e5c9b6a58ac593b21fc787a2173ecd240178c0a35" +check x25519("6ab9f1eb8f7d3388f4f9d586f66e99fd54080df2c446f0e58668b09c08a16dd0", "01cf1f6dfdb22ca8f893a292c686edc249c00475e79d39bd2774d82e945c6f14") == "b9d8c35e2f06231195efc3740096f2f4f8f0615f708a23a36802f2cd1ac3f91a" diff --git a/tests/crypto/x25519_4_checks.rce b/tests/crypto/x25519_4_checks.rce new file mode 100644 index 00000000..11ee75ab --- /dev/null +++ b/tests/crypto/x25519_4_checks.rce @@ -0,0 +1,5 @@ +# needs: crypto +# X25519 vectors (shard 4; one comptime fuel budget of 50M holds about three ladders). RFC 7748 5.2, iterated test round 1, 6.1; then differential vectors from the Python `cryptography` package (OpenSSL). +check x25519("015f7e6bc5aeaf483724089e9252cc13b50951a6b69412522765cff4d780306e", "29b1dc5318eca1e5c9770be2df962dcf8229927aff94c68aea7289da677a8461") == "2758d8d7f4f777953db2c70b1d19b82354f10f09c4c3d0c918582933b0865639" +check x25519("2f5052c9fd15b19a18c584d01363568198613f0c34e84409ef7938709a159ec2", "ca0e6df80ed5ad8596f7b5712aadee8d0730452450022a200837de077ca14e7b") == "0803cd4ca190cf8dc37bcc92d270299f12e09fefc11c7fc4c4288b48cf38dd46" +check x25519("94091dd64a21ffe94214bc6d17deeb43873a5cf2f0a71b4b5caa9a5c81b6967d", "53e06f55337287e194798e2a38cb2ca41a0bfea4d24e4f144d533539532d1a30") == "d547e76fd710889ba8a35b4799b486fcfd9880531e583a3f1bfc33f329afb039" diff --git a/tests/crypto/x25519_5_checks.rce b/tests/crypto/x25519_5_checks.rce new file mode 100644 index 00000000..0cc4a18e --- /dev/null +++ b/tests/crypto/x25519_5_checks.rce @@ -0,0 +1,5 @@ +# needs: crypto +# X25519 vectors (shard 5; one comptime fuel budget of 50M holds about three ladders). RFC 7748 5.2, iterated test round 1, 6.1; then differential vectors from the Python `cryptography` package (OpenSSL). +check x25519("88dbf612972c594a2c2f6dde493ef1c4cd27adba8c36e6ebd00b89ff143aba61", "e67f93c7a3fe8466281cde4e2a86c6dc4075d3f7825b55ac73d8b8259ba6c21f") == "83df276fe2226eec725f6c1dd50bd2b610eac6b83926a10dd8763a4441b12a33" +check x25519("8704a01a73fa56816fb473d937190aa74b3e8ba54b92c30f8c80c1c50823a5af", "e9ce32cbc936a51dc3c9242425fc45865c24953ec85a8ebba06d69629e384a73") == "df1ff5a9d7b2908ff167e5ad0b55c3ec59e69710a230ce400a2b830bb7968b58" +check x25519("badb7283766a112aebdb2936077a25f5db85ea465cdbac330ba6641d38c4ac77", "316ca0efda6296d8f2c11d1e20890d220cec4266a0c16fbbef324c004688460a") == "ca169880d2f77963d768c71c19d2b3e3857349e53cb09a2ec21721778c2e9a5a" diff --git a/tests/crypto/x25519_6_checks.rce b/tests/crypto/x25519_6_checks.rce new file mode 100644 index 00000000..8071b129 --- /dev/null +++ b/tests/crypto/x25519_6_checks.rce @@ -0,0 +1,3 @@ +# needs: crypto +# X25519 vectors (shard 6; one comptime fuel budget of 50M holds about three ladders). RFC 7748 5.2, iterated test round 1, 6.1; then differential vectors from the Python `cryptography` package (OpenSSL). +check x25519("6897ab3e7bed435cf094a10477f16bf68af03a04d99b2833d43902ce2b40f0a9", "325a90f389d8331f6ccd8da8b14844423eeff4ba736c5c03d2d034e64ad63a3d") == "b0c04f936de7d6542c766304c7b8fbaaebb4eae8c1cd0232607a0c358d15fc4e" diff --git a/tests/crypto/x25519_fuel.rce b/tests/crypto/x25519_fuel.rce new file mode 100644 index 00000000..50aebe52 --- /dev/null +++ b/tests/crypto/x25519_fuel.rce @@ -0,0 +1,10 @@ +# needs: crypto +# Fuel of X25519 does not depend on the scalar: all-zero, all-one-bits, +# alternating and random scalars, same u. (Before the cswap fix the fuel +# differed with every set bit.) Source-level evidence only. +fn u0() -> text = "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c" +fn probe_x25519k_1() -> text = x25519("0000000000000000000000000000000000000000000000000000000000000000", u0()) +fn probe_x25519k_2() -> text = x25519("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", u0()) +fn probe_x25519k_3() -> text = x25519("5555555555555555555555555555555555555555555555555555555555555555", u0()) +fn probe_x25519k_4() -> text = x25519("a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4", u0()) +fn probe_x25519k_5() -> text = x25519("4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d", u0())