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