1use super::mlkem::{
2 ML_KEM_1024, MlKemError, SHARED_SECRET_SIZE, crypto_kem_dec, crypto_kem_enc_derand, crypto_kem_keypair_derand,
3 indcpa_secret_key_bytes,
4};
5
6pub const PUBLIC_KEY_SIZE_1024: usize = 1568;
7pub const SECRET_KEY_SIZE_1024: usize = 3168;
8pub const CIPHERTEXT_SIZE_1024: usize = 1568;
9
10#[derive(Clone, Debug, PartialEq, Eq)]
12#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
13pub struct SecretKey1024 {
14 bytes: [u8; SECRET_KEY_SIZE_1024],
15}
16
17#[derive(Clone, Debug, PartialEq, Eq)]
19pub struct PublicKey1024 {
20 bytes: [u8; PUBLIC_KEY_SIZE_1024],
21}
22
23#[inline]
24pub fn generate_keypair_1024() -> (SecretKey1024, PublicKey1024) {
25 SecretKey1024::generate()
26}
27
28impl SecretKey1024 {
29 pub fn from_bytes(bytes: &[u8; SECRET_KEY_SIZE_1024]) -> Self {
30 Self {
31 bytes: *bytes,
32 }
33 }
34
35 pub fn to_bytes(&self) -> [u8; SECRET_KEY_SIZE_1024] {
36 self.bytes
37 }
38
39 pub fn generate() -> (Self, PublicKey1024) {
40 let coins: [u8; 64] = rand::random();
41 Self::generate_derand(&coins)
42 }
43
44 fn generate_derand(coins: &[u8; 64]) -> (Self, PublicKey1024) {
45 let (sk_bytes, pk_bytes) =
46 crypto_kem_keypair_derand::<4, SECRET_KEY_SIZE_1024, PUBLIC_KEY_SIZE_1024>(&ML_KEM_1024, coins);
47 (
48 Self {
49 bytes: sk_bytes,
50 },
51 PublicKey1024 {
52 bytes: pk_bytes,
53 },
54 )
55 }
56
57 pub fn decapsulate(&self, ciphertext: &[u8; CIPHERTEXT_SIZE_1024]) -> Result<[u8; SHARED_SECRET_SIZE], MlKemError> {
58 crypto_kem_dec::<4, SECRET_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &self.bytes, ciphertext)
59 }
60
61 pub fn public_key(&self) -> PublicKey1024 {
62 let offset = indcpa_secret_key_bytes::<4>();
63 let mut pk_bytes = [0u8; PUBLIC_KEY_SIZE_1024];
64 pk_bytes.copy_from_slice(&self.bytes[offset..offset + PUBLIC_KEY_SIZE_1024]);
65 PublicKey1024 {
66 bytes: pk_bytes,
67 }
68 }
69}
70
71impl From<&[u8; SECRET_KEY_SIZE_1024]> for SecretKey1024 {
72 fn from(bytes: &[u8; SECRET_KEY_SIZE_1024]) -> Self {
73 Self::from_bytes(bytes)
74 }
75}
76
77impl TryFrom<&[u8]> for SecretKey1024 {
78 type Error = MlKemError;
79
80 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
81 Ok(Self::from_bytes(bytes.try_into().map_err(|_| MlKemError::InvalidKey)?))
82 }
83}
84
85impl PublicKey1024 {
86 pub fn from_bytes(bytes: &[u8; PUBLIC_KEY_SIZE_1024]) -> Self {
87 Self {
88 bytes: *bytes,
89 }
90 }
91
92 pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_SIZE_1024] {
93 self.bytes
94 }
95
96 pub fn encapsulate(&self) -> ([u8; CIPHERTEXT_SIZE_1024], [u8; SHARED_SECRET_SIZE]) {
97 let coins: [u8; 32] = rand::random();
98 self.encapsulate_derand(&coins)
99 }
100
101 fn encapsulate_derand(&self, coins: &[u8; 32]) -> ([u8; CIPHERTEXT_SIZE_1024], [u8; SHARED_SECRET_SIZE]) {
102 crypto_kem_enc_derand::<4, PUBLIC_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &self.bytes, coins)
103 }
104}
105
106impl From<&[u8; PUBLIC_KEY_SIZE_1024]> for PublicKey1024 {
107 fn from(bytes: &[u8; PUBLIC_KEY_SIZE_1024]) -> Self {
108 Self::from_bytes(bytes)
109 }
110}
111
112impl TryFrom<&[u8]> for PublicKey1024 {
113 type Error = MlKemError;
114
115 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
116 Ok(Self::from_bytes(bytes.try_into().map_err(|_| MlKemError::InvalidKey)?))
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::{
123 super::mlkem::{
124 ML_KEM_1024, crypto_kem_dec, crypto_kem_enc_derand, crypto_kem_keypair_derand, decode_hex_array,
125 sha3_256_hex,
126 },
127 *,
128 };
129
130 #[test]
131 fn ml_kem_1024_round_trip() {
132 let (private_key, public_key) = generate_keypair_1024();
133 let (ciphertext, encapsulated_secret) = public_key.encapsulate();
134 let decapsulated_secret = private_key.decapsulate(&ciphertext).unwrap();
135
136 assert_eq!(encapsulated_secret, decapsulated_secret);
137 }
138
139 #[test]
140 fn ml_kem_1024_deterministic_derand_vectors_are_stable() {
141 let key_coins = [3u8; 64];
142 let enc_coins = [5u8; 32];
143 let (secret_key, public_key) =
144 crypto_kem_keypair_derand::<4, SECRET_KEY_SIZE_1024, PUBLIC_KEY_SIZE_1024>(&ML_KEM_1024, &key_coins);
145 let (ciphertext, shared_secret) = crypto_kem_enc_derand::<4, PUBLIC_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(
146 &ML_KEM_1024,
147 &public_key,
148 &enc_coins,
149 );
150 let decapsulated =
151 crypto_kem_dec::<4, SECRET_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &secret_key, &ciphertext)
152 .unwrap();
153
154 assert_eq!(shared_secret, decapsulated);
155 assert_eq!(
156 hex::encode(&public_key[..32]),
157 "2dd29da8b193397a4336c02382aab3bcfbac25f0cd71c888af379e1e75149a79"
158 );
159 assert_eq!(
160 hex::encode(&ciphertext[..32]),
161 "5f12f173ef59a45f910d3a225913f3297b2277636a72401a273648015cccf079"
162 );
163 assert_eq!(
164 hex::encode(shared_secret),
165 "8bf157178aa556b55f95686ba9b5afe13a6b75c848f1ddd9a334d50287bec24e"
166 );
167 }
168
169 #[test]
170 fn ml_kem_1024_cctv_accumulated_10k() {
171 use crate::{Xof, sha3::Shake128};
172
173 let mut rng = Shake128::new();
174 rng.absorb(&[]);
175
176 let mut acc = Shake128::new();
177
178 for _ in 0..10_000u32 {
179 let mut d = [0u8; 32];
180 let mut z = [0u8; 32];
181 let mut m = [0u8; 32];
182 let mut ct_random = [0u8; CIPHERTEXT_SIZE_1024];
183
184 rng.squeeze(&mut d);
185 rng.squeeze(&mut z);
186 rng.squeeze(&mut m);
187 rng.squeeze(&mut ct_random);
188
189 let mut coins = [0u8; 64];
190 coins[..32].copy_from_slice(&d);
191 coins[32..].copy_from_slice(&z);
192
193 let (dk, ek) =
194 crypto_kem_keypair_derand::<4, SECRET_KEY_SIZE_1024, PUBLIC_KEY_SIZE_1024>(&ML_KEM_1024, &coins);
195 let (ct, k_encaps) =
196 crypto_kem_enc_derand::<4, PUBLIC_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &ek, &m);
197
198 let k_decaps =
199 crypto_kem_dec::<4, SECRET_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &dk, &ct).unwrap();
200 assert_eq!(k_encaps, k_decaps);
201
202 let k_decaps_random =
203 crypto_kem_dec::<4, SECRET_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &dk, &ct_random).unwrap();
204
205 acc.absorb(&ek);
206 acc.absorb(&dk);
207 acc.absorb(&ct);
208 acc.absorb(&k_encaps);
209 acc.absorb(&k_decaps_random);
210 }
211
212 let mut hash = [0u8; 32];
213 acc.squeeze(&mut hash);
214 assert_eq!(
215 hex::encode(hash),
216 "e3bf82b013307b2e9d47dde791ff6dfc82e694e6382404abdb948b908b75bad5",
217 "ML-KEM-1024 CCTV accumulated hash mismatch"
218 );
219 }
220
221 #[test]
222 fn ml_kem_1024_cctv_intermediate_vector() {
223 let d: [u8; 32] = decode_hex_array("2a62c39ef4fc499f2d132716f480bb7521a49558ae84ee80d9352e66daf1e3a8");
224 let z: [u8; 32] = decode_hex_array("5f574ef7f013d4336801fed022178c3ed91d0b6d51325315fc1dcabf4770a2ea");
225 let m: [u8; 32] = decode_hex_array("e07d685ed308e609c9c7842026e35732f6ffc6e2fee10f0afd348f2b42a8acb4");
226
227 let mut coins = [0u8; 64];
228 coins[..32].copy_from_slice(&d);
229 coins[32..].copy_from_slice(&z);
230
231 let (dk, ek) = crypto_kem_keypair_derand::<4, SECRET_KEY_SIZE_1024, PUBLIC_KEY_SIZE_1024>(&ML_KEM_1024, &coins);
232 let (ct, k) = crypto_kem_enc_derand::<4, PUBLIC_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &ek, &m);
233
234 assert_eq!(
235 sha3_256_hex(&ek),
236 "3b308d1344ed70366b84d790acb705b86cd3dfd471fff171969aaa338f26dca5"
237 );
238 assert_eq!(
239 sha3_256_hex(&dk),
240 "aa63a9e0c035ada6635e7938b71856b24917ff9b3ebca1a4d205a83b502a415a"
241 );
242 assert_eq!(
243 sha3_256_hex(&ct),
244 "8caba02733421f12a7ba9a2bcbe4de7c9853156a0637df5a7a0f9127c81da943"
245 );
246 assert_eq!(
247 hex::encode(k),
248 "d53825c3ff666bb2881215dbec04a8bdce9099b2a3680938c2f199b54d505953"
249 );
250 }
251
252 #[test]
253 fn ml_kem_1024_decapsulation_rejects_tampered_ciphertext() {
254 let (private_key, public_key) = generate_keypair_1024();
255 let (mut ciphertext, encapsulated_secret) = public_key.encapsulate();
256
257 ciphertext[0] ^= 0x80;
258
259 let decapsulated_secret = private_key.decapsulate(&ciphertext).unwrap();
260
261 assert_ne!(encapsulated_secret, decapsulated_secret);
262 }
263
264 #[test]
265 fn ml_kem_1024_decapsulation_with_wrong_key_rejects() {
266 let (_, alice_pk) = generate_keypair_1024();
267 let (bob_sk, _bob_pk) = generate_keypair_1024();
268 let (ct, _alice_ss) = alice_pk.encapsulate();
269
270 let wrong_ss = bob_sk.decapsulate(&ct).unwrap();
271 assert_ne!(_alice_ss, wrong_ss);
272 }
273
274 #[test]
275 fn ml_kem_1024_round_trip_many() {
276 for _ in 0..100 {
277 let (sk, pk) = generate_keypair_1024();
278 let (ct, ss_enc) = pk.encapsulate();
279 let ss_dec = sk.decapsulate(&ct).unwrap();
280 assert_eq!(ss_enc, ss_dec);
281 }
282 }
283
284 #[test]
285 fn ml_kem_1024_all_zero_ciphertext_does_not_panic() {
286 let (sk, _pk) = generate_keypair_1024();
287 let ct = [0u8; CIPHERTEXT_SIZE_1024];
288 let _result = sk.decapsulate(&ct);
289 }
290
291 #[test]
292 fn ml_kem_1024_all_ones_ciphertext_does_not_panic() {
293 let (sk, _pk) = generate_keypair_1024();
294 let ct = [0xffu8; CIPHERTEXT_SIZE_1024];
295 let _result = sk.decapsulate(&ct);
296 }
297
298 #[test]
299 fn ml_kem_1024_derand_keygen_is_deterministic() {
300 let coins = [3u8; 64];
301 let (sk1, pk1) =
302 crypto_kem_keypair_derand::<4, SECRET_KEY_SIZE_1024, PUBLIC_KEY_SIZE_1024>(&ML_KEM_1024, &coins);
303 let (sk2, pk2) =
304 crypto_kem_keypair_derand::<4, SECRET_KEY_SIZE_1024, PUBLIC_KEY_SIZE_1024>(&ML_KEM_1024, &coins);
305 assert_eq!(sk1, sk2);
306 assert_eq!(pk1, pk2);
307 }
308
309 #[test]
310 fn ml_kem_1024_key_sizes_are_correct() {
311 let (sk, pk) = generate_keypair_1024();
312 let sk_bytes = sk.to_bytes();
313 let pk_bytes = pk.to_bytes();
314 assert_eq!(sk_bytes.len(), SECRET_KEY_SIZE_1024);
315 assert_eq!(pk_bytes.len(), PUBLIC_KEY_SIZE_1024);
316 let (ct, _) = pk.encapsulate();
317 assert_eq!(ct.len(), CIPHERTEXT_SIZE_1024);
318 }
319
320 #[test]
321 fn ml_kem_1024_encaps_is_deterministic_with_same_coins() {
322 let enc_coins = [5u8; 32];
323 let key_coins = [3u8; 64];
324 let (_sk, pk) =
325 crypto_kem_keypair_derand::<4, SECRET_KEY_SIZE_1024, PUBLIC_KEY_SIZE_1024>(&ML_KEM_1024, &key_coins);
326 let (ct1, ss1) =
327 crypto_kem_enc_derand::<4, PUBLIC_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &pk, &enc_coins);
328 let (ct2, ss2) =
329 crypto_kem_enc_derand::<4, PUBLIC_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &pk, &enc_coins);
330 assert_eq!(ct1, ct2);
331 assert_eq!(ss1, ss2);
332 }
333
334 #[test]
335 fn ml_kem_1024_decapsulation_with_wrong_key_is_deterministic() {
336 let (_, pk_a) = generate_keypair_1024();
337 let (sk_b, _pk_b) = generate_keypair_1024();
338 let (ct, _) = pk_a.encapsulate();
339
340 let ss1 = sk_b.decapsulate(&ct).unwrap();
341 let ss2 = sk_b.decapsulate(&ct).unwrap();
342 assert_eq!(ss1, ss2, "implicit rejection must be deterministic");
343 }
344
345 #[test]
346 fn ml_kem_1024_wycheproof_keygen() {
347 let data: serde_json::Value = serde_json::from_str(include_str!(
348 "../../testdata/wycheproof/testvectors_v1/mlkem_1024_keygen_seed_test.json"
349 ))
350 .unwrap();
351 let mut tested = 0u64;
352 for group in data["testGroups"].as_array().unwrap() {
353 if group["parameterSet"].as_str() != Some("ML-KEM-1024") {
354 continue;
355 }
356 for test in group["tests"].as_array().unwrap() {
357 let seed_hex = test["seed"].as_str().unwrap();
358 let expected_ek_hex = test["ek"].as_str().unwrap();
359 let expected_dk_hex = test["dk"].as_str().unwrap();
360 let result = test["result"].as_str().unwrap();
361
362 let seed = hex::decode_array::<64>(seed_hex.as_bytes()).unwrap();
363
364 let (dk, ek) =
365 crypto_kem_keypair_derand::<4, SECRET_KEY_SIZE_1024, PUBLIC_KEY_SIZE_1024>(&ML_KEM_1024, &seed);
366
367 let ek_hex = hex::encode(ek);
368 let dk_hex = hex::encode(dk);
369
370 if result == "valid" {
371 assert_eq!(
372 ek_hex, expected_ek_hex,
373 "wycheproof keygen KAT tcId={} ek mismatch",
374 test["tcId"]
375 );
376 assert_eq!(
377 dk_hex, expected_dk_hex,
378 "wycheproof keygen KAT tcId={} dk mismatch",
379 test["tcId"]
380 );
381 }
382 tested += 1;
383 }
384 }
385 assert!(tested > 0, "no ML-KEM-1024 keygen tests were run");
386 }
387
388 fn wycheproof_kem_skip_invalid_lengths(seed_hex: &str, c_hex: &str, ct_size: usize) -> bool {
389 seed_hex.len() != 128 || c_hex.len() != ct_size * 2
390 }
391
392 #[test]
393 fn ml_kem_1024_wycheproof_kem() {
394 let data: serde_json::Value =
395 serde_json::from_str(include_str!("../../testdata/wycheproof/testvectors_v1/mlkem_1024_test.json"))
396 .unwrap();
397 let mut tested = 0u64;
398 for group in data["testGroups"].as_array().unwrap() {
399 if group["parameterSet"].as_str() != Some("ML-KEM-1024") {
400 continue;
401 }
402 for test in group["tests"].as_array().unwrap() {
403 let seed_hex = test["seed"].as_str().unwrap();
404 let c_hex = test["c"].as_str().unwrap();
405 let expected_k_hex = test["K"].as_str().unwrap();
406 let result = test["result"].as_str().unwrap();
407
408 if wycheproof_kem_skip_invalid_lengths(seed_hex, c_hex, CIPHERTEXT_SIZE_1024) {
409 tested += 1;
410 continue;
411 }
412
413 let seed = hex::decode_array::<64>(seed_hex.as_bytes()).unwrap();
414
415 let (dk, ek) =
416 crypto_kem_keypair_derand::<4, SECRET_KEY_SIZE_1024, PUBLIC_KEY_SIZE_1024>(&ML_KEM_1024, &seed);
417
418 if let Some(expected_ek_hex) = test.get("ek").and_then(|v| v.as_str()) {
419 let ek_hex = hex::encode(ek);
420 assert_eq!(ek_hex, expected_ek_hex, "wycheproof KEM KAT tcId={} ek mismatch", test["tcId"]);
421 }
422
423 let c = decode_hex_array::<CIPHERTEXT_SIZE_1024>(c_hex);
424 let shared_secret =
425 crypto_kem_dec::<4, SECRET_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &dk, &c);
426
427 if result == "valid" {
428 let k = shared_secret.unwrap();
429 let k_hex = hex::encode(k);
430 assert_eq!(k_hex, expected_k_hex, "wycheproof KEM KAT tcId={} K mismatch", test["tcId"]);
431 } else {
432 assert!(
433 shared_secret.is_ok(),
434 "wycheproof KEM KAT tcId={} unexpected error",
435 test["tcId"]
436 );
437 }
438 tested += 1;
439 }
440 }
441 assert!(tested > 0, "no ML-KEM-1024 KEM tests were run");
442 }
443
444 #[test]
445 fn ml_kem_1024_wycheproof_encaps() {
446 let data: serde_json::Value = serde_json::from_str(include_str!(
447 "../../testdata/wycheproof/testvectors_v1/mlkem_1024_encaps_test.json"
448 ))
449 .unwrap();
450 let mut tested = 0u64;
451 for group in data["testGroups"].as_array().unwrap() {
452 if group["parameterSet"].as_str() != Some("ML-KEM-1024") {
453 continue;
454 }
455 for test in group["tests"].as_array().unwrap() {
456 let ek_hex = test["ek"].as_str().unwrap();
457 let m_hex = test["m"].as_str().unwrap();
458 let expected_c_hex = test["c"].as_str().unwrap();
459 let expected_k_hex = test["K"].as_str().unwrap();
460 let result = test["result"].as_str().unwrap();
461
462 if ek_hex.len() != PUBLIC_KEY_SIZE_1024 * 2 {
463 tested += 1;
464 continue;
465 }
466
467 let ek = decode_hex_array::<PUBLIC_KEY_SIZE_1024>(ek_hex);
468
469 if result == "valid" {
470 let m = decode_hex_array::<32>(m_hex);
471 let (c, k) =
472 crypto_kem_enc_derand::<4, PUBLIC_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &ek, &m);
473 let c_hex_out = hex::encode(c);
474 let k_hex_out = hex::encode(k);
475 assert_eq!(
476 c_hex_out, expected_c_hex,
477 "wycheproof encaps KAT tcId={} c mismatch",
478 test["tcId"]
479 );
480 assert_eq!(
481 k_hex_out, expected_k_hex,
482 "wycheproof encaps KAT tcId={} K mismatch",
483 test["tcId"]
484 );
485 }
486 tested += 1;
487 }
488 }
489 assert!(tested > 0, "no ML-KEM-1024 encaps tests were run");
490 }
491
492 #[test]
493 fn ml_kem_1024_wycheproof_decaps_validation() {
494 let data: serde_json::Value = serde_json::from_str(include_str!(
495 "../../testdata/wycheproof/testvectors_v1/mlkem_1024_semi_expanded_decaps_test.json"
496 ))
497 .unwrap();
498 let mut tested = 0u64;
499 for group in data["testGroups"].as_array().unwrap() {
500 if group["parameterSet"].as_str() != Some("ML-KEM-1024") {
501 continue;
502 }
503 for test in group["tests"].as_array().unwrap() {
504 let flags: Vec<&str> = test["flags"]
505 .as_array()
506 .map(|a| a.iter().filter_map(|v| v.as_str()).collect())
507 .unwrap_or_default();
508 let dk_hex = test["dk"].as_str().unwrap();
509 let c_hex = test["c"].as_str().unwrap();
510
511 if flags.contains(&"IncorrectDecapsulationKeyLength") || flags.contains(&"IncorrectCiphertextLength") {
512 tested += 1;
513 continue;
514 }
515
516 let dk = decode_hex_array::<SECRET_KEY_SIZE_1024>(dk_hex);
517 let c = decode_hex_array::<CIPHERTEXT_SIZE_1024>(c_hex);
518
519 let result = crypto_kem_dec::<4, SECRET_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &dk, &c);
520
521 assert!(result.is_ok(), "wycheproof decaps tcId={} panicked", test["tcId"]);
522 tested += 1;
523 }
524 }
525 assert!(tested > 0, "no ML-KEM-1024 decaps validation tests were run");
526 }
527
528 #[test]
529 fn ml_kem_1024_cross_implementation_pqcrypto() {
530 let data: serde_json::Value =
533 serde_json::from_str(include_str!("../../testdata/mlkem/pqcrypto_1024_vectors.json")).unwrap();
534 let vectors = data.as_array().unwrap();
535 assert!(vectors.len() >= 5, "not enough cross-impl vectors");
536
537 for (i, vector) in vectors.iter().enumerate() {
538 let sk_hex = vector["sk"].as_str().unwrap();
539 let ct_hex = vector["ct"].as_str().unwrap();
540 let expected_ss_hex = vector["ss"].as_str().unwrap();
541
542 let sk = decode_hex_array::<SECRET_KEY_SIZE_1024>(sk_hex);
543 let ct = decode_hex_array::<CIPHERTEXT_SIZE_1024>(ct_hex);
544
545 let ss = crypto_kem_dec::<4, SECRET_KEY_SIZE_1024, CIPHERTEXT_SIZE_1024>(&ML_KEM_1024, &sk, &ct).unwrap();
546 assert_eq!(
547 hex::encode(ss),
548 expected_ss_hex,
549 "cross-impl pqcrypto vector {i} decapsulation mismatch"
550 );
551 }
552 }
553}