Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_crypto/src/pqc/saber.rs

82.1 KiB, 65 runs

created by r1870400018:244, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1/*!
2This module provides an implementation of the [SABER][eprint] key encapsulation and exchange mechanism.
3
4[SABER][saber_web] has been devised by:
5- Jan-Pieter D'Anvers, KU Leuven, imec-COSIC
6- Angshuman Karmakar, KU Leuven, imec-COSIC
7- Sujoy Sinha Roy, KU Leuven, imec-COSIC
8- Frederik Vercauteren, KU Leuven, imec-COSIC
9
10[Daan Sprenkels][saber_rust] has made a Rust implementation available, with generics via macros. This implementation uses const generics and aims to be a little easier to read, test and verify in conjunction with the [C reference implementation][saber_c].
11
12C integer operations were directly translated using the Rust modular arithmetic functions `wrapping_add` and `wrapping_mul`. However the SABER C reference implementation makes use of unsigned subtraction with implicit coercion. Subtraction of two unsigned integers automatically triggers C compilers to perform a type coercion (or conversion) to two signed integers that can accomodate any possible result.
13
14```c
15#include <stdio.h>
16#include <stdint.h>
17
18int main() {
19 uint8_t a = 0;
20 uint8_t b = 255;
21 uint8_t c = a - b;
22 printf("%d\n", c); // prints 1
23 return 0;
24}
25```
26
27The equivalent Rust subtraction process must be explicit about these conversions in order to produce the same modular result,
28
29```
30let a: u8 = 0;
31let b: u8 = 255;
32let d: i16 = a as i16 - b as i16;
33let c: u8 = d as u8;
34println!("The decimal difference {}-{} is {}", a, b, d);
35println!("The modular result in decimal difference is -255");
36```
37
38[eprint]: https://eprint.iacr.org/2018/230.pdf
39[saber_web]: https://www.esat.kuleuven.be/cosic/pqcrypto/saber/
40[saber_rust]: https://github.com/dsprenkels/saber-rust
41[saber_c]: https://github.com/KULeuven-COSIC/SABER
42*/
43
44use crate::generic_saber_api;
45
46use oxedyne_fe2o3_core::prelude::*;
47
48use std::{
49 convert::TryInto,
50 fmt,
51 iter::Chain,
52 slice::Iter,
53};
54
55use rand_core::{
56 OsRng,
57 RngCore,
58};
59use tiny_keccak::{
60 Hasher,
61 Sha3,
62 Shake,
63};
64use wasm_bindgen::prelude::*;
65use zeroize::DefaultIsZeroes;
66
67pub const LIGHTSABER_ID: u8 = 1;
68pub const SABER_ID: u8 = 2;
69pub const FIRESABER_ID: u8 = 3;
70
71pub const SABER_N: usize = 256;
72pub const SEED_BYTES: usize = 32;
73pub const NOISE_SEED_BYTES: usize = 32;
74pub const KEY_BYTES: usize = 32;
75pub const HASH_BYTES: usize = 32;
76pub const EQ: usize = 13;
77pub const EP: usize = 10;
78
79pub const POLY_BYTES: usize = EQ * SABER_N / 8;
80pub const POLY_COMPRESSED_BYTES: usize = EP * SABER_N / 8;
81
82// Polynomial multiplication
83const MULT_KN: usize = 64;
84const MULT_N_SB: usize = SABER_N >> 2; // i.e. SABER_N / 4 = 64
85const MULT_N_SB_RES: usize = 2 * MULT_N_SB - 1; // i.e. 127
86
87// Note: we cannot branch on unit structs, nor use them as arguments in functions, so we can't
88// switch between them. You choose one and stick with it, a little like a form of conditional
89// compilation.
90
91#[wasm_bindgen]
92#[derive(Default)]
93pub struct LightSaber;
94
95#[wasm_bindgen]
96#[derive(Default)]
97pub struct Saber;
98
99#[wasm_bindgen]
100#[derive(Default)]
101pub struct FireSaber;
102
103impl LightSaber { generic_saber_api!(); }
104impl Saber { generic_saber_api!(); }
105impl FireSaber { generic_saber_api!(); }
106
107impl fmt::Display for LightSaber {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 write!(f, "LightSaber")
110 }
111}
112
113impl fmt::Display for Saber {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 write!(f, "Saber")
116 }
117}
118
119impl fmt::Display for FireSaber {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 write!(f, "FireSaber")
122 }
123}
124
125/// Each of the three schemes has important associated constants (i.e. `L`, `ET` and `MU`), a few
126/// specific serialisation/deserialisation differences (i.e. `polt2bs` and `bs2polt`) and
127/// different algorithms for sampling from a centered binomial distribution (`cbd`).
128impl SaberAlgorithm for LightSaber {
129
130 const L: usize = 2;
131 const ET: usize = 3;
132 const MU: usize = 10;
133
134 fn polt2bs<
135 const N: usize,
136 const SBK: usize,
137 >(
138 data: &[u16; N],
139 start: usize,
140 ) -> [u8; SBK]
141 {
142 let mut bytes = [0u8; SBK];
143 for j in 0..N/8 {
144 let offset_byte = start + 3 * j;
145 let offset_data = 8 * j;
146 bytes[offset_byte + 0] = (
147 (data[offset_data + 0] & 0x7) |
148 ((data[offset_data + 1] & 0x7) << 3) | // reminder: "<<" increases the value
149 ((data[offset_data + 2] & 0x3) << 6)
150 ) as u8;
151 bytes[offset_byte + 1] = (
152 ((data[offset_data + 2] >> 2) & 0x01) |
153 ((data[offset_data + 3] & 0x7) << 1) |
154 ((data[offset_data + 4] & 0x7) << 4) |
155 (((data[offset_data + 5]) & 0x01) << 7)
156 ) as u8;
157 bytes[offset_byte + 2] = (
158 ((data[offset_data + 5] >> 1) & 0x03) |
159 ((data[offset_data + 6] & 0x7) << 2) |
160 ((data[offset_data + 7] & 0x7) << 5)
161 ) as u8;
162 }
163 bytes
164 }
165
166 fn bs2polt<
167 const N: usize,
168 const SBK: usize,
169 >(
170 bytes: &[u8; SBK],
171 start: usize,
172 ) -> [u16; N]
173 {
174 let mut data = [0u16; N];
175
176 for j in 0..N/8 {
177 let offset_byte = start + 3 * j;
178 let offset_data = 8 * j;
179 data[offset_data + 0] = (bytes[offset_byte + 0] & 0x07) as u16;
180 data[offset_data + 1] = ((bytes[offset_byte + 0] >> 3) & 0x07) as u16;
181 data[offset_data + 2] = (
182 ((bytes[offset_byte + 0] >> 6) & 0x03) |
183 ((bytes[offset_byte + 1] & 0x01) << 2)
184 ) as u16;
185 data[offset_data + 3] = ((bytes[offset_byte + 1] >> 1) & 0x07) as u16;
186 data[offset_data + 4] = ((bytes[offset_byte + 1] >> 4) & 0x07) as u16;
187 data[offset_data + 5] = (
188 ((bytes[offset_byte + 1] >> 7) & 0x01) |
189 ((bytes[offset_byte + 2] & 0x03) << 1)
190 ) as u16;
191 data[offset_data + 6] = ((bytes[offset_byte + 2] >> 2) & 0x07) as u16;
192 data[offset_data + 7] = ((bytes[offset_byte + 2] >> 5) & 0x07) as u16;
193 }
194 data
195 }
196
197 fn cbd(&self, buf: &[u8]) -> [u16; SABER_N] {
198 //msg!("buf len = {} ", buf.len());
199 let mut a = [0_u64; 4];
200 let mut b = [0_u64; 4];
201 let mut secret = [0_16; SABER_N];
202
203 for i in 0..SABER_N/4 {
204 let k1 = 5 * i;
205 let k2 = k1 + 5;
206 let t = <Self as SaberAlgorithm>::load_little_endian(&buf[k1..k2]);
207 let mut d = 0_u64;
208 for j in 0..5 {
209 d += (t >> j) & 0x0842108421;
210 }
211
212 a[0] = d & 0x1f;
213 b[0] = (d >> 5) & 0x1f;
214 a[1] = (d >> 10) & 0x1f;
215 b[1] = (d >> 15) & 0x1f;
216 a[2] = (d >> 20) & 0x1f;
217 b[2] = (d >> 25) & 0x1f;
218 a[3] = (d >> 30) & 0x1f;
219 b[3] = d >> 35;
220
221 secret[4 * i + 0] = (a[0] as i64 - b[0] as i64) as u16;
222 secret[4 * i + 1] = (a[1] as i64 - b[1] as i64) as u16;
223 secret[4 * i + 2] = (a[2] as i64 - b[2] as i64) as u16;
224 secret[4 * i + 3] = (a[3] as i64 - b[3] as i64) as u16;
225
226 }
227 secret
228 }
229
230}
231
232impl SaberAlgorithm for Saber {
233
234 const L: usize = 3;
235 const ET: usize = 4;
236 const MU: usize = 8;
237
238 fn polt2bs<
239 const N: usize,
240 const SBK: usize,
241 >(
242 data: &[u16; N],
243 start: usize,
244 ) -> [u8; SBK]
245 {
246 let mut bytes = [0u8; SBK];
247 for j in 0..N/2 {
248 let offset_byte = start + j;
249 let offset_data = 2 * j;
250 bytes[offset_byte] = (
251 (data[offset_data] & 0x0f) |
252 ((data[offset_data + 1] & 0x0f) << 4)
253 ) as u8;
254 }
255 bytes
256 }
257
258 fn bs2polt<
259 const N: usize,
260 const SBK: usize,
261 >(
262 bytes: &[u8; SBK],
263 start: usize,
264 ) -> [u16; N]
265 {
266 let mut data = [0u16; N];
267 for j in 0..N/2 {
268 let offset_byte = start + j;
269 let offset_data = 2 * j;
270 data[offset_data] = (bytes[offset_byte] & 0x0f) as u16;
271 data[offset_data + 1] = ((bytes[offset_byte] >> 4) & 0x0f) as u16;
272 }
273 data
274 }
275
276 fn cbd(&self, buf: &[u8]) -> [u16; SABER_N] {
277 let mut a = [0_u32; 4];
278 let mut b = [0_u32; 4];
279 let mut secret = [0_16; SABER_N];
280
281 for i in 0..SABER_N/4 {
282 let k1 = 4 * i;
283 let k2 = k1 + 4;
284 let t = <Self as SaberAlgorithm>::load_little_endian(&buf[k1..k2]) as u32;
285 let mut d = 0_u32;
286 for j in 0..4 {
287 d += (t >> j) & 0x11111111;
288 }
289
290 a[0] = d & 0xf;
291 b[0] = (d >> 4) & 0xf;
292 a[1] = (d >> 8) & 0xf;
293 b[1] = (d >> 12) & 0xf;
294 a[2] = (d >> 16) & 0xf;
295 b[2] = (d >> 20) & 0xf;
296 a[3] = (d >> 24) & 0xf;
297 b[3] = d >> 28;
298
299 secret[4 * i + 0] = (a[0] as i32 - b[0] as i32) as u16;
300 secret[4 * i + 1] = (a[1] as i32 - b[1] as i32) as u16;
301 secret[4 * i + 2] = (a[2] as i32 - b[2] as i32) as u16;
302 secret[4 * i + 3] = (a[3] as i32 - b[3] as i32) as u16;
303
304 }
305 secret
306 }
307}
308
309impl SaberAlgorithm for FireSaber {
310
311 const L: usize = 4;
312 const ET: usize = 6;
313 const MU: usize = 6;
314
315 fn polt2bs<
316 const N: usize,
317 const SBK: usize,
318 >(
319 data: &[u16; N],
320 start: usize,
321 ) -> [u8; SBK]
322 {
323 let mut bytes = [0u8; SBK];
324 for j in 0..N/4 {
325 let offset_byte = start + 3 * j;
326 let offset_data = 4 * j;
327 bytes[offset_byte + 0] = (
328 (data[offset_data + 0] & 0x3f) |
329 ((data[offset_data + 1] & 0x03) << 6)
330 ) as u8;
331 bytes[offset_byte + 1] = (
332 ((data[offset_data + 1] >> 2) & 0x0f) |
333 ((data[offset_data + 2] & 0x0f) << 4)
334 ) as u8;
335 bytes[offset_byte + 2] = (
336 ((data[offset_data + 2] >> 4) & 0x03) |
337 ((data[offset_data + 3] & 0x3f) << 2)
338 ) as u8;
339 }
340 bytes
341 }
342
343 fn bs2polt<
344 const N: usize,
345 const SBK: usize,
346 >(
347 bytes: &[u8; SBK],
348 start: usize,
349 ) -> [u16; N]
350 {
351 let mut data = [0u16; N];
352 for j in 0..N/4 {
353 let offset_byte = start + 3 * j;
354 let offset_data = 4 * j;
355 data[offset_data + 0] = (bytes[offset_byte + 0] & 0x3f) as u16;
356 data[offset_data + 1] = (
357 ((bytes[offset_byte + 0] >> 6) & 0x03) |
358 ((bytes[offset_byte + 1] & 0x0f) << 2)
359 ) as u16;
360 data[offset_data + 2] = (
361 ((bytes[offset_byte + 1] & 0xff) >> 4) |
362 ((bytes[offset_byte + 2] & 0x03) << 4)
363 ) as u16;
364 data[offset_data + 3] = ((bytes[offset_byte + 2] & 0xff) >> 2) as u16;
365 }
366 data
367 }
368
369 fn cbd(&self, buf: &[u8]) -> [u16; SABER_N] {
370 let mut a = [0_u32; 4];
371 let mut b = [0_u32; 4];
372 let mut secret = [0_16; SABER_N];
373
374 for i in 0..SABER_N/4 {
375 let k1 = 3 * i;
376 let k2 = k1 + 3;
377 let t = <Self as SaberAlgorithm>::load_little_endian(&buf[k1..k2]) as u32;
378 let mut d = 0_u32;
379 for j in 0..3 {
380 d += (t >> j) & 0x249249;
381 }
382
383 a[0] = d & 0x7;
384 b[0] = (d >> 3) & 0x7;
385 a[1] = (d >> 6) & 0x7;
386 b[1] = (d >> 9) & 0x7;
387 a[2] = (d >> 12) & 0x7;
388 b[2] = (d >> 15) & 0x7;
389 a[3] = (d >> 18) & 0x7;
390 b[3] = d >> 21;
391
392 secret[4 * i + 0] = (a[0] as i32 - b[0] as i32) as u16;
393 secret[4 * i + 1] = (a[1] as i32 - b[1] as i32) as u16;
394 secret[4 * i + 2] = (a[2] as i32 - b[2] as i32) as u16;
395 secret[4 * i + 3] = (a[3] as i32 - b[3] as i32) as u16;
396
397 }
398 secret
399 }
400}
401
402pub trait SaberAlgorithm: fmt::Display {
403
404 const L: usize;
405 const ET: usize;
406 const MU: usize;
407
408 const POLY_COIN_BYTES: usize = Self::MU * SABER_N / 8;
409 const POLY_VEC_BYTES: usize = Self::L * POLY_BYTES;
410 const POLY_VEC_COMPRESSED_BYTES: usize = Self::L * POLY_COMPRESSED_BYTES;
411 const SCALE_BYTES_KEM: usize = Self::ET * SABER_N / 8;
412 const INDCPA_PUBLIC_KEY_BYTES: usize = Self::POLY_VEC_COMPRESSED_BYTES + SEED_BYTES;
413 const INDCPA_SECRET_KEY_BYTES: usize = Self::POLY_VEC_BYTES;
414 const PUBLIC_KEY_BYTES: usize = Self::INDCPA_PUBLIC_KEY_BYTES;
415 const SECRET_KEY_BYTES: usize =
416 Self::INDCPA_SECRET_KEY_BYTES +
417 Self::INDCPA_PUBLIC_KEY_BYTES +
418 HASH_BYTES +
419 KEY_BYTES;
420 const CIPHERTEXT_BYTES: usize =
421 Self::POLY_VEC_COMPRESSED_BYTES + Self::SCALE_BYTES_KEM;
422
423 const PK_LEN: usize = Self::POLY_VEC_COMPRESSED_BYTES;
424 const SK_LEN: usize = Self::POLY_VEC_BYTES;
425
426 const H1: u16 = (1 << (EQ - EP - 1)) as u16;
427 const H2: u16 = (
428 (1 << (EP - 2)) -
429 (1 << (EP - Self::ET - 1)) +
430 (1 << (EQ - EP - 1))
431 ) as u16;
432 const H3: u16 = (EP - Self::ET) as u16;
433
434 fn pk_len(&self) -> usize { Self::PUBLIC_KEY_BYTES }
435 fn sk_len(&self) -> usize { Self::SECRET_KEY_BYTES }
436 fn ct_len(&self) -> usize { Self::CIPHERTEXT_BYTES }
437
438 /// IND-CPA Algorithm 17
439 /// # Parameters
440 /// * `L` - The length of the polynomial vector (i.e. the rank [`Self::L`])
441 /// * `PVB` - The length of the byte string into [`Self::bs2polvecq`] and out of [`Self::polvecq2bs`] (i.e. [`Self::POLY_VEC_BYTES`])
442 /// * `L_PVB` - The length of the [`Self::gen_matrix`] byte string (i.e. [`Self::L * Self::POLY_VEC_BYTES`])
443 /// * `PVCB` - The length of the byte string from [`Self::polvecp2bs`] (i.e. [`Self::POLY_VEC_COMPRESSED_BYTES`])
444 /// * `PCB` - The length of the byte string into cbd (i.e. [`Self::POLY_COIN_BYTES`])
445 /// * `L_PCB` - The length of the byte string into bs2polvecq (i.e. [`Self::L * Self::POLY_COIN_BYTES`])
446 fn generic_pke_keygen<
447 const L: usize,
448 const PVB: usize,
449 const L_PVB: usize,
450 const PVCB: usize,
451 const PCB: usize,
452 const L_PCB: usize,
453 >(
454 &self,
455 mut seed_a: [u8; SEED_BYTES],
456 seed_s: [u8; NOISE_SEED_BYTES],
457 ) -> (
458 PublicKey<PVCB>,
459 SecretKeyCPA<PVB>,
460 ) {
461 let mut shake = Shake::v128();
462 shake.update(&seed_a);
463 shake.finalize(&mut seed_a);
464
465 let mut a = [[[0_u16; SABER_N]; L]; L];
466 Self::gen_matrix::<L, PVB, L_PVB>(&mut a, &seed_a);
467
468 let mut secret = [[0_u16; SABER_N]; L];
469 Self::gen_secret::<L, PCB, L_PCB>(&self, &mut secret, &seed_s);
470 let mut b = [[0_u16; SABER_N]; L];
471 Self::matrix_vector_mul::<L>(&a, &secret, &mut b, true);
472
473 for i in 0..L {
474 for j in 0..SABER_N {
475 b[i][j] = b[i][j].wrapping_add(Self::H1) >> (EQ - EP);
476 }
477 }
478
479 let sk = Self::polvecq2bs::<SABER_N, L, POLY_BYTES, PVB>(&secret);
480 let pk = Self::polvecp2bs::<SABER_N, L, POLY_COMPRESSED_BYTES, PVCB>(&b);
481
482 (
483 PublicKey::new(seed_a, pk),
484 SecretKeyCPA::new(sk),
485 )
486 }
487
488 /// IND-CPA Algorithm 18
489 /// # Parameters
490 /// * `L` - [`Self::L`]
491 /// * `PVB` - [`Self::POLY_VEC_BYTES`]
492 /// * `L_PVB` - [`Self::L * Self::POLY_VEC_BYTES`]
493 /// * `PVCB` - [`Self::POLY_VEC_COMPRESSED_BYTES`]
494 /// * `PCB` - [`Self::POLY_COIN_BYTES`]
495 /// * `L_PCB` - [`Self::L * Self::POLY_COIN_BYTES`]
496 /// * `SBK` - [`Self::SCALE_BYTES_KEM`]
497 fn generic_pke_enc<
498 const L: usize,
499 const PVB: usize,
500 const L_PVB: usize,
501 const PVCB: usize,
502 const PCB: usize,
503 const L_PCB: usize,
504 const SBK: usize,
505 >(
506 &self,
507 m: &[u8; KEY_BYTES],
508 seed_sp:&[u8; SEED_BYTES],
509 pk: &PublicKey<PVCB>,
510 ) -> CipherText<SBK, PVCB>
511 {
512 // 2
513 let mut a = [[[0_u16; SABER_N]; L]; L];
514 Self::gen_matrix::<L, PVB, L_PVB>(&mut a, pk.seed_ref());
515 // 3
516 let mut sp = [[0_u16; SABER_N]; L];
517 Self::gen_secret::<L, PCB, L_PCB>(&self, &mut sp, seed_sp);
518 // 4
519 let mut bp = [[0_u16; SABER_N]; L];
520 Self::matrix_vector_mul::<L>(&a, &sp, &mut bp, false);
521 // 5-6
522 for i in 0..L {
523 for j in 0..SABER_N {
524 bp[i][j] = bp[i][j].wrapping_add(Self::H1) >> (EQ - EP);
525 }
526 }
527
528 // ?
529 let ct = Self::polvecp2bs::<SABER_N, L, POLY_COMPRESSED_BYTES, PVCB>(&bp);
530 // 7
531 let b = Self::bs2polvecp::<SABER_N, L, POLY_COMPRESSED_BYTES, PVCB>(pk.key_ref());
532 // 8
533 let mut vp = [0_u16; SABER_N];
534 Self::inner_prod::<L>(&b, &sp, &mut vp);
535 // 9-11
536 let mp = Self::bs2polmsg::<SABER_N, KEY_BYTES>(&m);
537 for j in 0..SABER_N {
538 vp[j] = (
539 (vp[j] as i32 - (mp[j] << (EP - 1)) as i32) as u16
540 ).wrapping_add(Self::H1) >> (EP - Self::ET);
541 }
542 let cm = Self::polt2bs::<SABER_N, SBK>(&vp, 0);
543
544 CipherText {
545 cm: cm,
546 ct: ct,
547 }
548 }
549
550 /// A WebAssembly version of Self::generic_pke_enc that avoids accepting a PublicKey argument,
551 /// instead accepting the public key and seed parts as arrays, and returns the
552 /// ciphertext as an owned vector.
553 fn generic_pke_enc_wasm<
554 const L: usize,
555 const PVB: usize,
556 const L_PVB: usize,
557 const PVCB: usize,
558 const PCB: usize,
559 const L_PCB: usize,
560 const SBK: usize,
561 >(
562 &self,
563 m: &[u8; KEY_BYTES],
564 seed_sp:&[u8; SEED_BYTES],
565 pk_key: &[u8; PVCB],
566 pk_seed:&[u8; SEED_BYTES],
567 ) -> Vec<u8> // Ciphertext
568 {
569 // 2
570 let mut a = [[[0_u16; SABER_N]; L]; L];
571 Self::gen_matrix::<L, PVB, L_PVB>(&mut a, pk_seed);
572 // 3
573 let mut sp = [[0_u16; SABER_N]; L];
574 Self::gen_secret::<L, PCB, L_PCB>(&self, &mut sp, seed_sp);
575 // 4
576 let mut bp = [[0_u16; SABER_N]; L];
577 Self::matrix_vector_mul::<L>(&a, &sp, &mut bp, false);
578 // 5-6
579 for i in 0..L {
580 for j in 0..SABER_N {
581 bp[i][j] = bp[i][j].wrapping_add(Self::H1) >> (EQ - EP);
582 }
583 }
584
585 // ?
586 let ct = Self::polvecp2bs::<SABER_N, L, POLY_COMPRESSED_BYTES, PVCB>(&bp);
587 // 7
588 let b = Self::bs2polvecp::<SABER_N, L, POLY_COMPRESSED_BYTES, PVCB>(pk_key);
589 // 8
590 let mut vp = [0_u16; SABER_N];
591 Self::inner_prod::<L>(&b, &sp, &mut vp);
592 // 9-11
593 let mp = Self::bs2polmsg::<SABER_N, KEY_BYTES>(&m);
594 for j in 0..SABER_N {
595 vp[j] = (
596 (vp[j] as i32 - (mp[j] << (EP - 1)) as i32) as u16
597 ).wrapping_add(Self::H1) >> (EP - Self::ET);
598 }
599 let cm = Self::polt2bs::<SABER_N, SBK>(&vp, 0);
600
601 [&ct[..], &cm[..]].concat()
602 }
603
604 /// IND-CPA Algorithm 19
605 /// # Parameters
606 /// * `L` - [`Self::L`]
607 /// * `PVB` - [`Self::POLY_VEC_BYTES`]
608 /// * `L_PVB` - [`Self::L * Self::POLY_VEC_BYTES`]
609 /// * `PVCB` - [`Self::POLY_VEC_COMPRESSED_BYTES`]
610 /// * `PCB` - [`Self::POLY_COIN_BYTES`]
611 /// * `L_PCB` - [`Self::L * Self::POLY_COIN_BYTES`]
612 /// * `SBK` - [`Self::SCALE_BYTES_KEM`]
613 fn generic_pke_dec<
614 const L: usize,
615 const PVB: usize,
616 const L_PVB: usize,
617 const PVCB: usize,
618 const PCB: usize,
619 const L_PCB: usize,
620 const SBK: usize,
621 >(
622 &self,
623 ciphertext: &CipherText<SBK, PVCB>,
624 sk: &SecretKeyCPA<PVB>,
625 ) -> [u8; KEY_BYTES]
626 {
627
628 let s = Self::bs2polvecq::<SABER_N, L, POLY_BYTES, PVB>(sk.key_ref());
629 let b = Self::bs2polvecp::<SABER_N, L, POLY_COMPRESSED_BYTES, PVCB>(&ciphertext.ct);
630 let mut v = [0_u16; SABER_N];
631 Self::inner_prod::<L>(&b, &s, &mut v);
632 let cm = Self::bs2polt::<SABER_N, SBK>(&ciphertext.cm, 0);
633
634 for i in 0..SABER_N {
635 //msg!("i = {}", i);
636 v[i] = ((
637 v[i].wrapping_add(Self::H2) as i32 - (cm[i] << Self::H3) as i32
638 ) >> (EP - 1)) as u16;
639 }
640
641 Self::polmsg2bs::<SABER_N, KEY_BYTES>(&v)
642 }
643
644 /// IND-CCA Algorithm 20
645 /// # Parameters
646 /// * `L` - [`Self::L`]
647 /// * `PVB` - [`Self::POLY_VEC_BYTES`]
648 /// * `L_PVB` - [`Self::L * Self::POLY_VEC_BYTES`]
649 /// * `PVCB` - [`Self::POLY_VEC_COMPRESSED_BYTES`]
650 /// * `PCB` - [`Self::POLY_COIN_BYTES`]
651 /// * `L_PCB` - [`Self::L * Self::POLY_COIN_BYTES`]
652 fn generic_kem_keygen<
653 const L: usize,
654 const PVB: usize,
655 const L_PVB: usize,
656 const PVCB: usize,
657 const PCB: usize,
658 const L_PCB: usize,
659 >(
660 &self,
661 seed_a: [u8; SEED_BYTES],
662 seed_s: [u8; NOISE_SEED_BYTES],
663 rand: [u8; KEY_BYTES],
664 ) -> (
665 PublicKey<PVCB>,
666 SecretKeyCCA<PVB, PVCB>,
667 ) {
668 let (pk, sk) =
669 Self::generic_pke_keygen::<
670 L, PVB, L_PVB, PVCB, PCB, L_PCB,
671 >(
672 &self,
673 seed_a,
674 seed_s,
675 );
676
677 let mut hash_pk = [0_u8; HASH_BYTES];
678 let mut sha3 = Sha3::v256();
679 sha3.update(&pk.to_bytes());
680 sha3.finalize(&mut hash_pk);
681
682 (
683 pk.clone(),
684 SecretKeyCCA {
685 sk: sk,
686 pk: pk,
687 pk_hash:hash_pk,
688 rand: rand,
689 },
690 )
691 }
692
693 /// IND-CCA Algorithm 21
694 /// # Parameters
695 /// * `L` - [`Self::L`]
696 /// * `PVB` - [`Self::POLY_VEC_BYTES`]
697 /// * `L_PVB` - [`Self::L * Self::POLY_VEC_BYTES`]
698 /// * `PVCB` - [`Self::POLY_VEC_COMPRESSED_BYTES`]
699 /// * `PCB` - [`Self::POLY_COIN_BYTES`]
700 /// * `L_PCB` - [`Self::L * Self::POLY_COIN_BYTES`]
701 /// * `SBK` - [`Self::SCALE_BYTES_KEM`]
702 /// * `CT` - [`Self::CIPHERTEXT_BYTES`]
703 fn generic_kem_encap<
704 const L: usize,
705 const PVB: usize,
706 const L_PVB: usize,
707 const PVCB: usize,
708 const PCB: usize,
709 const L_PCB: usize,
710 const SBK: usize,
711 const CT: usize,
712 >(
713 &self,
714 pk: &PublicKey<PVCB>,
715 mut m: [u8; KEY_BYTES],
716 ) -> (
717 [u8; KEY_BYTES], // Session key
718 CipherText<SBK, PVCB>,
719 ) {
720 // 1
721 // Accept m as a function parameter to allow validation testing
722 // 2
723 let mut hasher = Sha3::v256();
724 hasher.update(&m);
725 hasher.finalize(&mut m);
726 // 3
727 let mut hash_pk = [0_u8; HASH_BYTES];
728 let mut hasher = Sha3::v256();
729 hasher.update(&pk.to_bytes());
730 hasher.finalize(&mut hash_pk);
731 // 4
732 let buf = [&m[..], &hash_pk[..]].concat();
733 // 5
734 // Two `KEY_BYTES`-wide halves: `kr[0]` is the key part, `kr[1]`
735 // the seed part. Splitting into fixed sub-arrays lets the seed be
736 // passed as `&[u8; SEED_BYTES]` without a fallible slice-to-array
737 // conversion (`KEY_BYTES == SEED_BYTES`).
738 let mut kr = [[0u8; KEY_BYTES]; 2];
739 let mut hasher = Sha3::v512();
740 hasher.update(&buf);
741 hasher.finalize(kr.as_flattened_mut());
742
743 // 7
744 let ciphertext =
745 Self::generic_pke_enc::<
746 L, PVB, L_PVB, PVCB, PCB, L_PCB, SBK,
747 >(
748 &self,
749 &m,
750 &kr[1],
751 pk,
752 );
753
754 // 8
755 let mut rdash = [0_u8; KEY_BYTES];
756 let mut hasher = Sha3::v256();
757 hasher.update(&ciphertext.to_bytes::<CT>());
758 hasher.finalize(&mut rdash);
759 // 9
760 let krdash = [&kr[0][..], &rdash[..]].concat();
761 // 10
762 let mut session_key = [0u8; KEY_BYTES];
763 let mut hasher = Sha3::v256();
764 hasher.update(&krdash);
765 hasher.finalize(&mut session_key);
766
767 (session_key, ciphertext)
768 }
769
770 /// A WebAssembly version of Self::generic_kem_enc that
771 /// - avoids accepting a PublicKey argument, instead accepting the public key and seed parts
772 /// as a slice and array respectively,
773 /// - moves the session secret from an output to a mutable input,
774 /// - returns the ciphertext as an owned vector,
775 /// - generates the seed value `m` here instead of accepting it as an argument
776 fn generic_kem_encap_wasm<
777 const L: usize,
778 const PVB: usize,
779 const L_PVB: usize,
780 const PVCB: usize,
781 const PCB: usize,
782 const L_PCB: usize,
783 const SBK: usize,
784 >(
785 &self,
786 pk_key: &[u8],
787 pk_seed: &[u8],
788 mut secret: &mut [u8], // Session key
789 ) ->
790 Outcome<Vec<u8>> // Ciphertext
791 {
792 // 1
793 let mut m = [0_u8; KEY_BYTES];
794 OsRng.fill_bytes(&mut m);
795 // 2
796 let mut hasher = Sha3::v256();
797 hasher.update(&m);
798 hasher.finalize(&mut m);
799 // 3
800 let mut hash_pk = [0_u8; HASH_BYTES];
801 let mut hasher = Sha3::v256();
802 let pk_bytes = [&pk_key[..], &pk_seed].concat();
803 hasher.update(&pk_bytes);
804 hasher.finalize(&mut hash_pk);
805 // 4
806 let buf = [&m[..], &hash_pk[..]].concat();
807 // 5
808 // Two `KEY_BYTES`-wide halves: `kr[0]` is the key part, `kr[1]`
809 // the seed part. Splitting into fixed sub-arrays lets the seed be
810 // passed as `&[u8; SEED_BYTES]` without a fallible slice-to-array
811 // conversion (`KEY_BYTES == SEED_BYTES`).
812 let mut kr = [[0u8; KEY_BYTES]; 2];
813 let mut hasher = Sha3::v512();
814 hasher.update(&buf);
815 hasher.finalize(kr.as_flattened_mut());
816
817 // 7
818 // Validate the caller-supplied public-key material at this
819 // boundary rather than panicking, since it originates outside
820 // the library (the WebAssembly entry points).
821 let pk_key_arr = match TryInto::<&[u8; PVCB]>::try_into(pk_key) {
822 Ok(a) => a,
823 Err(_) => return Err(err!(
824 "wasm KEM encapsulation: public-key part is {} bytes, expected {}.",
825 pk_key.len(), PVCB; Input, Invalid)),
826 };
827 let pk_seed_arr = match TryInto::<&[u8; SEED_BYTES]>::try_into(pk_seed) {
828 Ok(a) => a,
829 Err(_) => return Err(err!(
830 "wasm KEM encapsulation: public-key seed is {} bytes, expected {}.",
831 pk_seed.len(), SEED_BYTES; Input, Invalid)),
832 };
833 let ciphertext =
834 Self::generic_pke_enc_wasm::<
835 L, PVB, L_PVB, PVCB, PCB, L_PCB, SBK,
836 >(
837 &self,
838 &m,
839 &kr[1],
840 pk_key_arr,
841 pk_seed_arr,
842 );
843
844 // 8
845 let mut rdash = [0_u8; KEY_BYTES];
846 let mut hasher = Sha3::v256();
847 hasher.update(&ciphertext);
848 hasher.finalize(&mut rdash);
849 // 9
850 let krdash = [&kr[0][..], &rdash[..]].concat();
851 // 10
852 let mut hasher = Sha3::v256();
853 hasher.update(&krdash);
854 hasher.finalize(&mut secret);
855
856 Ok(ciphertext)
857 }
858
859 /// IND-CCA Algorithm 22
860 /// # Parameters
861 /// * `L` - [`Self::L`]
862 /// * `PVB` - [`Self::POLY_VEC_BYTES`]
863 /// * `L_PVB` - [`Self::L * Self::POLY_VEC_BYTES`]
864 /// * `PVCB` - [`Self::POLY_VEC_COMPRESSED_BYTES`]
865 /// * `PCB` - [`Self::POLY_COIN_BYTES`]
866 /// * `L_PCB` - [`Self::L * Self::POLY_COIN_BYTES`]
867 /// * `SBK` - [`Self::SCALE_BYTES_KEM`]
868 /// * `CT` - [`Self::CIPHERTEXT_BYTES`]
869 fn generic_kem_decap<
870 const L: usize,
871 const PVB: usize,
872 const L_PVB: usize,
873 const PVCB: usize,
874 const PCB: usize,
875 const L_PCB: usize,
876 const SBK: usize,
877 const CT: usize,
878 >(
879 &self,
880 ct_bytes: &[u8],
881 sk: &SecretKeyCCA<PVB, PVCB>,
882 ) ->
883 Outcome<[u8; KEY_BYTES]> // Session key
884 {
885 // 1
886 let ct = res!(CipherText::<SBK, PVCB>::from_bytes(ct_bytes));
887 // 2
888 let m = self.generic_pke_dec::<L, PVB, L_PVB, PVCB, PCB, L_PCB, SBK>(&ct, sk.key_ref());
889 // 3
890 let buf = [&m[..], &sk.pk_hash_ref()[..]].concat();
891 // 4
892 // Two `KEY_BYTES`-wide halves: `kr[0]` is the key part, `kr[1]`
893 // the seed part. Splitting into fixed sub-arrays lets the seed be
894 // passed as `&[u8; SEED_BYTES]` without a fallible slice-to-array
895 // conversion (`KEY_BYTES == SEED_BYTES`).
896 let mut kr = [[0u8; KEY_BYTES]; 2];
897 let mut hasher = Sha3::v512();
898 hasher.update(&buf);
899 hasher.finalize(kr.as_flattened_mut());
900 // 6
901 let ciphertext_dash =
902 Self::generic_pke_enc::<
903 L, PVB, L_PVB, PVCB, PCB, L_PCB, SBK,
904 >(
905 &self,
906 &m,
907 &kr[1],
908 sk.pk_ref(),
909 );
910 let ctdash_bytes = ciphertext_dash.to_bytes::<CT>();
911 // 7
912 let same = res!(Self::verify(&ctdash_bytes, ct_bytes));
913 // 8
914 let mut rdash = [0_u8; KEY_BYTES];
915 let mut hasher = Sha3::v256();
916 hasher.update(&ctdash_bytes);
917 hasher.finalize(&mut rdash);
918 // 9-12
919 // the order of these concatenations seems to be erroneously reversed in the report text
920 let temp = if same {
921 [&kr[0][..], &rdash[..]].concat()
922 } else {
923 [&sk.rand_ref()[..], &rdash[..]].concat()
924 };
925 // 13
926 let mut session_key = [0u8; KEY_BYTES];
927 let mut hasher = Sha3::v256();
928 hasher.update(&temp);
929 hasher.finalize(&mut session_key);
930 Ok(session_key)
931 }
932
933 fn verify(a: &[u8], b: &[u8]) -> Outcome<bool> {
934 if a.len() != b.len() {
935 return Err(err!(
936 "First slice length = {}, second slice length = {}.",
937 a.len(),
938 b.len();
939 Index, Mismatch));
940 }
941 let mut r: u64 = 0;
942 for i in 0..a.len() {
943 r |= (a[i] ^ b[i]) as u64;
944 }
945 //r = (-r) >> 63;
946 Ok(r == 0)
947 }
948
949 /// This method represents Algorithm 10 of the
950 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
951 /// packs the 3 significant bits from each u16 polynomial coefficient for the case `N` = `T`
952 /// into a byte string.
953 ///
954 /// # Parameters
955 /// * `N` - The order of the outgoing polynomial vector (i.e. [`SABER_N`])
956 /// * `SBK` - [`Self::SCALE_BYTES_KEM`]
957 fn polt2bs<
958 const N: usize,
959 const SBK: usize,
960 >(
961 data: &[u16; N],
962 start: usize,
963 ) -> [u8; SBK];
964
965 /// This method represents Algorithm 9 of the
966 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
967 /// unpacks chunks of 13 significant bits from the string into u16 polynomial coefficients for
968 /// the case `N` = `T`. This does not change between the schemes.
969 ///
970 /// # Parameters
971 /// * `N` - The order of the modified polynomial vector (i.e. [`SABER_N`])
972 /// * `SBK` - [`Self::SCALE_BYTES_KEM`]
973 fn bs2polt<
974 const N: usize,
975 const SBK: usize,
976 >(
977 bytes: &[u8; SBK],
978 start: usize,
979 ) -> [u16; N];
980
981 /// This method represents Algorithm 10 of the
982 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
983 /// packs the 13 significant bits from each u16 polynomial coefficient for the case `N` = `q`
984 /// into a byte string. This does not change between the schemes.
985 ///
986 /// # Parameters
987 /// * `N` - The order of the outgoing polynomial vector (i.e. [`SABER_N`])
988 fn polq2bs<
989 const N: usize,
990 >(
991 data: &[u16; N],
992 bytes: &mut [u8],
993 start: usize,
994 ) {
995 for j in 0..N/8 {
996 let offset_byte = start + 13 * j;
997 let offset_data = 8 * j;
998 bytes[offset_byte + 0] = (data[offset_data + 0] & (0xff)) as u8;
999 bytes[offset_byte + 1] = (
1000 ((data[offset_data + 0] >> 8) & 0x1f) |
1001 ((data[offset_data + 1] & 0x07) << 5)
1002 ) as u8;
1003 bytes[offset_byte + 2] = ((data[offset_data + 1] >> 3) & 0xff) as u8;
1004 bytes[offset_byte + 3] = (
1005 ((data[offset_data + 1] >> 11) & 0x03) |
1006 ((data[offset_data + 2] & 0x3f) << 2)
1007 ) as u8;
1008 bytes[offset_byte + 4] = (
1009 ((data[offset_data + 2] >> 6) & 0x7f) |
1010 ((data[offset_data + 3] & 0x01) << 7)
1011 ) as u8;
1012 bytes[offset_byte + 5] = ((data[offset_data + 3] >> 1) & 0xff) as u8;
1013 bytes[offset_byte + 6] = (
1014 ((data[offset_data + 3] >> 9) & 0x0f) |
1015 ((data[offset_data + 4] & 0x0f) << 4)
1016 ) as u8;
1017 bytes[offset_byte + 7] = ((data[offset_data + 4] >> 4) & 0xff) as u8;
1018 bytes[offset_byte + 8] = (
1019 ((data[offset_data + 4] >> 12) & 0x01) |
1020 ((data[offset_data + 5] & 0x7f) << 1)
1021 ) as u8;
1022 bytes[offset_byte + 9] = (
1023 ((data[offset_data + 5] >> 7) & 0x3f) |
1024 ((data[offset_data + 6] & 0x03) << 6)
1025 ) as u8;
1026 bytes[offset_byte + 10] = ((data[offset_data + 6] >> 2) & 0xff) as u8;
1027 bytes[offset_byte + 11] = (
1028 ((data[offset_data + 6] >> 10) & 0x07) |
1029 ((data[offset_data + 7] & 0x1f) << 3)
1030 ) as u8;
1031 bytes[offset_byte + 12] = ((data[offset_data + 7] >> 5) & 0xff) as u8;
1032 }
1033 }
1034
1035 /// This method represents Algorithm 12 of the
1036 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
1037 /// packs the 13 significant bits from each u16 polynomial coefficient for the given vector of
1038 /// polynomials, where `N` = `q`, into a byte string. This does not change between the
1039 /// schemes.
1040 ///
1041 /// # Parameters
1042 /// * `N` - The order of the outgoing polynomial vector (i.e. [`SABER_N`])
1043 /// * `L` - The length of the polynomial vector (i.e. the rank [`Self::L`])
1044 /// * `I` - The length of the byte string from polq2bs (i.e. [`POLY_BYTES`])
1045 /// * `B` - The length of the outgoing byte string (i.e. [`Self::POLY_VEC_BYTES`])
1046 fn polvecq2bs<
1047 const N: usize,
1048 const L: usize,
1049 const I: usize,
1050 const B: usize,
1051 >(
1052 data: &[[u16; N]; L],
1053 ) -> [u8; B]
1054 {
1055 let mut bytes = [0; B];
1056 for i in 0..L {
1057 Self::polq2bs(&data[i], &mut bytes, i * I);
1058 }
1059 bytes
1060 }
1061
1062 /// This method represents Algorithm 10 of the
1063 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
1064 /// packs the 10 significant bits from each u16 polynomial coefficient for the case `N` = `p`
1065 /// into a byte string. This does not change between the schemes.
1066 ///
1067 /// # Parameters
1068 /// * `N` - The order of the incoming polynomial vector (i.e. [`SABER_N`])
1069 fn polp2bs<
1070 const N: usize,
1071 >(
1072 data: &[u16; N],
1073 bytes: &mut [u8],
1074 start: usize,
1075 ) {
1076 for j in 0..N/4 {
1077 let offset_byte = start + 5 * j;
1078 let offset_data = 4 * j;
1079 bytes[offset_byte + 0] = (data[offset_data + 0] & (0xff)) as u8;
1080 bytes[offset_byte + 1] = (
1081 ((data[offset_data + 0] >> 8) & 0x03) |
1082 ((data[offset_data + 1] & 0x3f) << 2)
1083 ) as u8;
1084 bytes[offset_byte + 2] = (
1085 ((data[offset_data + 1] >> 6) & 0x0f) |
1086 ((data[offset_data + 2] & 0x0f) << 4)
1087 ) as u8;
1088 bytes[offset_byte + 3] = (
1089 ((data[offset_data + 2] >> 4) & 0x3f) |
1090 ((data[offset_data + 3] & 0x03) << 6)
1091 ) as u8;
1092 bytes[offset_byte + 4] = ((data[offset_data + 3] >> 2) & 0xff) as u8;
1093 }
1094 }
1095
1096 /// This method represents Algorithm 12 of the
1097 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
1098 /// packs the 10 significant bits from each u16 polynomial coefficient for the given vector of
1099 /// polynomials, where `N` = `p`, into a byte string. This does not change between the
1100 /// schemes.
1101 ///
1102 /// # Parameters
1103 /// * `N` - The order of the incoming polynomial vector (i.e. [`SABER_N`])
1104 /// * `L` - The length of the polynomial vector (i.e. the rank [`Self::L`])
1105 /// * `I` - The length of the byte string from polq2bs (i.e. [`POLY_COMPRESSED_BYTES`])
1106 /// * `B` - The length of the outgoing byte string (i.e. [`Self::POLY_VEC_COMPRESSED_BYTES`])
1107 fn polvecp2bs<
1108 const N: usize,
1109 const L: usize,
1110 const I: usize,
1111 const B: usize,
1112 >(
1113 data: &[[u16; N]; L],
1114 ) -> [u8; B]
1115 {
1116 let mut bytes = [0; B];
1117 for i in 0..L {
1118 Self::polp2bs(&data[i], &mut bytes, i * I);
1119 }
1120 bytes
1121 }
1122
1123 /// This method represents Algorithm 9 of the
1124 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
1125 /// unpacks chunks of 13 significant bits from the string into u16 polynomial coefficients for
1126 /// the case `N` = `q`. This does not change between the schemes.
1127 ///
1128 /// # Parameters
1129 /// * `N` - The order of the modified polynomial vector (i.e. [`SABER_N`])
1130 fn bs2polq<
1131 const N: usize,
1132 >(
1133 bytes: &[u8],
1134 data: &mut [u16; N],
1135 ) {
1136 for j in 0..N/8 {
1137 let offset_byte = 13 * j;
1138 let offset_data = 8 * j;
1139 data[offset_data + 0] =
1140 (bytes[offset_byte + 0] as u16 & (0xff)) |
1141 ((bytes[offset_byte + 1] as u16 & 0x1f) << 8);
1142 data[offset_data + 1] =
1143 (bytes[offset_byte + 1] as u16 >> 5 & (0x07)) |
1144 ((bytes[offset_byte + 2] as u16 & 0xff) << 3) |
1145 ((bytes[offset_byte + 3] as u16 & 0x03) << 11);
1146 data[offset_data + 2] =
1147 (bytes[offset_byte + 3] as u16 >> 2 & (0x3f)) |
1148 ((bytes[offset_byte + 4] as u16 & 0x7f) << 6);
1149 data[offset_data + 3] =
1150 (bytes[offset_byte + 4] as u16 >> 7 & (0x01)) |
1151 ((bytes[offset_byte + 5] as u16 & 0xff) << 1) |
1152 ((bytes[offset_byte + 6] as u16 & 0x0f) << 9);
1153 data[offset_data + 4] =
1154 (bytes[offset_byte + 6] as u16 >> 4 & (0x0f)) |
1155 ((bytes[offset_byte + 7] as u16 & 0xff) << 4) |
1156 ((bytes[offset_byte + 8] as u16 & 0x01) << 12);
1157 data[offset_data + 5] =
1158 (bytes[offset_byte + 8] as u16 >> 1 & (0x7f)) |
1159 ((bytes[offset_byte + 9] as u16 & 0x3f) << 7);
1160 data[offset_data + 6] =
1161 (bytes[offset_byte + 9] as u16 >> 6 & (0x03)) |
1162 ((bytes[offset_byte + 10] as u16 & 0xff) << 2) |
1163 ((bytes[offset_byte + 11] as u16 & 0x07) << 10);
1164 data[offset_data + 7] =
1165 (bytes[offset_byte + 11] as u16 >> 3 & (0x1f)) |
1166 ((bytes[offset_byte + 12] as u16 & 0xff) << 5);
1167 }
1168 }
1169
1170 /// This method represents Algorithm 11 of the
1171 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
1172 /// unpacks chunks of 13 significant bits from the string into each set of u16 coefficients for
1173 /// the newly created vector of polynomials for the case `N` = `q`. This does not change
1174 /// between the schemes.
1175 ///
1176 /// # Parameters
1177 /// * `N` - The order of the outgoing polynomial vector (i.e. [`SABER_N`])
1178 /// * `L` - The length of the polynomial vector (i.e. the rank [`Self::L`])
1179 /// * `I` - The length of the byte string to bs2polq (i.e. [`POLY_BYTES`])
1180 /// * `B` - The length of the outgoing byte string (i.e. [`Self::POLY_VEC_BYTES`])
1181 fn bs2polvecq<
1182 const N: usize,
1183 const L: usize,
1184 const I: usize,
1185 const B: usize,
1186 >(
1187 bytes: &[u8; B],
1188 ) -> [[u16; N]; L]
1189 {
1190 let mut data = [[0; N]; L];
1191 for i in 0..L {
1192 let j = i * I;
1193 Self::bs2polq(&bytes[j..j+I], &mut data[i]);
1194 }
1195 data
1196 }
1197
1198 /// This method represents Algorithm 9 of the
1199 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
1200 /// unpacks chunks of 10 significant bits from the string into u16 polynomial coefficients for
1201 /// the case `N` = `p`. This does not change between the schemes.
1202 ///
1203 /// # Parameters
1204 /// * `N` - The order of the modified polynomial vector (i.e. [`SABER_N`])
1205 fn bs2polp<
1206 const N: usize,
1207 >(
1208 bytes: &[u8],
1209 data: &mut [u16; N],
1210 ) {
1211 for j in 0..N/4 {
1212 let offset_byte = 5 * j;
1213 let offset_data = 4 * j;
1214 data[offset_data + 0] =
1215 (bytes[offset_byte + 0] as u16 & (0xff)) |
1216 ((bytes[offset_byte + 1] as u16 & 0x03) << 8);
1217 data[offset_data + 1] =
1218 ((bytes[offset_byte + 1] as u16 >> 2) & (0x3f)) |
1219 ((bytes[offset_byte + 2] as u16 & 0x0f) << 6);
1220 data[offset_data + 2] =
1221 ((bytes[offset_byte + 2] as u16 >> 4) & (0x0f)) |
1222 ((bytes[offset_byte + 3] as u16 & 0x3f) << 4);
1223 data[offset_data + 3] =
1224 ((bytes[offset_byte + 3] as u16 >> 6) & (0x03)) |
1225 ((bytes[offset_byte + 4] as u16 & 0xff) << 2);
1226 }
1227 }
1228
1229 /// This method represents Algorithm 11 of the
1230 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
1231 /// unpacks chunks of 13 significant bits from the string into each set of u16 coefficients for
1232 /// the newly created vector of polynomials for the case `N` = `q`. This does not change
1233 /// between the schemes.
1234 ///
1235 /// # Parameters
1236 /// * `N` - The order of the outgoing polynomial vector (i.e. [`SABER_N`])
1237 /// * `L` - The length of the polynomial vector (i.e. the rank [`Self::L`])
1238 /// * `I` - The length of the byte string to bs2polq (i.e. [`POLY_COMPRESSED_BYTES`])
1239 /// * `B` - The length of the outgoing byte string (i.e. [`Self::POLY_VEC_COMPRESSED_BYTES`])
1240 fn bs2polvecp<
1241 const N: usize,
1242 const L: usize,
1243 const I: usize,
1244 const B: usize,
1245 >(
1246 bytes: &[u8; B],
1247 ) -> [[u16; N]; L]
1248 {
1249 let mut data = [[0; N]; L];
1250 for i in 0..L {
1251 let j = i * I;
1252 Self::bs2polp(&bytes[j..j+I], &mut data[i]);
1253 }
1254 data
1255 }
1256
1257 /// This method is not explicitly documented in the
1258 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
1259 /// interprets the bits from an arbitrary message as polynomial coefficients.
1260 ///
1261 /// # Parameters
1262 /// * `N` - The order of the outgoing polynomial vector (i.e. [`SABER_N`])
1263 /// * `B` - The length of the incoming byte string (i.e. [`KEY_BYTES`])
1264 fn bs2polmsg<
1265 const N: usize,
1266 const B: usize,
1267 >(
1268 bytes: &[u8; B],
1269 ) -> [u16; N]
1270 {
1271 let mut data = [0; N];
1272 for j in 0..B {
1273 for i in 0..8 {
1274 data[j * 8 + i] = ((bytes[j] as u16) >> i) & 0x01;
1275 }
1276 }
1277 data
1278 }
1279
1280 /// This method is not explicitly documented in the
1281 /// [spec](https://www.esat.kuleuven.be/cosic/pqcrypto/saber/files/saberspecround3.pdf). It
1282 /// interprets polynomial coefficients as a byte string message.
1283 ///
1284 /// # Parameters
1285 /// * `N` - The order of the outgoing polynomial vector (i.e. [`SABER_N`])
1286 /// * `B` - The length of the incoming byte string (i.e. [`KEY_BYTES`])
1287 fn polmsg2bs<
1288 const N: usize,
1289 const B: usize,
1290 >(
1291 data: &[u16; N],
1292 ) -> [u8; B]
1293 {
1294 let mut bytes = [0; B];
1295 for j in 0..B {
1296 for i in 0..8 {
1297 bytes[j] = bytes[j] | (((data[j * 8 + i] & 0x01) << i) as u8);
1298 }
1299 }
1300 bytes
1301 }
1302
1303 /// Performs Karatsuba multiplication of a subset of coefficients from two polynomials.
1304 fn karatsuba_simple(
1305 a_1: &[u16; MULT_KN],
1306 b_1: &[u16; MULT_KN],
1307 ) -> [u16; 2 * MULT_KN - 1]
1308 {
1309 let mut d01 = [0_i32; MULT_KN / 2 - 1];
1310 let mut d0123 = [0_i32; MULT_KN / 2 - 1];
1311 let mut d23 = [0_i32; MULT_KN / 2 - 1];
1312 let mut result_d01 = [0_i32; MULT_KN - 1];
1313 let mut result_final = [0_u16; 2 * MULT_KN - 1];
1314
1315 for i in 0..MULT_KN/4 {
1316 let acc1 = a_1[i]; //a0
1317 let acc2 = a_1[i + MULT_KN / 4]; //a1
1318 let acc3 = a_1[i + 2 * MULT_KN / 4]; //a2
1319 let acc4 = a_1[i + 3 * MULT_KN / 4]; //a3
1320
1321 for j in 0..MULT_KN/4 {
1322
1323 let mut acc5 = b_1[j]; //b0
1324 let mut acc6 = b_1[j + MULT_KN / 4]; //b1
1325
1326 result_final[i + j + 0 * MULT_KN / 4] =
1327 result_final[i + j + 0 * MULT_KN / 4]
1328 .wrapping_add(acc1.wrapping_mul(acc5));
1329 result_final[i + j + 2 * MULT_KN / 4] =
1330 result_final[i + j + 2 * MULT_KN / 4]
1331 .wrapping_add(acc2.wrapping_mul(acc6));
1332
1333 let mut acc7 = acc5.wrapping_add(acc6); //b01
1334 let mut acc8 = acc1.wrapping_add(acc2); //a01
1335 d01[i + j] = d01[i + j].wrapping_add(acc7.wrapping_mul(acc8) as i32);
1336
1337 acc7 = b_1[j + 2 * MULT_KN / 4]; //b2
1338 acc8 = b_1[j + 3 * MULT_KN / 4]; //b3
1339 result_final[i + j + 4 * MULT_KN / 4] =
1340 result_final[i + j + 4 * MULT_KN / 4]
1341 .wrapping_add(acc7.wrapping_mul(acc3));
1342
1343 result_final[i + j + 6 * MULT_KN / 4] =
1344 result_final[i + j + 6 * MULT_KN / 4]
1345 .wrapping_add(acc8.wrapping_mul(acc4));
1346
1347 let acc9 = acc3.wrapping_add(acc4);
1348 let acc10 = acc7.wrapping_add(acc8);
1349 d23[i + j] = d23[i + j].wrapping_add(acc9.wrapping_mul(acc10) as i32);
1350
1351 acc5 = acc5.wrapping_add(acc7); //b02
1352 acc7 = acc1.wrapping_add(acc3); //a02
1353 result_d01[i + j + 0 * MULT_KN / 4] =
1354 result_d01[i + j + 0 * MULT_KN / 4]
1355 .wrapping_add(acc5.wrapping_mul(acc7) as i32);
1356
1357 acc6 = acc6.wrapping_add(acc8); //b13
1358 acc8 = acc2.wrapping_add(acc4);
1359 result_d01[i + j + 2 * MULT_KN / 4] =
1360 result_d01[i + j + 2 * MULT_KN / 4]
1361 .wrapping_add(acc6.wrapping_mul(acc8) as i32);
1362
1363 acc5 = acc5.wrapping_add(acc6);
1364 acc7 = acc7.wrapping_add(acc8);
1365 d0123[i + j] = d0123[i + j].wrapping_add(acc5.wrapping_mul(acc7) as i32);
1366 }
1367 }
1368
1369 // 2nd last stage
1370
1371 for i in 0..(MULT_KN/2)-1 {
1372 d0123[i] = d0123[i]
1373 - result_d01[i + 0 * MULT_KN / 4]
1374 - result_d01[i + 2 * MULT_KN / 4];
1375 d01[i] = d01[i]
1376 - (result_final[i + 0 * MULT_KN / 4] as i32)
1377 - (result_final[i + 2 * MULT_KN / 4] as i32);
1378 d23[i] = d23[i]
1379 - (result_final[i + 4 * MULT_KN / 4] as i32)
1380 - (result_final[i + 6 * MULT_KN / 4] as i32);
1381 }
1382
1383 for i in 0..(MULT_KN/2)-1 {
1384 result_d01[i + 1 * MULT_KN / 4] =
1385 result_d01[i + 1 * MULT_KN / 4].wrapping_add(d0123[i]);
1386 result_final[i + 1 * MULT_KN / 4] =
1387 result_final[i + 1 * MULT_KN / 4].wrapping_add(d01[i] as u16);
1388 result_final[i + 5 * MULT_KN / 4] =
1389 result_final[i + 5 * MULT_KN / 4].wrapping_add(d23[i] as u16);
1390 }
1391
1392 // Last stage
1393 for i in 0..MULT_KN-1 {
1394 result_d01[i] = result_d01[i]
1395 - (result_final[i] as i32)
1396 - (result_final[i + MULT_KN] as i32);
1397 }
1398
1399 for i in 0..MULT_KN-1 {
1400 result_final[i + 1 * MULT_KN / 2] =
1401 result_final[i + 1 * MULT_KN / 2].wrapping_add(result_d01[i] as u16);
1402 }
1403 result_final
1404 }
1405
1406 fn toom_cook_4way(
1407 a: &[u16; SABER_N],
1408 b: &[u16; SABER_N],
1409 ) -> [u16; 2 * SABER_N]
1410 {
1411 const INV3: i32 = 43691;
1412 const INV9: i32 = 36409;
1413 const INV15: i32 = 61167;
1414
1415 let mut aw1 = [0_u16; MULT_N_SB];
1416 let mut aw2 = [0_u16; MULT_N_SB];
1417 let mut aw3 = [0_u16; MULT_N_SB];
1418 let mut aw4 = [0_u16; MULT_N_SB];
1419 let mut aw5 = [0_u16; MULT_N_SB];
1420 let mut aw6 = [0_u16; MULT_N_SB];
1421 let mut aw7 = [0_u16; MULT_N_SB];
1422
1423 let mut bw1 = [0_u16; MULT_N_SB];
1424 let mut bw2 = [0_u16; MULT_N_SB];
1425 let mut bw3 = [0_u16; MULT_N_SB];
1426 let mut bw4 = [0_u16; MULT_N_SB];
1427 let mut bw5 = [0_u16; MULT_N_SB];
1428 let mut bw6 = [0_u16; MULT_N_SB];
1429 let mut bw7 = [0_u16; MULT_N_SB];
1430
1431 let a0 = &a;
1432 let a1 = &a[MULT_N_SB..];
1433 let a2 = &a[2 * MULT_N_SB..];
1434 let a3 = &a[3 * MULT_N_SB..];
1435 let b0 = &b;
1436 let b1 = &b[MULT_N_SB..];
1437 let b2 = &b[2 * MULT_N_SB..];
1438 let b3 = &b[3 * MULT_N_SB..];
1439
1440 let mut c = [0_u16; 2 * SABER_N];
1441
1442 // EVALUATION
1443 for j in 0..MULT_N_SB {
1444 let r0 = a0[j];
1445 let r1 = a1[j];
1446 let r2 = a2[j];
1447 let r3 = a3[j];
1448 let mut r4 = r0.wrapping_add(r2);
1449 let mut r5 = r1.wrapping_add(r3);
1450 let mut r6 = r4.wrapping_add(r5);
1451 let mut r7 = ((r4 as i32) - (r5 as i32)) as u16;
1452 aw3[j] = r6;
1453 aw4[j] = r7;
1454 r4 = (r0 << 2).wrapping_add(r2) << 1;
1455 r5 = (r1 << 2).wrapping_add(r3);
1456 r6 = r4.wrapping_add(r5);
1457 r7 = ((r4 as i32) - (r5 as i32)) as u16;
1458 aw5[j] = r6;
1459 aw6[j] = r7;
1460 r4 = (r3 << 3).wrapping_add(r2 << 2).wrapping_add(r1 << 1).wrapping_add(r0);
1461 aw2[j] = r4;
1462 aw7[j] = r0;
1463 aw1[j] = r3;
1464 }
1465
1466 for j in 0..MULT_N_SB {
1467 let r0 = b0[j];
1468 let r1 = b1[j];
1469 let r2 = b2[j];
1470 let r3 = b3[j];
1471 let mut r4 = r0.wrapping_add(r2);
1472 let mut r5 = r1.wrapping_add(r3);
1473 let mut r6 = r4.wrapping_add(r5);
1474 let mut r7 = ((r4 as i32) - (r5 as i32)) as u16;
1475 bw3[j] = r6;
1476 bw4[j] = r7;
1477 r4 = (r0 << 2).wrapping_add(r2) << 1;
1478 r5 = (r1 << 2).wrapping_add(r3);
1479 r6 = r4.wrapping_add(r5);
1480 r7 = ((r4 as i32) - (r5 as i32)) as u16;
1481 bw5[j] = r6;
1482 bw6[j] = r7;
1483 r4 = (r3 << 3).wrapping_add(r2 << 2).wrapping_add(r1 << 1).wrapping_add(r0);
1484 bw2[j] = r4;
1485 bw7[j] = r0;
1486 bw1[j] = r3;
1487 }
1488
1489 // MULTIPLICATION
1490 let w1 = Self::karatsuba_simple(&aw1, &bw1);
1491 let w2 = Self::karatsuba_simple(&aw2, &bw2);
1492 let w3 = Self::karatsuba_simple(&aw3, &bw3);
1493 let w4 = Self::karatsuba_simple(&aw4, &bw4);
1494 let w5 = Self::karatsuba_simple(&aw5, &bw5);
1495 let w6 = Self::karatsuba_simple(&aw6, &bw6);
1496 let w7 = Self::karatsuba_simple(&aw7, &bw7);
1497
1498 // INTERPOLATION
1499 for i in 0..MULT_N_SB_RES {
1500 let r0 = w1[i] as i32;
1501 let mut r1 = w2[i] as i32;
1502 let mut r2 = w3[i] as i32;
1503 let mut r3 = w4[i] as i32;
1504 let mut r4 = w5[i] as i32;
1505 let mut r5 = w6[i] as i32;
1506 let r6 = w7[i] as i32;
1507
1508 r1 = r1 + r4;
1509 r1 &= 0xffff;
1510 r5 = r5 - r4;
1511 r5 &= 0xffff;
1512 r3 = (r3 - r2) >> 1;
1513 r3 &= 0xffff;
1514 r4 = r4 - r0;
1515 r4 &= 0xffff;
1516 r4 = r4 - (r6 << 6);
1517 r4 &= 0xffff;
1518 r4 = (r4 << 1) + r5;
1519 r4 &= 0xffff;
1520 r2 = r2 + r3;
1521 r2 &= 0xffff;
1522 r1 = r1 - (r2 << 6) - r2;
1523 r1 &= 0xffff;
1524 r2 = r2 - r6;
1525 r2 &= 0xffff;
1526 r2 = r2 - r0;
1527 r2 &= 0xffff;
1528 r1 = r1 + 45 * r2;
1529 r1 &= 0xffff;
1530 r4 = (r4 - (r2 << 3)).wrapping_mul(INV3) >> 3;
1531 r4 &= 0xffff;
1532 r5 = r5 + r1;
1533 r5 &= 0xffff;
1534 r1 = (r1 + (r3 << 4)).wrapping_mul(INV9) >> 1;
1535 r1 &= 0xffff;
1536 r3 = -(r3 + r1);
1537 r3 &= 0xffff;
1538 r5 = (30 * r1 - r5).wrapping_mul(INV15) >> 2;
1539 r5 &= 0xffff;
1540 r2 = r2 - r4;
1541 r2 &= 0xffff;
1542 r1 = r1 - r5;
1543 r1 &= 0xffff;
1544
1545 c[i] = c[i].wrapping_add(r6 as u16);
1546 c[i + 64] = c[i + 64].wrapping_add(r5 as u16);
1547 c[i + 128] = c[i + 128].wrapping_add(r4 as u16);
1548 c[i + 192] = c[i + 192].wrapping_add(r3 as u16);
1549 c[i + 256] = c[i + 256].wrapping_add(r2 as u16);
1550 c[i + 320] = c[i + 320].wrapping_add(r1 as u16);
1551 c[i + 384] = c[i + 384].wrapping_add(r0 as u16);
1552 }
1553 c
1554 }
1555
1556 /// Outlined in 8.3.7
1557 fn poly_mul_acc(
1558 a: &[u16; SABER_N],
1559 b: &[u16; SABER_N],
1560 res: &mut [u16; SABER_N],
1561 ) {
1562 let c = Self::toom_cook_4way(a, b);
1563
1564 for i in SABER_N..2*SABER_N {
1565 res[i - SABER_N] = (
1566 res[i - SABER_N].wrapping_add(c[i - SABER_N]) as i32 -
1567 c[i] as i32
1568 ) as u16;
1569 }
1570 }
1571
1572 /// Algorithm 13
1573 /// * `L` - The length of the polynomial vector (i.e. the rank [`Self::L`])
1574 fn matrix_vector_mul<
1575 const L: usize,
1576 >(
1577 a: &[[[u16; SABER_N]; L]; L],
1578 s: &[[u16; SABER_N]; L],
1579 res: &mut [[u16; SABER_N]; L],
1580 transpose: bool,
1581 ) {
1582 for i in 0..L {
1583 for j in 0..L {
1584 if transpose {
1585 Self::poly_mul_acc(&a[j][i], &s[j], &mut res[i]);
1586 } else {
1587 Self::poly_mul_acc(&a[i][j], &s[j], &mut res[i]);
1588 }
1589 }
1590 }
1591 }
1592
1593 /// Algorithm 14
1594 /// * `L` - The length of the polynomial vector (i.e. the rank [`Self::L`])
1595 fn inner_prod<
1596 const L: usize,
1597 >(
1598 b: &[[u16; SABER_N]; L],
1599 s: &[[u16; SABER_N]; L],
1600 res: &mut [u16; SABER_N],
1601 ) {
1602 for j in 0..L {
1603 Self::poly_mul_acc(&b[j], &s[j], res);
1604 }
1605 }
1606
1607 /// Algorithm 15
1608 /// * `L` - The length of the polynomial vector (i.e. the rank [`Self::L`])
1609 /// * `P` - The length of the byte string into bs2polvecq (i.e. [`Self::POLY_VEC_BYTES`])
1610 /// * `B` - The length of the initial byte string (i.e. [`Self::L * Self::POLY_VEC_BYTES`])
1611 fn gen_matrix<
1612 const L: usize,
1613 const P: usize,
1614 const B: usize,
1615 >(
1616 a: &mut [[[u16; SABER_N]; L]; L],
1617 seed: &[u8; SEED_BYTES],
1618 ) {
1619 let mut buf = [0_u8; B];
1620 let mut shake = Shake::v128();
1621 shake.update(&seed[..]);
1622 shake.finalize(&mut buf);
1623
1624 // `buf` divides into `L` contiguous `P`-byte polynomial blocks;
1625 // splitting into fixed-size chunks avoids a fallible
1626 // slice-to-array conversion.
1627 let (blocks, _rest) = buf.as_chunks::<P>();
1628 for i in 0..L {
1629 a[i] = Self::bs2polvecq::<
1630 SABER_N,
1631 L,
1632 POLY_BYTES,
1633 P,
1634 >(
1635 &blocks[i],
1636 );
1637 }
1638 }
1639
1640
1641 /// Centered Binomial Distribution
1642 fn cbd(&self, buf: &[u8]) -> [u16; SABER_N];
1643
1644 /// Support function for [`cbd`].
1645 fn load_little_endian(
1646 x: &[u8],
1647 ) -> u64
1648 {
1649 let mut r = x[0] as u64;
1650 for i in 1..x.len() {
1651 r |= (x[i] as u64) << (8 * i);
1652 }
1653 r
1654 }
1655
1656 /// Algorithm 16
1657 /// * `L` - The length of the polynomial vector (i.e. the rank [`Self::L`])
1658 /// * `PCB` - The length of the byte string into cbd (i.e. [`Self::POLY_COIN_BYTES`])
1659 /// * `L_PCB` - The length of the byte string into bs2polvecq (i.e. [`Self::L * Self::POLY_COIN_BYTES`])
1660 fn gen_secret<
1661 const L: usize,
1662 const PCB: usize,
1663 const L_PCB: usize,
1664 >(
1665 &self,
1666 s: &mut [[u16; SABER_N]; L],
1667 seed: &[u8; NOISE_SEED_BYTES],
1668 ) {
1669 let mut buf = [0_u8; L_PCB];
1670 let mut shake = Shake::v128();
1671 shake.update(&seed[..]);
1672 shake.finalize(&mut buf);
1673
1674 for i in 0..L {
1675 let k = i*PCB;
1676 s[i] = self.cbd(&buf[k..k+PCB]);
1677 }
1678 }
1679
1680}
1681
1682/// The public key used in both kex and kem.
1683#[derive(Clone, Copy)]
1684pub struct PublicKey<const LEN: usize> {
1685 seed: [u8; SEED_BYTES],
1686 key: [u8; LEN],
1687}
1688
1689// For zeroize
1690impl<const LEN: usize> Default for PublicKey<LEN> {
1691 fn default() -> Self {
1692 Self {
1693 seed: [0; SEED_BYTES],
1694 key: [0; LEN],
1695 }
1696 }
1697}
1698
1699impl<const LEN: usize> PublicKey<LEN> {
1700
1701 fn new(seed: [u8; SEED_BYTES], key: [u8; LEN]) -> Self {
1702 Self {
1703 seed: seed,
1704 key: key,
1705 }
1706 }
1707
1708 fn key(self) -> [u8; LEN] {
1709 self.key
1710 }
1711
1712 fn key_ref(&self) -> &[u8; LEN] {
1713 &self.key
1714 }
1715
1716 fn seed(self) -> [u8; SEED_BYTES] {
1717 self.seed
1718 }
1719
1720 fn seed_ref(&self) -> &[u8; SEED_BYTES] {
1721 &self.seed
1722 }
1723
1724 fn iter(&self) -> Chain<Iter<'_, u8>, Iter<'_, u8>> {
1725 self.key.iter().chain(self.seed.iter())
1726 }
1727
1728 pub fn to_bytes(&self) -> Vec<u8> {
1729 [&self.key[..], &self.seed[..]].concat()
1730 }
1731
1732 pub fn from_bytes(b: &[u8]) -> Outcome<Self> {
1733 let end: usize = LEN;
1734 let key = res!(
1735 TryInto::<&[u8; LEN]>::try_into(&b[..end]),
1736 Conversion, Bytes,
1737 );
1738 let seed = res!(
1739 TryInto::<&[u8; SEED_BYTES]>::try_into(&b[end..]),
1740 Conversion, Bytes,
1741 );
1742 Ok( PublicKey {
1743 seed: *seed,
1744 key: *key,
1745 })
1746 }
1747
1748 pub fn byte_len(&self) -> usize {
1749 SEED_BYTES + LEN
1750 }
1751}
1752
1753/// The key used in the key exchange mechanism (kex).
1754#[derive(Clone, Copy)]
1755pub struct SecretKeyCPA<const LEN: usize> {
1756 key: [u8; LEN],
1757}
1758
1759// For zeroize
1760impl<const LEN: usize> Default for SecretKeyCPA<LEN> {
1761 fn default() -> Self {
1762 Self {
1763 key: [0; LEN],
1764 }
1765 }
1766}
1767
1768impl<const LEN: usize> SecretKeyCPA<LEN> {
1769
1770 fn new(key: [u8; LEN]) -> Self {
1771 Self {
1772 key: key,
1773 }
1774 }
1775
1776 fn key(self) -> [u8; LEN] {
1777 self.key
1778 }
1779
1780 fn key_ref(&self) -> &[u8; LEN] {
1781 &self.key
1782 }
1783
1784 fn iter(&self) -> Iter<'_, u8> {
1785 self.key.iter()
1786 }
1787
1788 fn from_bytes(b: &[u8]) -> Outcome<Self> {
1789 let key = res!(
1790 TryInto::<&[u8; LEN]>::try_into(&b[..]),
1791 Conversion, Bytes,
1792 );
1793 Ok( SecretKeyCPA {
1794 key: *key,
1795 })
1796 }
1797
1798 fn byte_len(&self) -> usize {
1799 SEED_BYTES
1800 }
1801}
1802
1803/// The key used in the key encaspulation mechanism (kem).
1804#[derive(Clone, Copy, Default)]
1805pub struct SecretKeyCCA<
1806 const SK_LEN: usize,
1807 const PK_LEN: usize,
1808> {
1809 sk: SecretKeyCPA<SK_LEN>,
1810 pk: PublicKey<PK_LEN>,
1811 pk_hash:[u8; HASH_BYTES],
1812 rand: [u8; KEY_BYTES],
1813}
1814
1815impl<
1816 const SK_LEN: usize,
1817 const PK_LEN: usize,
1818>
1819 DefaultIsZeroes for SecretKeyCCA<SK_LEN, PK_LEN>
1820{}
1821
1822impl<
1823 const SK_LEN: usize,
1824 const PK_LEN: usize,
1825>
1826 SecretKeyCCA<SK_LEN, PK_LEN>
1827{
1828
1829 fn key(self) -> SecretKeyCPA<SK_LEN> {
1830 self.sk
1831 }
1832
1833 fn key_ref(&self) -> &SecretKeyCPA<SK_LEN> {
1834 &self.sk
1835 }
1836
1837 fn pk_hash_ref(&self) -> &[u8; HASH_BYTES] {
1838 &self.pk_hash
1839 }
1840
1841 fn rand_ref(&self) -> &[u8; KEY_BYTES] {
1842 &self.rand
1843 }
1844
1845 fn pk_ref(&self) -> &PublicKey<PK_LEN> {
1846 &self.pk
1847 }
1848
1849 fn iter(&self) ->
1850 Chain<
1851 Chain<
1852 Chain<
1853 Iter<'_, u8>,
1854 Chain<
1855 Iter<'_, u8>,
1856 Iter<'_, u8>,
1857 >,
1858 >,
1859 Iter<'_, u8>,
1860 >,
1861 Iter<'_, u8>,
1862 >
1863 {
1864 self.sk.iter()
1865 .chain(self.pk.iter())
1866 .chain(self.pk_hash.iter())
1867 .chain(self.rand.iter())
1868 }
1869
1870 pub fn to_bytes(&self) -> Vec<u8> {
1871 [
1872 &self.sk.key()[..],
1873 &self.pk.to_bytes(),
1874 &self.pk_hash[..],
1875 &self.rand[..],
1876 ].concat()
1877 }
1878
1879 pub fn from_bytes(b: &[u8]) -> Outcome<Self> {
1880 let mut end: usize = KEY_BYTES;
1881 let rand = res!(
1882 TryInto::<&[u8; KEY_BYTES]>::try_into(&b[..end]),
1883 Conversion, Bytes,
1884 );
1885 let mut start = end;
1886 end = start + HASH_BYTES;
1887 let hash_pk = res!(
1888 TryInto::<&[u8; HASH_BYTES]>::try_into(&b[start..end]),
1889 Conversion, Bytes,
1890 );
1891 start = end;
1892 end = start + PK_LEN + SEED_BYTES;
1893 let pk = res!(PublicKey::from_bytes(&b[start..end]));
1894 start = end;
1895 let sk = res!(SecretKeyCPA::from_bytes(&b[start..]));
1896 Ok( SecretKeyCCA {
1897 sk: sk,
1898 pk: pk,
1899 pk_hash:*hash_pk,
1900 rand: *rand,
1901 })
1902 }
1903
1904 pub fn byte_len(&self) -> usize {
1905 SK_LEN +
1906 self.pk.byte_len() +
1907 HASH_BYTES +
1908 KEY_BYTES
1909 }
1910}
1911
1912#[derive(Clone)]
1913pub struct CipherText<
1914 const SBK: usize,
1915 const PVCB: usize,
1916> {
1917 cm: [u8; SBK],
1918 ct: [u8; PVCB],
1919}
1920
1921impl<
1922 const SBK: usize,
1923 const PVCB: usize,
1924>
1925 CipherText<SBK, PVCB>
1926{
1927
1928 fn iter(&self) -> Chain<Iter<'_, u8>, Iter<'_, u8>> {
1929 self.ct.iter().chain(self.cm.iter())
1930 }
1931
1932 pub fn to_vec(&self) -> Vec<u8> {
1933 [&self.ct[..], &self.cm[..]].concat()
1934 }
1935
1936 pub fn to_bytes<const L: usize>(&self) -> [u8; L] {
1937 let mut result = [0u8; L];
1938 for i in 0..PVCB {
1939 result[i] = self.ct[i];
1940 }
1941 for i in 0..SBK {
1942 result[PVCB + i] = self.cm[i];
1943 }
1944 result
1945 }
1946
1947 pub fn from_bytes(b: &[u8]) -> Outcome<Self> {
1948 let end: usize = PVCB;
1949 let ct = res!(
1950 TryInto::<&[u8; PVCB]>::try_into(&b[..end]),
1951 Conversion, Bytes,
1952 );
1953 let cm = res!(
1954 TryInto::<&[u8; SBK]>::try_into(&b[end..]),
1955 Conversion, Bytes,
1956 );
1957 Ok( CipherText {
1958 cm: *cm,
1959 ct: *ct,
1960 })
1961 }
1962
1963 pub fn byte_len(&self) -> usize {
1964 SBK + PVCB
1965 }
1966}
1967
1968#[cfg(test)]
1969mod tests {
1970 use super::*;
1971 use std::{
1972 fs::OpenOptions,
1973 io::{
1974 BufWriter,
1975 Write,
1976 },
1977 };
1978
1979 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
1980
1981 #[test]
1982 fn test_polt2bs_lightsaber() {
1983 // For LightSaber, ET = 3, T = 8
1984 // Polynomial coefficients, 3 significant bits in every u16
1985 // msb lsb
1986 // ---------------+---------------+---------------+-..
1987 // ---+---+---+---+---+---+---+---+---+---+---+---+-..
1988 // 010101010101010101010101010101010101010101010101...
1989 // ^^^ ^^^ ^^^
1990 // +------------+ | |
1991 // | +-------------------------+ |
1992 // | | +--------------------------------------+
1993 // v v v v v v v v v v v v v v v v
1994 // 101101101101101101101101101101101101101101101101
1995 // ---+---+---+---+---+---+---+---+---+---+---+---+
1996 // -------+-------+-------+-------+-------+-------+
1997 // lsb msb note: flipped around for diagram
1998 // Significant bits of coefficients packed into byte string
1999 //
2000 // msb lsb
2001 // 01101101
2002 // 11011011
2003 // 10110110
2004 // 01101101
2005 // 11011011
2006 // 10110110
2007 const TEST_N: usize = 2*8;
2008 const TEST_ET: usize = 3;
2009 const TEST_SCALE_BYTES_KEM: usize = TEST_ET * TEST_N / 8;
2010 let poly = [0x5555_u16; TEST_N];
2011 let saber = LightSaber::default();
2012 let expected = [
2013 0b01101101_u8,
2014 0b11011011,
2015 0b10110110,
2016 0b01101101,
2017 0b11011011,
2018 0b10110110,
2019 ];
2020 let bytes = LightSaber::polt2bs::<TEST_N, TEST_SCALE_BYTES_KEM>(&poly, 0);
2021 assert_eq!(&bytes, &expected);
2022 }
2023
2024 #[test]
2025 fn test_polt2bs_saber() {
2026 // For LightSaber, ET = 4, T = 16
2027 // Polynomial coefficients, 4 significant bits in every u16
2028 // msb lsb
2029 // ---------------+---------------+---------------+-..
2030 // ---+---+---+---+---+---+---+---+---+---+---+---+-..
2031 // 010101010101010101010101010101010101010101010101...
2032 // ^^^^ ^^^^ ^^^^
2033 // +------------+ | |
2034 // | +------------------------+ |
2035 // | | +------------------------------------+
2036 // v v v v v v v v v v v v v v v v
2037 // 1010101010101010101010101010101010101010101010101010101010101010
2038 // ---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2039 // -------+-------+-------+-------+-------+-------+-------+-------+
2040 // lsb msb note: flipped around for diagram
2041 // Significant bits of coefficients packed into byte string
2042 //
2043 // msb lsb
2044 // 01010101 x8
2045 const TEST_N: usize = 2*8;
2046 const TEST_ET: usize = 4;
2047 const TEST_SCALE_BYTES_KEM: usize = TEST_ET * TEST_N / 8;
2048 let poly = [0x5555_u16; TEST_N];
2049 let saber = LightSaber::default();
2050 let expected = [0b01010101_u8; 8];
2051 let bytes = Saber::polt2bs::<TEST_N, TEST_SCALE_BYTES_KEM>(&poly, 0);
2052 assert_eq!(&bytes, &expected);
2053 }
2054
2055 #[test]
2056 fn test_polt2bs_firesaber() {
2057 // For FireSaber, ET = 6, T = 64
2058 // Polynomial coefficients, 6 significant bits in every u16
2059 // msb lsb
2060 // ---------------+---------------+---------------+-..
2061 // ---+---+---+---+---+---+---+---+---+---+---+---+-..
2062 // 010101010101010101010101010101010101010101010101...
2063 // ^^^^^^ ^^^^^^ ^^^^^^
2064 // +----------+ | |
2065 // | +--------------------+ |
2066 // | | +------------------------------+
2067 // vvvvvv v vvvvvv v ..
2068 // 101010101010101010101010..
2069 // ---+---+---+---+---+---+..
2070 // -------+-------+-------+..
2071 // lsb msb note: flipped around for diagram
2072 // Significant bits of coefficients packed into byte string
2073 //
2074 // msb lsb
2075 // 01010101 x12
2076 const TEST_N: usize = 2*8;
2077 const TEST_ET: usize = 6;
2078 const TEST_SCALE_BYTES_KEM: usize = TEST_ET * TEST_N / 8;
2079 let poly = [0x5555_u16; TEST_N];
2080 let saber = LightSaber::default();
2081 let expected = [0b01010101_u8; 12];
2082 let bytes = FireSaber::polt2bs::<TEST_N, TEST_SCALE_BYTES_KEM>(&poly, 0);
2083 assert_eq!(&bytes, &expected);
2084 }
2085
2086 #[test]
2087 fn test_polp2bs() {
2088 // Polynomial coefficients, 10 significant bits in every u16
2089 // msb lsb
2090 // ---------------+---------------+---------------+-..
2091 // ---+---+---+---+---+---+---+---+---+---+---+---+-..
2092 // 011010011010011001101001101001100110100110100110...
2093 // ^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^
2094 // +----------+ | |
2095 // | +------+ |
2096 // | | +--+
2097 // vvvvvvvvvv vvvvvvvvvv vvvvvvvvvv vvvvvvvvvv
2098 // 0110010110011001011001100101100110010110011001011001100101100110010110
2099 // ---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+..
2100 // ---1---+---2---+---3---+---4---+---5---+---6---+---7---+---8---+---9---+..
2101 // lsb msb note: flipped around for diagram
2102 // Significant bits of coefficients packed into byte string
2103 //
2104 // msb lsb lowest common multiple of 8, 10 is 5, so 5 byte cycle
2105 // 1 10100110
2106 // 2 10011001
2107 // 3 01100110
2108 // 4 10011010
2109 // 5 01101001
2110 // 6 ..
2111 const TEST_N: usize = 2*8;
2112 const TEST_EP: usize = 10;
2113 const TEST_POLY_COMPRESSED_BYTES: usize = TEST_EP * TEST_N / 8;
2114 let poly = [0b0110100110100110_u16; TEST_N];
2115 let expected_bytes = [
2116 0b10100110_u8, // 1
2117 0b10011001, // 2
2118 0b01100110, // 3
2119 0b10011010, // 4
2120 0b01101001, // 5
2121 0b10100110, // 6
2122 0b10011001, // 7
2123 0b01100110, // 8
2124 0b10011010, // 9
2125 0b01101001, // 10
2126 0b10100110, // 11
2127 0b10011001, // 12
2128 0b01100110, // 13
2129 0b10011010, // 14
2130 0b01101001, // 15
2131 0b10100110, // 16
2132 0b10011001, // 17
2133 0b01100110, // 18
2134 0b10011010, // 19
2135 0b01101001, // 20
2136 ];
2137 let mut bytes = [0; TEST_POLY_COMPRESSED_BYTES];
2138 Saber::polp2bs::<TEST_N>(&poly, &mut bytes, 0);
2139 assert_eq!(&bytes, &expected_bytes);
2140 // byte string -> poly coeffs
2141 // vvvvvv these should be zero, rather than original poly
2142 let expected_poly = [0b0000000110100110_u16; TEST_N];
2143 let mut data = [0_u16; TEST_N];
2144 Saber::bs2polp::<TEST_N>(&bytes, &mut data);
2145 assert_eq!(&data, &expected_poly);
2146 // vector of poly coeffs -> byte string
2147 const TEST_L: usize = 3;
2148 let poly = [poly; TEST_L];
2149 let expected: Vec<u8> = vec![expected_bytes.to_vec(); TEST_L]
2150 .into_iter()
2151 .flatten()
2152 .collect();
2153 let bytes = Saber::polvecp2bs::<
2154 TEST_N,
2155 TEST_L,
2156 TEST_POLY_COMPRESSED_BYTES,
2157 {TEST_L * TEST_POLY_COMPRESSED_BYTES},
2158 >(&poly);
2159 assert_eq!(&bytes.to_vec(), &expected);
2160 }
2161
2162 #[test]
2163 fn test_polq2bs() {
2164 // Polynomial coefficients, 13 significant bits in every u16
2165 // msb lsb
2166 // ---------------+---------------+---------------+-..
2167 // ---+---+---+---+---+---+---+---+---+---+---+---+-..
2168 // 011010011010011001101001101001100110100110100110...
2169 // ^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^
2170 // +----------+ | |
2171 // | ++ |
2172 // | | +--------+
2173 // vvvvvvvvvvvvv vvvvvvvvvvvvv vvvvvvvvvvvvv vvvvvvvvvvvvv
2174 // 01100101100100110010110010011001011001001100101100100110010110010011001011001001100101100100110010110010
2175 // ---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2176 // ---1---+---2---+---3---+---4---+---5---+---6---+---7---+---8---+---9---+--10---+--11---+--12---+--13---+
2177 // lsb msb note: flipped around for diagram
2178 // Significant bits of coefficients packed into byte string
2179 //
2180 // msb lsb lowest common multiple of 8, 13 is 104, so 13 byte cycle
2181 // 1 10100110
2182 // 2 11001001
2183 // 3 00110100
2184 // 4 10011001
2185 // 5 00100110
2186 // 6 11010011
2187 // 7 01100100
2188 // 8 10011010
2189 // 9 01001100
2190 // 10 10010011
2191 // 11 01101001
2192 // 12 00110010
2193 // 13 01001101
2194 // 14 ..
2195 const TEST_N: usize = 2*8;
2196 const TEST_EQ: usize = 13;
2197 const TEST_POLY_BYTES: usize = TEST_EQ * TEST_N / 8;
2198 // poly coeffs -> byte string
2199 let poly = [0b0110100110100110_u16; TEST_N];
2200 let expected_bytes = [
2201 0b10100110_u8, // 1
2202 0b11001001, // 2
2203 0b00110100, // 3
2204 0b10011001, // 4
2205 0b00100110, // 5
2206 0b11010011, // 6
2207 0b01100100, // 7
2208 0b10011010, // 8
2209 0b01001100, // 9
2210 0b10010011, // 10
2211 0b01101001, // 11
2212 0b00110010, // 12
2213 0b01001101, // 13
2214 0b10100110, // 14
2215 0b11001001, // 15
2216 0b00110100, // 16
2217 0b10011001, // 17
2218 0b00100110, // 18
2219 0b11010011, // 19
2220 0b01100100, // 20
2221 0b10011010, // 21
2222 0b01001100, // 22
2223 0b10010011, // 23
2224 0b01101001, // 24
2225 0b00110010, // 25
2226 0b01001101, // 26
2227 ];
2228 let mut bytes = [0_u8; TEST_POLY_BYTES];
2229 Saber::polq2bs::<TEST_N>(&poly, &mut bytes, 0);
2230 assert_eq!(&bytes, &expected_bytes);
2231 // byte string -> poly coeffs
2232 // vvv these should be zero, rather than original poly
2233 let expected_poly = [0b0000100110100110_u16; TEST_N];
2234 let mut data = [0_u16; TEST_N];
2235 Saber::bs2polq::<TEST_N>(&bytes, &mut data);
2236 assert_eq!(&data, &expected_poly);
2237 // vector of poly coeffs -> byte string
2238 const TEST_L: usize = 3;
2239 let poly = [poly; TEST_L];
2240 let expected: Vec<u8> = vec![expected_bytes.to_vec(); TEST_L]
2241 .into_iter()
2242 .flatten()
2243 .collect();
2244 let bytes = Saber::polvecq2bs::<
2245 TEST_N,
2246 TEST_L,
2247 TEST_POLY_BYTES,
2248 {TEST_L * TEST_POLY_BYTES},
2249 >(&poly);
2250 assert_eq!(&bytes.to_vec(), &expected);
2251 }
2252
2253 #[test]
2254 fn test_bs2polmsg_polmsg2bs() {
2255 const TEST_N: usize = 64;
2256 const TEST_KEY_BYTES: usize = 8;
2257 let msg_in = [
2258 0b01001101_u8,
2259 0b01010001,
2260 0b11110110,
2261 0b00001101,
2262 0b10000110,
2263 0b01010111,
2264 0b00100000,
2265 0b00111010,
2266 ];
2267 let poly = Saber::bs2polmsg::<TEST_N, TEST_KEY_BYTES>(&msg_in);
2268 let msg_out = Saber::polmsg2bs::<TEST_N, TEST_KEY_BYTES>(&poly);
2269 assert_eq!(&msg_in, &msg_out);
2270 }
2271
2272 #[derive(Default)]
2273 struct SaberC {
2274 client_secret: [u8; KEY_BYTES],
2275 server_secret: [u8; KEY_BYTES],
2276 entropy_input: Vec<u8>,
2277 pk: Vec<u8>,
2278 sk: Vec<u8>,
2279 ct: Vec<u8>,
2280 }
2281
2282 fn call_c<
2283 const PK: usize,
2284 const SK: usize,
2285 const CT: usize,
2286 >(
2287 mut c: &mut SaberC
2288 )
2289 {
2290 let mut pk = [0_u8; PK];
2291 let mut sk = [0_u8; SK];
2292 let mut ct = [0_u8; CT];
2293 unsafe {
2294 randombytes_init(
2295 c.entropy_input.as_mut_ptr(),
2296 std::ptr::null_mut(),
2297 256,
2298 );
2299 crypto_kem_keypair(
2300 pk.as_mut_ptr(),
2301 sk.as_mut_ptr(),
2302 );
2303 crypto_kem_enc(
2304 ct.as_mut_ptr(),
2305 c.client_secret.as_mut_ptr(),
2306 pk.as_ptr(),
2307 );
2308 crypto_kem_dec(
2309 c.server_secret.as_mut_ptr(),
2310 ct.as_ptr(),
2311 sk.as_ptr(),
2312 );
2313 }
2314 c.pk = pk.to_vec();
2315 c.sk = sk.to_vec();
2316 c.ct = ct.to_vec();
2317 }
2318
2319 #[test]
2320 fn test_validate_kem() -> Outcome<()> {
2321
2322 let which = env!("SABER_SCHEME");
2323
2324 let mut c = SaberC::default();
2325
2326 for i in 0..48_usize {
2327 c.entropy_input.push(i as u8);
2328 }
2329
2330 match which {
2331 "LIGHTSABER" => {
2332 call_c::<
2333 {LightSaber::PUBLIC_KEY_BYTES},
2334 {LightSaber::SECRET_KEY_BYTES},
2335 {LightSaber::CIPHERTEXT_BYTES},
2336 >(&mut c);
2337 },
2338 "SABER" => {
2339 call_c::<
2340 {Saber::PUBLIC_KEY_BYTES},
2341 {Saber::SECRET_KEY_BYTES},
2342 {Saber::CIPHERTEXT_BYTES},
2343 >(&mut c);
2344 },
2345 "FIRESABER" => {
2346 call_c::<
2347 {FireSaber::PUBLIC_KEY_BYTES},
2348 {FireSaber::SECRET_KEY_BYTES},
2349 {FireSaber::CIPHERTEXT_BYTES},
2350 >(&mut c);
2351 },
2352 _ => unimplemented!(),
2353 }
2354
2355 #[cfg(SABER_SCHEME = "LIGHTSABER")]
2356 let scheme = LightSaber;
2357 #[cfg(SABER_SCHEME = "LIGHTSABER")]
2358 const CT_LEN: usize = LightSaber::CIPHERTEXT_BYTES;
2359
2360 #[cfg(SABER_SCHEME = "SABER")]
2361 let scheme = Saber;
2362 #[cfg(SABER_SCHEME = "SABER")]
2363 const CT_LEN: usize = Saber::CIPHERTEXT_BYTES;
2364
2365 #[cfg(SABER_SCHEME = "FIRESABER")]
2366 let scheme = FireSaber;
2367 #[cfg(SABER_SCHEME = "FIRESABER")]
2368 const CT_LEN: usize = FireSaber::CIPHERTEXT_BYTES;
2369
2370 msg!("{} parameters:", scheme);
2371 msg!("PUBLIC_KEY_BYTES: {}", scheme.pk_len());
2372 msg!("SECRET_KEY_BYTES: {}", scheme.sk_len());
2373 msg!("CIPHERTEXT_BYTES: {}", scheme.ct_len());
2374
2375 let seed_a = [
2376 0x06, 0x15, 0x50, 0x23, 0x4d, 0x15, 0x8c, 0x5e,
2377 0xc9, 0x55, 0x95, 0xfe, 0x04, 0xef, 0x7a, 0x25,
2378 0x76, 0x7f, 0x2e, 0x24, 0xcc, 0x2b, 0xc4, 0x79,
2379 0xd0, 0x9d, 0x86, 0xdc, 0x9a, 0xbc, 0xfd, 0xe7,
2380 ];
2381 let seed_s = [
2382 0x1a, 0x9f, 0xbc, 0xbc, 0x8d, 0xa3, 0x6d, 0xff,
2383 0x2a, 0xbe, 0x20, 0x32, 0x96, 0x17, 0x0f, 0xdb,
2384 0x97, 0xc3, 0x29, 0x7f, 0x67, 0xfc, 0xb6, 0x79,
2385 0xac, 0x71, 0x9c, 0x9f, 0xd0, 0x02, 0x53, 0xb0,
2386 ];
2387 let rand = [
2388 0xb2, 0xf0, 0x04, 0xf5, 0x43, 0x5f, 0x10, 0xc4,
2389 0xcd, 0x45, 0x11, 0x48, 0x44, 0x7a, 0xfd, 0x9b,
2390 0x99, 0xb2, 0x09, 0x77, 0x0d, 0xe0, 0xd0, 0x3a,
2391 0xcd, 0xb7, 0xbc, 0x6b, 0xe5, 0x71, 0x68, 0x8c,
2392 ];
2393 let mut enc_seed = [
2394 0x78, 0x97, 0x71, 0x80, 0x42, 0xad, 0x01, 0x0b,
2395 0xc9, 0x8b, 0xe9, 0x5d, 0x13, 0xdd, 0xde, 0xf0,
2396 0x65, 0x33, 0xab, 0x95, 0x42, 0x6f, 0xaf, 0xc7,
2397 0x49, 0x76, 0xcd, 0x99, 0xad, 0xb7, 0x45, 0x62,
2398 ];
2399
2400 let (pk, sk) = scheme.kem_keygen_test(seed_a, seed_s, rand);
2401
2402 let file = res!(OpenOptions::new()
2403 .read(false)
2404 .write(true)
2405 .create(true)
2406 .append(false)
2407 .open(format!("validation_output_for_{}.txt", which)));
2408 let mut fb = BufWriter::new(file);
2409
2410 writeln!(&mut fb, "Rust secret key: length {}", sk.byte_len());
2411 for line in dump!(" {:02x}", sk.iter(), 16) {
2412 writeln!(&mut fb, "{}", line);
2413 }
2414 writeln!(&mut fb, "C secret key: length {}", c.sk.len());
2415 for line in dump!(" {:02x}", &c.sk, 16) {
2416 writeln!(&mut fb, "{}", line);
2417 }
2418 writeln!(&mut fb, "Rust public key: length {}", pk.byte_len());
2419 for line in dump!(" {:02x}", pk.iter(), 16) {
2420 writeln!(&mut fb, "{}", line);
2421 }
2422 writeln!(&mut fb, "C public key: length {}", c.pk.len());
2423 for line in dump!(" {:02x}", &c.pk, 16) {
2424 writeln!(&mut fb, "{}", line);
2425 }
2426
2427 assert_eq!(pk.byte_len(), c.pk.len());
2428 assert_eq!(sk.byte_len(), c.sk.len());
2429
2430 for (i, pki) in pk.iter().enumerate() {
2431 assert_eq!(pki, &c.pk[i], "failed at i = {}", i);
2432 }
2433
2434 for (i, ski) in sk.iter().enumerate() {
2435 assert_eq!(ski, &c.sk[i], "failed at i = {}", i);
2436 }
2437
2438 let (client_secret, ciphertext) = scheme.kem_encap_test(&pk, enc_seed);
2439 writeln!(&mut fb, "Rust client secret: length {}", client_secret.len());
2440 for line in dump!(" {:02x}", client_secret.iter(), 16) {
2441 writeln!(&mut fb, "{}", line);
2442 }
2443 writeln!(&mut fb, "C client secret: length {}", c.client_secret.len());
2444 for line in dump!(" {:02x}", &c.client_secret, 16) {
2445 writeln!(&mut fb, "{}", line);
2446 }
2447 writeln!(&mut fb, "Rust ciphertext: length {}", ciphertext.byte_len());
2448 for line in dump!(" {:02x}", ciphertext.iter(), 16) {
2449 writeln!(&mut fb, "{}", line);
2450 }
2451 writeln!(&mut fb, "C ciphertext: length {}", c.ct.len());
2452 for line in dump!(" {:02x}", &c.ct, 16) {
2453 writeln!(&mut fb, "{}", line);
2454 }
2455
2456 let server_secret = res!(scheme.kem_decap(&ciphertext.to_bytes::<{CT_LEN}>(), &sk));
2457 writeln!(&mut fb, "Rust server secret: length {}", server_secret.len());
2458 for line in dump!(" {:02x}", server_secret.iter(), 16) {
2459 writeln!(&mut fb, "{}", line);
2460 }
2461 writeln!(&mut fb, "C server secret: length {}", c.server_secret.len());
2462 for line in dump!(" {:02x}", &c.server_secret, 16) {
2463 writeln!(&mut fb, "{}", line);
2464 }
2465
2466 for i in 0..client_secret.len() {
2467 assert_eq!(client_secret[i], server_secret[i], "failed at i = {}", i);
2468 }
2469
2470 Ok(())
2471 }
2472
2473 #[test]
2474 fn test_lightsaber_kem() -> Outcome<()> {
2475
2476 let scheme = LightSaber;
2477
2478 msg!("{} parameters:", scheme);
2479 msg!("PUBLIC_KEY_BYTES: {}", scheme.pk_len());
2480 msg!("SECRET_KEY_BYTES: {}", scheme.sk_len());
2481 msg!("CIPHERTEXT_BYTES: {}", scheme.ct_len());
2482
2483 for _ in 0..1000 {
2484 let (pk, sk) = scheme.kem_keygen();
2485 let (client_secret, ciphertext) = scheme.kem_encap(&pk);
2486 let server_secret = res!(scheme.kem_decap(
2487 &ciphertext.to_bytes::<{LightSaber::CIPHERTEXT_BYTES}>(),
2488 &sk,
2489 ));
2490 for i in 0..client_secret.len() {
2491 assert_eq!(client_secret[i], server_secret[i], "failed at i = {}", i);
2492 }
2493 }
2494
2495 Ok(())
2496 }
2497
2498 #[test]
2499 fn test_saber_kem() -> Outcome<()> {
2500
2501 let scheme = Saber;
2502
2503 msg!("{} parameters:", scheme);
2504 msg!("PUBLIC_KEY_BYTES: {}", scheme.pk_len());
2505 msg!("SECRET_KEY_BYTES: {}", scheme.sk_len());
2506 msg!("CIPHERTEXT_BYTES: {}", scheme.ct_len());
2507
2508 for _ in 0..1000 {
2509 let (pk, sk) = scheme.kem_keygen();
2510 let (client_secret, ciphertext) = scheme.kem_encap(&pk);
2511 let server_secret = res!(scheme.kem_decap(
2512 &ciphertext.to_bytes::<{Saber::CIPHERTEXT_BYTES}>(),
2513 &sk,
2514 ));
2515 for i in 0..client_secret.len() {
2516 assert_eq!(client_secret[i], server_secret[i], "failed at i = {}", i);
2517 }
2518 }
2519
2520 Ok(())
2521 }
2522
2523 #[test]
2524 fn test_firesaber_kem() -> Outcome<()> {
2525
2526 let scheme = FireSaber;
2527
2528 msg!("{} parameters:", scheme);
2529 msg!("PUBLIC_KEY_BYTES: {}", scheme.pk_len());
2530 msg!("SECRET_KEY_BYTES: {}", scheme.sk_len());
2531 msg!("CIPHERTEXT_BYTES: {}", scheme.ct_len());
2532
2533 for _ in 0..1000 {
2534 let (pk, sk) = scheme.kem_keygen();
2535 let (client_secret, ciphertext) = scheme.kem_encap(&pk);
2536 let server_secret = res!(scheme.kem_decap(
2537 &ciphertext.to_bytes::<{FireSaber::CIPHERTEXT_BYTES}>(),
2538 &sk,
2539 ));
2540 for i in 0..client_secret.len() {
2541 assert_eq!(client_secret[i], server_secret[i], "failed at i = {}", i);
2542 }
2543 }
2544
2545 Ok(())
2546 }
2547}