diff --git a/.gitignore b/.gitignore index 070d67f..bd4f46d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ Cargo.lock *.swp + +# Proptest +proptest-regressions diff --git a/Cargo.toml b/Cargo.toml index 72c09ea..d9a8bb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,11 +19,15 @@ byteorder = "1.4.3" # clap = { version = "4.3.12", features = ["cargo"] } more-asserts = "0.3.1" num_enum = { version = "0.7.1", default-features = false } +rand_core = { version = "0.6.4", default-features = false } sha3 = "0.10.8" tinyvec = "1.6.0" +zeroize = { version = "1.7.0", default-features = false } [dev-dependencies] rand = "0.8.5" +proptest = "1.4.0" + # [workspace] # members = ["src/kyber"] diff --git a/src/field_operations.rs b/src/field_operations.rs index c0bb897..12f0156 100644 --- a/src/field_operations.rs +++ b/src/field_operations.rs @@ -1,10 +1,10 @@ -use more_asserts::assert_ge; - use crate::params::Q; // given -2^15 q <= x < 2^15 q, returns -q < y < q with y = x 2^-16 mod q // Example: -// let x = montgomery_reduce(y); +// ``` +// let x = montgomery_reduce(5); //TODO: Tris broke this to remind you to make doctests! +// ``` #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] pub fn montgomery_reduce(x: i32) -> i16 { const QPRIME: i32 = 62209; @@ -50,14 +50,13 @@ pub fn barrett_reduce(x: i16) -> i16 { // Example: // let x = conditional_sub_q(y); #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] -pub fn conditional_sub_q(x: i16) -> i16 { +pub const fn conditional_sub_q(x: i16) -> i16 { const Q_16: i16 = Q as i16; - assert_ge!( - x, - -29439, - "x must be >= to -29439 when applying conditional subtract q" - ); - let mut result = x - Q_16; - result += (result >> 15) & Q_16; - result + if x < Q_16 { + x + } else { + let mut result = x - Q_16; + result += (result >> 15) & Q_16; + result + } } diff --git a/src/indcpa.rs b/src/indcpa.rs index 5567e90..12c9d8a 100644 --- a/src/indcpa.rs +++ b/src/indcpa.rs @@ -2,7 +2,7 @@ use core::num::TryFromIntError; use crate::{ matrix::{MatOperations, New}, - params::{GetSecLevel, POLYBYTES}, + params::{GetSecLevel, POLYBYTES, SYMBYTES}, polynomials::Poly, vectors::{LinkSecLevel, PolyVecOperations}, }; @@ -15,7 +15,7 @@ pub struct PrivateKey { #[derive(Default, PartialEq, Debug, Eq)] pub struct PublicKey> { - pub rho: [u8; 32], + pub rho: [u8; SYMBYTES], pub noise: PV, pub a_t: M, } @@ -55,7 +55,7 @@ where M: MatOperations + GetSecLevel + LinkSecLevel + New + IntoIterator + Copy, { let mut pub_key = PublicKey { - rho: [0u8; 32], + rho: [0u8; SYMBYTES], noise: PV::new_filled(), a_t: M::new(), }; @@ -63,7 +63,7 @@ where secret: PV::new_filled(), }; - let mut expanded_seed = [0u8; 64]; + let mut expanded_seed = [0u8; 2 * SYMBYTES]; let mut hash = Sha3_512::new(); hash.update(seed); @@ -104,16 +104,19 @@ pub fn encrypt( seed: &[u8], // output_buf: &'a mut [u8], output_buf: &mut [u8], -// ) -> Result<&'a [u8], TryFromIntError> + // ) -> Result<&'a [u8], TryFromIntError> ) -> Result<(), TryFromIntError> where PV: PolyVecOperations + GetSecLevel + Default + IntoIterator + Copy, M: MatOperations + GetSecLevel + LinkSecLevel + New + IntoIterator + Copy, { + let mut m = Poly::new(); + m.read_msg(plaintext)?; + let mut rh = PV::new_filled(); rh.derive_noise(seed, 0, PV::sec_level().eta_1()); rh.ntt(); - rh.barrett_reduce(); + // rh.barrett_reduce(); let k_value: u8 = PV::sec_level().k().into(); let mut error_1 = PV::new_filled(); @@ -125,27 +128,25 @@ where for (mut poly, vec) in u.into_iter().zip(pub_key.a_t) { poly.inner_product_pointwise(vec, rh); } - u.barrett_reduce(); u.inv_ntt(); - u.add(error_1); + u.barrett_reduce(); + let mut v = Poly::new(); v.inner_product_pointwise(pub_key.noise, rh); - v.barrett_reduce(); + // v.barrett_reduce(); v.inv_ntt(); - let mut m = Poly::new(); - m.read_msg(plaintext)?; - v.add(&m); v.add(&error_2); - u.normalise(); - v.normalise(); + v.barrett_reduce(); + + // u.normalise(); + // v.normalise(); let poly_vec_compressed_bytes: usize = PV::sec_level().poly_vec_compressed_bytes(); - let poly_compressed_bytes: usize = PV::sec_level().poly_compressed_bytes(); - u.compress(&mut output_buf[..poly_vec_compressed_bytes])?; + u.compress(output_buf)?; v.compress( &mut output_buf[poly_vec_compressed_bytes..], &PV::sec_level(), @@ -160,7 +161,7 @@ pub fn decrypt( ciphertext: &[u8], // output_buf: &'a mut [u8], output_buf: &mut [u8], -// ) -> Result<&'a [u8], TryFromIntError> + // ) -> Result<&'a [u8], TryFromIntError> ) -> Result<(), TryFromIntError> where PV: PolyVecOperations + GetSecLevel + Default + IntoIterator + Copy, diff --git a/src/lib.rs b/src/lib.rs index 391fa21..d2e5b89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,11 +37,11 @@ mod vectors; mod tests { mod buffer; mod field_operations; + mod indcpa; mod matrix; mod ntt; mod params; mod polynomials; mod sample; mod vectors; - mod indcpa; } diff --git a/src/ntt.rs b/src/ntt.rs index 776bc1e..3d88322 100644 --- a/src/ntt.rs +++ b/src/ntt.rs @@ -89,8 +89,8 @@ impl Poly { l <<= 1; } - for j in 0..N { - self.coeffs[j] = montgomery_reduce(1441 * i32::from(self.coeffs[j])); + for coeff in &mut self.coeffs { + *coeff = montgomery_reduce(1441 * i32::from(*coeff)); } } } diff --git a/src/polynomials.rs b/src/polynomials.rs index 7fe85b7..4d32e58 100644 --- a/src/polynomials.rs +++ b/src/polynomials.rs @@ -1,10 +1,313 @@ use crate::{ field_operations::{barrett_reduce, conditional_sub_q, mont_form, montgomery_reduce}, ntt::ZETAS, - params::{SecurityLevel, N, Q}, + params::{SecurityLevel, N, Q, SYMBYTES}, }; use core::num::TryFromIntError; +struct StatefulPoly { + pub(crate) coeffs: [i16; N], + state: S, +} + +struct Normalised; +struct Unnormalised; + +trait State {} +impl State for Normalised {} +impl State for Unnormalised {} + +impl Default for StatefulPoly { + fn default() -> Self { + Self { + coeffs: [0; N], + state: Unnormalised, + } + } +} + +impl StatefulPoly { + // const function equivelent of default (default is needed for ArrayVec) + // Example: + // let poly = Poly::new(); + const fn new() -> StatefulPoly { + StatefulPoly { + coeffs: [0; N], + state: Unnormalised, + } + } + + const fn from(array: &[i16; N]) -> StatefulPoly { + StatefulPoly { + coeffs: *array, + state: Unnormalised, + } + } + + // Sets self to self + x + // Example: + // poly1.add(&poly2); + fn add(&mut self, x: &Self) { + for i in 0..N { + self.coeffs[i] += x.coeffs[i]; + } + // // self.state = Unnormalised + } + + // Sets self to self - x + // Example: + // poly1.sub(&poly2); + pub(crate) fn sub(&mut self, x: &Self) { + for i in 0..N { + self.coeffs[i] -= x.coeffs[i]; + } + // // self.state = Unnormalised; + } + + // Barrett reduces all coefficients of given polynomial + // Example: + // poly.barrett_reduce(); + pub(crate) fn barrett_reduce(&mut self) { + for coeff in &mut self.coeffs { + *coeff = barrett_reduce(*coeff); + } + // // self.state = Unnormalised; + } + + // Converts all coefficients of the given polynomial to Mongomery form + // Example: + // poly.mont_form(); + pub(crate) fn mont_form(&mut self) { + for coeff in &mut self.coeffs { + *coeff = mont_form(*coeff); + } + // // self.state = Unnormalised; + } + + // Unpacks a buffer of bytes into a polynomial + // poly will NOT be normalised, but 0 <= coeffs < 4096 + // Example: + // poly.unpack(buf); + pub(crate) fn unpack(&mut self, buf: &[u8]) { + for i in 0..N / 2 { + self.coeffs[2 * i] = i16::from(buf[3 * i]) | ((i16::from(buf[3 * i + 1]) << 8) & 0xfff); + self.coeffs[2 * i + 1] = + i16::from(buf[3 * i + 1] >> 4) | ((i16::from(buf[3 * i + 2]) << 4) & 0xfff); + } + // self.state = Unnormalised; + } + + // Converts a message buffer into a polynomial + // msg should be of length SYMBYTES (32) + // poly will not be normalised + // Example: + // poly.read_msg(msg_buf); + pub(crate) fn read_msg(&mut self, msg: &[u8]) -> Result<(), TryFromIntError> { + for i in 0..SYMBYTES { + for j in 0..8 { + let mask = ((i16::from(msg[i]) >> j) & 1).wrapping_neg(); + self.coeffs[8 * i + j] = mask & i16::try_from((Q + 1) / 2)?; + } + } + // self.state = Unnormalised; + Ok(()) + } + + // Decompresses buffer into a polynomial + // is dependent on the security level + // buf should be of length poly_compressed_bytes + // output poly is normalised + // Example: + // poly.decompress(buf, k); + pub(crate) fn decompress( + &mut self, + buf: &[u8], + sec_level: &SecurityLevel, + ) -> Result<(), TryFromIntError> { + let mut k = 0usize; + + match sec_level { + SecurityLevel::FiveOneTwo { .. } | SecurityLevel::SevenSixEight { .. } => { + for (i, &byte) in buf.iter().take(N / 2).enumerate() { + self.coeffs[2 * i] = i16::try_from((usize::from(byte & 15) * Q + 8) >> 4)?; + self.coeffs[2 * i + 1] = i16::try_from((usize::from(byte >> 4) * Q + 8) >> 4)?; + } + // self.state = Normalised; + Ok(()) + } + SecurityLevel::TenTwoFour { .. } => { + let mut t = [0u8; 8]; + for i in 0..N / 8 { + t[0] = buf[k]; + t[1] = (buf[k] >> 5) | (buf[k + 1] << 3); + t[2] = buf[k + 1] >> 2; + t[3] = (buf[k + 1] >> 7) | (buf[k + 2] << 1); + t[4] = (buf[k + 2] >> 4) | (buf[k + 3] << 4); + t[5] = buf[k + 3] >> 1; + t[6] = (buf[k + 3] >> 6) | (buf[k + 4] << 2); + t[7] = buf[k + 4] >> 3; + k += 5; + + for (j, t_elem) in t.iter().enumerate() { + self.coeffs[8 * i + j] = i16::try_from( + ((u32::from(*t_elem) & 31) * u32::try_from(Q)? + 16) >> 5, + )?; + } + } + // self.state = Normalised; + Ok(()) + } + } + } +} + +impl StatefulPoly { + // Normalise coefficients of given polynomial + // Example: + // poly.normalise(); + fn normalise(&mut self) { + for coeff in &mut self.coeffs { + *coeff = conditional_sub_q(barrett_reduce(*coeff)); + } + // self.state = Normalised; + } +} + +impl StatefulPoly { + // Pointwise multiplication of two polynomials, + // assumes inputs are of montgomery form. + // Example: + // poly1.pointwise_mul(&poly2); + pub(crate) fn pointwise_mul(&mut self, x: &Self) { + for ((chunk, x_chunk), &zeta) in self + .coeffs + .chunks_mut(4) + .zip(x.coeffs.chunks(4)) + .zip(ZETAS.iter().skip(64)) + { + let mut temp = [0i16; 4]; + + for (i, coeff) in temp.iter_mut().enumerate() { + if i % 2 == 0 { + let sign: i16 = if i == 2 { -1 } else { 1 }; + *coeff = montgomery_reduce(i32::from(chunk[i + 1]) * i32::from(x_chunk[i + 1])); + *coeff = sign * montgomery_reduce(i32::from(*coeff) * i32::from(zeta)); + *coeff += montgomery_reduce(i32::from(chunk[i]) * i32::from(x_chunk[i])); + } else { + *coeff = montgomery_reduce(i32::from(chunk[i - 1]) * i32::from(x_chunk[i])); + *coeff += montgomery_reduce(i32::from(chunk[i]) * i32::from(x_chunk[i - 1])); + } + } + chunk.copy_from_slice(&temp); + } + // self.state = Unnormalised; + } + + // Packs given poly into a 384-byte (POLYBYTES size) buffer + // must be normalised + // Example: + // poly.pack(buf); + #[allow( + clippy::cast_possible_truncation, + clippy::cast_sign_loss, + clippy::cast_possible_wrap + )] + pub(crate) fn pack(&self, buf: &mut [u8]) { + for i in 0..N / 2 { + let mut t0 = self.coeffs[2 * i]; + t0 += (t0 >> 15) & Q as i16; + let mut t1 = self.coeffs[2 * i + 1]; + t1 += (t1 >> 15) & Q as i16; + + buf[3 * i] = t0 as u8; + buf[3 * i + 1] = ((t0 >> 8) | (t1 << 4)) as u8; + buf[3 * i + 2] = (t1 >> 4) as u8; + } + } + + // Convert a given polynomial into a SYMBYTES (32-byte) message + // poly should be normalised + // Example: + // poly.write_msg(msg_buf); + pub(crate) fn write_msg(&self, buf: &mut [u8]) -> Result<(), TryFromIntError> { + #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] + let q_16 = i16::try_from(Q)?; + for i in 0..N / 8 { + buf[i] = 0; + for j in 0..8 { + let mut x = self.coeffs[8 * i + j]; + x += (x >> 15) & q_16; + x = (((x << 1) + q_16 / 2) / q_16) & 1; + buf[i] |= u8::try_from(x << j)?; + } + } + Ok(()) + } + + // Compress polynomial to a buffer + // buf must have space for poly_compressed_bytes + // poly should be normalised + // Example: + // self.compress(buf); + pub(crate) fn compress( + &self, + buf: &mut [u8], + sec_level: &SecurityLevel, + ) -> Result<(), TryFromIntError> { + let mut k = 0usize; + let mut t = [0u8; 8]; + + match sec_level { + SecurityLevel::FiveOneTwo { .. } | SecurityLevel::SevenSixEight { .. } => { + for i in 0..N / 8 { + for j in 0..8 { + let mut u = self.coeffs[8 * i + j]; + u += (u >> 15) & i16::try_from(Q)?; + t[j] = u8::try_from( + ((((u16::try_from(u)?) << 4) + u16::try_from(Q)? / 2) + / u16::try_from(Q)?) + & 15, + )?; + } + + buf[k..k + 4].copy_from_slice(&[ + t[0] | (t[1] << 4), + t[2] | (t[3] << 4), + t[4] | (t[5] << 4), + t[6] | (t[7] << 4), + ]); + k += 4; + } + Ok(()) + } + SecurityLevel::TenTwoFour { .. } => { + for i in 0..N / 8 { + for j in 0..8 { + let mut u = self.coeffs[8 * i + j]; + u += (u >> 15) & i16::try_from(Q)?; + t[j] = u8::try_from( + ((((u32::try_from(u)?) << 5) + u32::try_from(Q)? / 2) + / u32::try_from(Q)?) + & 31, + )?; + } + + buf[k..k + 5].copy_from_slice(&[ + t[0] | (t[1] << 5), + (t[1] >> 3) | (t[2] << 2) | (t[3] << 7), + (t[3] >> 1) | (t[4] << 4), + (t[4] >> 4) | (t[5] << 1) | (t[6] << 6), + (t[6] >> 2) | (t[7] << 3), + ]); + k += 5; + } + Ok(()) + } + } + } +} + + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Poly { pub(crate) coeffs: [i16; N], @@ -24,6 +327,10 @@ impl Poly { Self { coeffs: [0; N] } } + pub(crate) const fn from(array: &[i16; N]) -> Self { + Self { coeffs: *array } + } + // Sets self to self + x // Example: // poly1.add(&poly2); @@ -53,7 +360,7 @@ impl Poly { // Barrett reduces all coefficients of given polynomial // Example: - // poly.reduce(); + // poly.barrett_reduce(); pub(crate) fn barrett_reduce(&mut self) { for coeff in &mut self.coeffs { *coeff = barrett_reduce(*coeff); @@ -74,40 +381,38 @@ impl Poly { // Example: // poly1.pointwise_mul(&poly2); pub(crate) fn pointwise_mul(&mut self, x: &Self) { - let mut j: usize = 64; + for ((chunk, x_chunk), &zeta) in self + .coeffs + .chunks_mut(4) + .zip(x.coeffs.chunks(4)) + .zip(ZETAS.iter().skip(64)) + { + let mut temp = [0i16; 4]; - for i in (0..N).step_by(4) { - let zeta = i32::from(ZETAS[j]); - j += 1; - - let mut p0 = - montgomery_reduce(i32::from(self.coeffs[i + 1]) * i32::from(x.coeffs[i + 1])); - p0 = montgomery_reduce(i32::from(p0) * zeta); - p0 += montgomery_reduce(i32::from(self.coeffs[i]) * i32::from(x.coeffs[i])); - - let mut p1 = montgomery_reduce(i32::from(self.coeffs[i]) * i32::from(x.coeffs[i + 1])); - p1 += montgomery_reduce(i32::from(self.coeffs[i + 1]) * i32::from(x.coeffs[i])); - - let mut p2 = - montgomery_reduce(i32::from(self.coeffs[i + 3]) * i32::from(x.coeffs[i + 3])); - p2 = -montgomery_reduce(i32::from(p2) * zeta); - p2 += montgomery_reduce(i32::from(self.coeffs[i + 2]) * i32::from(x.coeffs[i + 2])); - - let mut p3 = - montgomery_reduce(i32::from(self.coeffs[i + 2]) * i32::from(x.coeffs[i + 3])); - p3 += montgomery_reduce(i32::from(self.coeffs[i + 3]) * i32::from(x.coeffs[i + 2])); - - self.coeffs[i] = p0; - self.coeffs[i + 1] = p1; - self.coeffs[i + 2] = p2; - self.coeffs[i + 3] = p3; + for (i, coeff) in temp.iter_mut().enumerate() { + if i % 2 == 0 { + let sign: i16 = if i == 2 { -1 } else { 1 }; + *coeff = montgomery_reduce(i32::from(chunk[i + 1]) * i32::from(x_chunk[i + 1])); + *coeff = sign * montgomery_reduce(i32::from(*coeff) * i32::from(zeta)); + *coeff += montgomery_reduce(i32::from(chunk[i]) * i32::from(x_chunk[i])); + } else { + *coeff = montgomery_reduce(i32::from(chunk[i - 1]) * i32::from(x_chunk[i])); + *coeff += montgomery_reduce(i32::from(chunk[i]) * i32::from(x_chunk[i - 1])); + } + } + chunk.copy_from_slice(&temp); } } // Packs given poly into a 384-byte (POLYBYTES size) buffer + // must be normalised // Example: // poly.pack(buf); - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_possible_wrap)] + #[allow( + clippy::cast_possible_truncation, + clippy::cast_sign_loss, + clippy::cast_possible_wrap + )] pub(crate) fn pack(&self, buf: &mut [u8]) { for i in 0..N / 2 { let mut t0 = self.coeffs[2 * i]; @@ -122,6 +427,7 @@ impl Poly { } // Unpacks a buffer of bytes into a polynomial + // poly will NOT be normalised, but 0 <= coeffs < 4096 // Example: // poly.unpack(buf); pub(crate) fn unpack(&mut self, buf: &[u8]) { @@ -134,10 +440,11 @@ impl Poly { // Converts a message buffer into a polynomial // msg should be of length SYMBYTES (32) + // poly will not be normalised // Example: // poly.read_msg(msg_buf); pub(crate) fn read_msg(&mut self, msg: &[u8]) -> Result<(), TryFromIntError> { - for i in 0..N / 8 { + for i in 0..SYMBYTES { for j in 0..8 { let mask = ((i16::from(msg[i]) >> j) & 1).wrapping_neg(); self.coeffs[8 * i + j] = mask & i16::try_from((Q + 1) / 2)?; @@ -147,6 +454,7 @@ impl Poly { } // Convert a given polynomial into a SYMBYTES (32-byte) message + // poly should be normalised // Example: // poly.write_msg(msg_buf); pub(crate) fn write_msg(&self, buf: &mut [u8]) -> Result<(), TryFromIntError> { @@ -167,6 +475,7 @@ impl Poly { // Decompresses buffer into a polynomial // is dependent on the security level // buf should be of length poly_compressed_bytes + // output poly is normalised // Example: // poly.decompress(buf, k); pub(crate) fn decompress( @@ -180,8 +489,7 @@ impl Poly { SecurityLevel::FiveOneTwo { .. } | SecurityLevel::SevenSixEight { .. } => { for (i, &byte) in buf.iter().take(N / 2).enumerate() { self.coeffs[2 * i] = i16::try_from((usize::from(byte & 15) * Q + 8) >> 4)?; - self.coeffs[2 * i + 1] = - i16::try_from((usize::from(byte >> 4) * Q + 8) >> 4)?; + self.coeffs[2 * i + 1] = i16::try_from((usize::from(byte >> 4) * Q + 8) >> 4)?; } Ok(()) } @@ -211,6 +519,7 @@ impl Poly { // Compress polynomial to a buffer // buf must have space for poly_compressed_bytes + // poly should be normalised // Example: // self.compress(buf); pub(crate) fn compress( @@ -270,3 +579,44 @@ impl Poly { } } } + +// struct HttpResponse { +// // Instead of PhantomData, we store an actual copy. +// extra: S, +// } + +// // Start adds no fields. +// struct Start; + +// // Headers adds a field recording the response code we sent. +// struct Headers { +// response_code: u8, +// } + +// trait ResponseState {} +// impl ResponseState for Start {} +// impl ResponseState for Headers {} + +// impl HttpResponse { +// fn status_line(self, response_code: u8, _message: &str) +// -> HttpResponse +// { +// HttpResponse { +// extra: Headers { +// response_code, +// }, +// } +// } +// } + +// impl HttpResponse { +// fn response_code(&self) -> u8 { +// self.extra.response_code +// } +// } + +// fn testing() { +// let r = HttpResponse { +// extra: Start +// }; +// } diff --git a/src/sample.rs b/src/sample.rs index 63d8ec0..0e6f032 100644 --- a/src/sample.rs +++ b/src/sample.rs @@ -1,15 +1,25 @@ use crate::{ - params::{Eta, N, Q}, + params::{Eta, N, Q, SYMBYTES}, polynomials::Poly, }; use byteorder::{ByteOrder, LittleEndian}; +use rand_core::{CryptoRng, Error, RngCore}; use sha3::{ digest::{ExtendableOutput, Update, XofReader}, Shake128, Shake256, }; +pub fn random_bytes(buf: &mut [u8], len: usize, rng: &mut R) -> Result<(), Error> +where + R: RngCore + CryptoRng, +{ + rng.try_fill_bytes(&mut buf[..len])?; + Ok(()) +} + impl Poly { // Sample our polynomial from a centered binomial distribution + // given a uniformly distributed array of bytes // n = 4, p = 1/2 // ie. coefficients are in {-2, -1, 0, 1, 2} // with probabilities {1/16, 1/4, 3/8, 1/4, 1/16} @@ -19,23 +29,22 @@ impl Poly { hash.update(seed); hash.update(&key_suffix); - let mut entropy_buf = [0u8; 128]; + let mut entropy_buf = [0u8; SYMBYTES * 4]; hash.finalize_xof().read(&mut entropy_buf); - for i in 0..16 { - let coeff_bytes = &entropy_buf[i * 8..(i + 1) * 8]; + for (i, coeff_bytes) in entropy_buf.chunks_exact(8).enumerate() { let coeff_sum = LittleEndian::read_u64(coeff_bytes); let mut accumulated_sum = coeff_sum & 0x5555_5555_5555_5555; accumulated_sum += (coeff_sum >> 1) & 0x5555_5555_5555_5555; #[allow(clippy::cast_possible_truncation)] - for j in 0..16 { + for coeff in self.coeffs.iter_mut().skip(16 * i).take(16) { let coeff_a = (accumulated_sum as i16) & 0x3; accumulated_sum >>= 2; let coeff_b = (accumulated_sum as i16) & 0x3; accumulated_sum >>= 2; - self.coeffs[16 * i + j] = coeff_a - coeff_b; + *coeff = coeff_a - coeff_b; } } } @@ -50,24 +59,25 @@ impl Poly { hash.update(seed); hash.update(&key_suffix); - let mut entropy_buf = [0u8; 192 + 2]; + let mut entropy_buf = [0u8; SYMBYTES * 6]; hash.finalize_xof().read(&mut entropy_buf); - for i in 0..32 { - let coeff_bytes = &entropy_buf[i * 6..i * 6 + 8]; - let coeff_sum = LittleEndian::read_u64(coeff_bytes); + for (i, coeff_bytes) in entropy_buf.chunks_exact(6).enumerate() { + //must be able to read 8 bytes even though we only use 6. + let coeff_sum = LittleEndian::read_u64(&[coeff_bytes, &[0u8; 2]].concat()); let mut accumulated_sum = coeff_sum & 0x2492_4924_9249; accumulated_sum += (coeff_sum >> 1) & 0x2492_4924_9249; accumulated_sum += (coeff_sum >> 2) & 0x2492_4924_9249; #[allow(clippy::cast_possible_truncation)] - for j in 0..8 { + for coeff in self.coeffs.iter_mut().skip(8 * i).take(8) { let coeff_a = (accumulated_sum as i16) & 0x7; accumulated_sum >>= 3; let coeff_b = (accumulated_sum as i16) & 0x7; accumulated_sum >>= 3; - self.coeffs[8 * i + j] = coeff_a - coeff_b; + + *coeff = coeff_a - coeff_b; } } } diff --git a/src/tests/buffer.rs b/src/tests/buffer.rs index 8967ebc..db86268 100644 --- a/src/tests/buffer.rs +++ b/src/tests/buffer.rs @@ -1,6 +1,14 @@ #[cfg(test)] pub(in crate::tests) mod buffer_tests { - use crate::{params::*, polynomials::*, vectors::*}; + use crate::{ + params::*, + polynomials::*, + tests::{ + params::params_tests::sec_level_strategy, polynomials::poly_tests::new_poly_array, + }, + vectors::*, + }; + use proptest::prelude::*; use rand::Rng; extern crate std; use std::vec; @@ -27,30 +35,32 @@ pub(in crate::tests) mod buffer_tests { data } - #[test] - fn pack_unpack_poly_test() { - let poly = Poly { coeffs: [20; N] }; - let mut buffer = [0; POLYBYTES]; - poly.pack(&mut buffer); + proptest! { + #[test] + fn pack_unpack_poly_test(a in new_poly_array()) { + let mut poly = Poly::from(&a); + poly.normalise(); + let mut buffer = [0; POLYBYTES]; + poly.pack(&mut buffer); - let mut comp_poly = Poly::new(); - comp_poly.unpack(&buffer); + let mut comp_poly = Poly::new(); + comp_poly.unpack(&buffer); - assert_eq!(comp_poly.coeffs, poly.coeffs); - } + assert_eq!(poly, comp_poly); + } - #[test] - fn compress_decompress_poly_test() { - for sec_level in &TEST_PARAMS { + #[test] + fn compress_decompress_poly_test( + sec_level in sec_level_strategy() + ) { let buf = generate_random_buffer(sec_level.poly_compressed_bytes()); let mut buf_comp = zero_initialise_buffer(sec_level.poly_compressed_bytes()); - let mut poly = Poly::new(); - let _ = poly.decompress(&buf, sec_level); - let _ = poly.compress(&mut buf_comp, sec_level); + let _ = poly.decompress(&buf, &sec_level); + let _ = poly.compress(&mut buf_comp, &sec_level); - assert_eq!(buf_comp, buf); + assert_eq!(buf, buf_comp); } } @@ -94,10 +104,8 @@ pub(in crate::tests) mod buffer_tests { #[test] fn compress_decompress_vec_test() { for sec_level in &TEST_PARAMS { - let buf = - generate_random_buffer(sec_level.poly_vec_compressed_bytes()); - let mut buf_comp = - zero_initialise_buffer(sec_level.poly_vec_compressed_bytes()); + let buf = generate_random_buffer(sec_level.poly_vec_compressed_bytes()); + let mut buf_comp = zero_initialise_buffer(sec_level.poly_vec_compressed_bytes()); if let &SecurityLevel::FiveOneTwo { .. } = sec_level { let mut poly_vec = PolyVec512::from([Poly::new(); 2]); diff --git a/src/tests/field_operations.rs b/src/tests/field_operations.rs index d92c2ac..1d72b10 100644 --- a/src/tests/field_operations.rs +++ b/src/tests/field_operations.rs @@ -1,29 +1,30 @@ #![allow(warnings)] #[cfg(test)] + mod field_tests { - use crate::field_operations::*; + use crate::{field_operations::*, params::Q}; + use proptest::prelude::*; - #[test] - pub(in crate::tests) fn montgomery_reduce_test() { - assert_eq!(montgomery_reduce(i32::MAX), 32599); - assert_eq!(montgomery_reduce(i32::MIN), -32768); - } + const montgomery_reduce_limit: i32 = (Q as i32) * (2 as i32).pow(15); + proptest! { + #[test] + fn montgomery_reduce_test(i in -montgomery_reduce_limit..montgomery_reduce_limit) { + montgomery_reduce(i); + } - #[test] - pub(in crate::tests) fn mont_form_test() { - assert_eq!(mont_form(i16::MAX), 56); - assert_eq!(mont_form(i16::MIN), 988); - } + #[test] + fn mont_form_test(i: i16) { + mont_form(i); + } - #[test] - pub(in crate::tests) fn barrett_reduce_test() { - assert_eq!(barrett_reduce(i16::MAX), 2806); - assert_eq!(barrett_reduce(i16::MIN), 522); - } + #[test] + fn barrett_reduce_test(i: i16) { + barrett_reduce(i); + } - #[test] - pub(in crate::tests) fn conditional_sub_q_test() { - assert_eq!(conditional_sub_q(i16::MAX), 29438); - assert_eq!(conditional_sub_q(-29439), -29439); + #[test] + fn conditional_sub_q_test(i: i16) { + conditional_sub_q(i); + } } } diff --git a/src/tests/indcpa.rs b/src/tests/indcpa.rs index c0caead..8099a31 100644 --- a/src/tests/indcpa.rs +++ b/src/tests/indcpa.rs @@ -1,6 +1,13 @@ #[cfg(test)] mod indcpa_tests { - use crate::{indcpa::*, vectors::PolyVec512, matrix::{Mat512, MatOperations}, tests::sample::sample_tests::generate_random_seed, polynomials::Poly, params::N}; + use crate::{ + indcpa::*, + matrix::{Mat512, MatOperations}, + params::{N, SYMBYTES}, + polynomials::Poly, + tests::sample::sample_tests::generate_random_seed, + vectors::PolyVec512, + }; #[test] fn priv_pack_unpack() { @@ -21,35 +28,36 @@ mod indcpa_tests { let seed = generate_random_seed(); let pub_key = PublicKey:: { rho: seed, - noise: PolyVec512::from([Poly { coeffs: [20; N]}; 2]), + noise: PolyVec512::from([Poly { coeffs: [20; N] }; 2]), a_t: Mat512::derive(&seed, true), }; let mut buf = [0u8; 2 * 384 + 32]; // k * poly_compressed_bytes + rho length pub_key.pack(&mut buf); let mut new_pub_key = PublicKey:: { rho: [0u8; 32], - noise: PolyVec512::from([Poly { coeffs: [0; N]}; 2]), + noise: PolyVec512::from([Poly { coeffs: [0; N] }; 2]), a_t: Mat512::derive(&generate_random_seed(), true), }; new_pub_key.unpack(&buf); assert_eq!(pub_key, new_pub_key); } - #[test] fn key_gen_enc_dec() { - let seed = generate_random_seed(); + let key_seed = generate_random_seed(); + let cipher_seed = generate_random_seed(); let plaintext = generate_random_seed(); - let (priv_key, pub_key) = generate_key_pair::(&seed); + let (priv_key, pub_key) = generate_key_pair::(&key_seed); - let mut ciphertext = [0u8; 768]; + let mut ciphertext = [0u8; 768]; //indcpa bytes - let _ = encrypt(&pub_key, &plaintext, &seed, &mut ciphertext); + let _ = encrypt(&pub_key, &plaintext, &cipher_seed, &mut ciphertext); - let mut message = [0u8; 768]; + let mut message = [0u8; SYMBYTES]; // SYMBYTES let _ = decrypt(&priv_key, &ciphertext, &mut message); - assert_eq!(message, ciphertext); + // assert_eq!(ciphertext, [0u8; 768]); + assert_eq!(message, plaintext); } } diff --git a/src/tests/matrix.rs b/src/tests/matrix.rs index 580bf42..348631e 100644 --- a/src/tests/matrix.rs +++ b/src/tests/matrix.rs @@ -15,6 +15,7 @@ mod matrix_tests { ]; #[test] + #[ignore] fn derive_test() { let seed = generate_random_seed(); for sec_level in &TEST_PARAMS { diff --git a/src/tests/ntt.rs b/src/tests/ntt.rs index ce9b5a5..60b19ce 100644 --- a/src/tests/ntt.rs +++ b/src/tests/ntt.rs @@ -1,44 +1,53 @@ #![allow(warnings)] #[cfg(test)] mod ntt_tests { - use crate::{params::*, polynomials::*}; - use more_asserts::{assert_gt, assert_lt}; - - // Test Poly::ntt() and Poly::inv_ntt() - #[test] - fn ntt_inv_ntt_test() { - let mut input_poly = Poly { coeffs: [20; N] }; - - // Save a copy of the original input for later comparison. - let mut original_input = input_poly; - original_input.normalise(); - - input_poly.ntt(); - - for coefficient in input_poly.coeffs { - assert_lt!(coefficient, 7 * (Q as i16)); - assert_gt!(coefficient, -7 * (Q as i16)); + use crate::{params::*, polynomials::*, tests::polynomials::poly_tests::new_poly_array}; + use more_asserts::assert_lt; + use proptest::prelude::*; + + proptest! { + // Our poly's are over Z_q and so we only need to test for |coefficients| <= q + #[test] + fn ntt_test(a in new_poly_array()) { + let mut poly = Poly { coeffs: a }; + poly.ntt(); + + for coefficient in poly.coeffs { + assert_lt!(coefficient.abs(), 7 * (Q as i16)); + } } - input_poly.normalise(); - input_poly.inv_ntt(); + #[test] + fn inv_ntt_test(a in new_poly_array()) { + let mut poly = Poly { coeffs: a }; + poly.inv_ntt(); - for coefficient in input_poly.coeffs { - assert_lt!(coefficient, (Q as i16)); - assert_gt!(coefficient, -(Q as i16)); + for coefficient in poly.coeffs { + assert_lt!(coefficient.abs(), (Q as i16)); + } } - input_poly.normalise(); - - for i in 0..N { - let p: i32 = input_poly.coeffs[i] as i32; - let q: i32 = original_input.coeffs[i] as i32; - assert_eq!( - p, - (q * (1 << 16)) % (Q as i32), - "we are testing equality with original at index {}", - i - ); + #[test] + fn ntt_inv_ntt_test(a in new_poly_array()) { + let mut input_poly = Poly { coeffs: a }; + let mut original_input = input_poly; + original_input.normalise(); + + input_poly.ntt(); + input_poly.normalise(); + input_poly.inv_ntt(); + input_poly.normalise(); + + for i in 0..N { + let p: i32 = input_poly.coeffs[i] as i32; + let q: i32 = original_input.coeffs[i] as i32; + assert_eq!( + p, + (q * (1 << 16)) % (Q as i32), + "we are testing equality with original at index {}", + i + ); + } } } } diff --git a/src/tests/params.rs b/src/tests/params.rs index 0b1e556..4624b19 100644 --- a/src/tests/params.rs +++ b/src/tests/params.rs @@ -1,7 +1,16 @@ #![allow(warnings)] #[cfg(test)] -mod params_tests { +pub(in crate::tests) mod params_tests { use crate::params::*; + use proptest::prelude::*; + + pub(in crate::tests) fn sec_level_strategy() -> impl Strategy { + prop_oneof![ + Just(SecurityLevel::new(K::Two)), + Just(SecurityLevel::new(K::Three)), + Just(SecurityLevel::new(K::Four)), + ] + } #[test] fn sec_level_test() { diff --git a/src/tests/polynomials.rs b/src/tests/polynomials.rs index 74c3450..ffc56fc 100644 --- a/src/tests/polynomials.rs +++ b/src/tests/polynomials.rs @@ -1,49 +1,52 @@ #![allow(warnings)] #[cfg(test)] -mod poly_tests { +pub(in crate::tests) mod poly_tests { use crate::{ field_operations::{barrett_reduce, montgomery_reduce}, + ntt::ZETAS, params::*, polynomials::*, tests::buffer::buffer_tests::zero_initialise_buffer, }; + use proptest::prelude::*; - const INPUT_COEFFS: [i16; N] = [ - -650, -1557, -1607, 924, 1571, 776, -531, -1418, -1172, -511, 1430, 1180, 892, 1471, 1063, - 934, 1320, -1278, 1420, 687, 834, -1508, 80, 5, -266, -1306, 826, -958, 1079, -705, -1507, - -1236, -597, -1449, 1405, -638, 1045, -791, -339, 1590, 415, -573, 1105, -305, -715, 555, - -1036, -1059, 995, -1281, 1293, 216, -1072, -292, -1443, 327, 119, 1100, 1087, -467, -1269, - 1245, 15, -149, 1514, -245, 930, 946, 682, -1073, 923, -516, 19, 364, 844, 969, -694, 1473, - 1627, -1364, -1420, 1255, 570, -827, -650, 792, 1218, 1186, 227, 640, -893, 675, 272, 839, - -1138, 173, -1071, 1457, -546, 1328, -1281, -1287, -852, 455, 794, -1621, -188, -1565, - 1570, -226, -1211, -1515, -583, 1024, -625, 484, 203, -1072, 6, -1235, 1285, 830, 1106, - -107, 4, -1645, -1599, 650, 1529, -427, 314, -1416, -49, 1179, 756, -868, 1275, -1045, - -768, 1180, 395, -262, 1330, 1529, -903, -907, 348, 965, -262, -1259, 1448, -641, 1236, - 889, 917, -373, 961, 1035, -1387, 825, -1057, 644, 1126, 611, 210, 218, 1408, -180, 838, - -972, -664, -380, 431, -947, -516, 1246, -137, 1550, 546, 1267, -1374, 329, -1039, 1528, - -395, 1595, -458, -1099, 1017, -128, 1444, -1652, -1149, 905, 624, 778, -542, 420, -1066, - -1316, 1113, -13, 21, -69, 757, 1223, -488, -1044, 1108, -1554, -1442, 1399, 492, -816, - 1314, -1567, -834, -756, -949, -1482, 781, -1170, -1469, 1350, 1401, 873, 463, -754, -372, - 1114, -353, -872, -564, 1386, 724, -1471, 944, -1376, -850, 439, -1265, -627, 173, 892, - 274, -125, 1042, 1105, 784, -1571, 1340, -48, -1024, 1537, -363, -1236, - ]; - - const OUTPUT_COEFFS: [i16; N] = [ - 0, 1665, 1665, 1665, 1665, 0, 0, 1665, 1665, 0, 1665, 1665, 1665, 1665, 1665, 1665, 1665, - 1665, 1665, 0, 1665, 1665, 0, 0, 0, 1665, 0, 1665, 1665, 0, 1665, 1665, 0, 1665, 1665, 0, - 1665, 0, 0, 1665, 0, 0, 1665, 0, 0, 0, 1665, 1665, 1665, 1665, 1665, 0, 1665, 0, 1665, 0, - 0, 1665, 1665, 0, 1665, 1665, 0, 0, 1665, 0, 1665, 1665, 0, 1665, 1665, 0, 0, 0, 1665, - 1665, 0, 1665, 1665, 1665, 1665, 1665, 0, 0, 0, 0, 1665, 1665, 0, 0, 1665, 0, 0, 1665, - 1665, 0, 1665, 1665, 0, 1665, 1665, 1665, 1665, 0, 0, 1665, 0, 1665, 1665, 0, 1665, 1665, - 0, 1665, 0, 0, 0, 1665, 0, 1665, 1665, 0, 1665, 0, 0, 1665, 1665, 0, 1665, 0, 0, 1665, 0, - 1665, 0, 1665, 1665, 1665, 0, 1665, 0, 0, 1665, 1665, 1665, 1665, 0, 1665, 0, 1665, 1665, - 0, 1665, 1665, 1665, 0, 1665, 1665, 1665, 0, 1665, 0, 1665, 0, 0, 0, 1665, 0, 1665, 1665, - 0, 0, 0, 1665, 0, 1665, 0, 1665, 0, 1665, 1665, 0, 1665, 1665, 0, 1665, 0, 1665, 1665, 0, - 1665, 1665, 1665, 1665, 0, 0, 0, 0, 1665, 1665, 1665, 0, 0, 0, 0, 1665, 0, 1665, 1665, - 1665, 1665, 1665, 0, 0, 1665, 1665, 1665, 0, 1665, 1665, 0, 1665, 1665, 1665, 1665, 1665, - 0, 0, 0, 1665, 0, 1665, 0, 1665, 0, 1665, 1665, 1665, 1665, 0, 1665, 0, 0, 1665, 0, 0, - 1665, 1665, 0, 1665, 1665, 0, 1665, 1665, 0, 1665, - ]; + pub(in crate::tests) fn new_poly_array() -> impl Strategy { + prop::array::uniform(-(Q as i16)..(Q as i16)) + } + + impl Poly { + fn pointwise_mul_alt(&mut self, x: &Self) { + let mut j: usize = 64; + + for i in (0..N).step_by(4) { + let zeta = i32::from(ZETAS[j]); + j += 1; + + let mut p0 = + montgomery_reduce(i32::from(self.coeffs[i + 1]) * i32::from(x.coeffs[i + 1])); + p0 = montgomery_reduce(i32::from(p0) * zeta); + p0 += montgomery_reduce(i32::from(self.coeffs[i]) * i32::from(x.coeffs[i])); + + let mut p1 = + montgomery_reduce(i32::from(self.coeffs[i]) * i32::from(x.coeffs[i + 1])); + p1 += montgomery_reduce(i32::from(self.coeffs[i + 1]) * i32::from(x.coeffs[i])); + + let mut p2 = + montgomery_reduce(i32::from(self.coeffs[i + 3]) * i32::from(x.coeffs[i + 3])); + p2 = -montgomery_reduce(i32::from(p2) * zeta); + p2 += montgomery_reduce(i32::from(self.coeffs[i + 2]) * i32::from(x.coeffs[i + 2])); + + let mut p3 = + montgomery_reduce(i32::from(self.coeffs[i + 2]) * i32::from(x.coeffs[i + 3])); + p3 += montgomery_reduce(i32::from(self.coeffs[i + 3]) * i32::from(x.coeffs[i + 2])); + + self.coeffs[i] = p0; + self.coeffs[i + 1] = p1; + self.coeffs[i + 2] = p2; + self.coeffs[i + 3] = p3; + } + } + } // Test Poly::new() #[test] @@ -52,95 +55,76 @@ mod poly_tests { assert_eq!(poly.coeffs, [0; N]); } - // Test Poly::add() - #[test] - fn add_test() { - let mut poly1 = Poly { coeffs: [1; N] }; - let poly2 = Poly { coeffs: [4; N] }; - poly1.add(&poly2); - assert_eq!(poly1.coeffs, [5; N]); - } + proptest! { + #[test] + fn from_test(a in new_poly_array()) { + let mut poly = Poly::from(&a); + assert_eq!(a, poly.coeffs); + } - // Test Poly::sub() - #[test] - fn sub_test() { - let mut poly1 = Poly { coeffs: [3; N] }; - let poly2 = Poly { coeffs: [1; N] }; - poly1.sub(&poly2); - assert_eq!(poly1.coeffs, [2; N]); - } + #[test] + fn pointwise_mul_test( + a in new_poly_array(), + b in new_poly_array() + ) { + let mut poly_a = Poly::from(&a); + let poly_b = Poly::from(&b); - #[test] - fn mont_form_test() { - let mut poly1 = Poly { - coeffs: [i16::MAX; N], - }; - let mut poly2 = Poly { - coeffs: [i16::MIN; N], - }; - - poly1.mont_form(); - poly2.mont_form(); - - assert_eq!(poly1.coeffs, [56; N]); - assert_eq!(poly2.coeffs, [988; N]); - } + let mut a_copy = poly_a; + let b_copy = poly_b; - // Test Poly::pointwise_mul() - #[test] - fn pointwise_mul_test() { - let a = Poly { - coeffs: [Q as i16; N], - }; - let mut b = Poly { coeffs: [20; N] }; - let mut p = Poly::new(); - - b.coeffs[0] = 1; - - let mut a_copy = a; - let mut b_copy = b; - - a_copy.ntt(); - b_copy.ntt(); - - a_copy.pointwise_mul(&b_copy); - a_copy.barrett_reduce(); - a_copy.inv_ntt(); - - for i in 0..N { - for j in 0..N { - let mut v = montgomery_reduce((a.coeffs[i] as i32) * (b.coeffs[j] as i32)); - let mut k = i + j; - - // circular shifting case; x^N = -1 - if k >= N { - k -= N; - v = -v; - } - p.coeffs[k] = barrett_reduce(v + p.coeffs[k]); - } + poly_a.pointwise_mul(&poly_b); + a_copy.pointwise_mul_alt(&poly_b); + + assert_eq!(poly_a, a_copy); } - for i in 0..N { - p.coeffs[i] = (((p.coeffs[i] as i32) * ((1 << 16) % (Q as i32))) % (Q as i32)) as i16; + #[test] + fn to_and_from_msg_test(a in new_poly_array()) { + let mut poly = Poly::from(&a); + poly.normalise(); + let mut msg = [0u8; POLYBYTES]; + + poly.write_msg(&mut msg); + + let mut new_poly = Poly::new(); + new_poly.read_msg(&msg); + + for (&coeff, new_coeff) in poly.coeffs.iter().zip(new_poly.coeffs) { + if 833 <= coeff && coeff <= 2496 { + assert_eq!(new_coeff, (Q as i16 + 1) / 2, "{}", coeff); + } else { + assert_eq!(new_coeff, 0, "{}", coeff); + } + } } - p.normalise(); - a_copy.normalise(); + #[test] + fn add_test( + a in new_poly_array(), + b in new_poly_array() + ) { + let mut poly_a = Poly::from(&a); + let poly_b = Poly::from(&b); - assert_eq!(p.coeffs, a_copy.coeffs); - } + poly_a.add(&poly_b); + } - #[test] - fn to_and_from_msg_test() { - let mut poly_original = Poly { - coeffs: INPUT_COEFFS, - }; + #[test] + fn sub_test( + a in new_poly_array(), + b in new_poly_array() + ) { + let mut poly_a = Poly::from(&a); + let poly_b = Poly::from(&b); - let mut msg = zero_initialise_buffer(32); - poly_original.write_msg(&mut msg); - poly_original.read_msg(&msg); + poly_a.sub(&poly_b); + } - assert_eq!(poly_original.coeffs, OUTPUT_COEFFS); + #[test] + fn mont_form_test(a in new_poly_array()) { + let mut poly = Poly::from(&a); + poly.mont_form(); + } } } diff --git a/src/tests/sample.rs b/src/tests/sample.rs index bd021c9..56a2534 100644 --- a/src/tests/sample.rs +++ b/src/tests/sample.rs @@ -129,6 +129,7 @@ pub(in crate::tests) mod sample_tests { } #[test] + #[ignore] fn derive_noise_2_dist_test() { let seed = generate_random_seed(); let nonce = generate_random_nonce(); @@ -140,6 +141,7 @@ pub(in crate::tests) mod sample_tests { } #[test] + #[ignore] fn derive_noise_3_dist_test() { let seed = generate_random_seed(); let nonce = generate_random_nonce(); @@ -151,6 +153,7 @@ pub(in crate::tests) mod sample_tests { } #[test] + #[ignore] fn derive_uniform_test() { let seed = generate_random_seed(); let x = generate_random_nonce(); diff --git a/src/tests/vectors.rs b/src/tests/vectors.rs index 6a07fa4..f802454 100644 --- a/src/tests/vectors.rs +++ b/src/tests/vectors.rs @@ -269,6 +269,7 @@ mod vec_tests { } #[test] + #[ignore] fn derive_noise_dist_test() { let poly = Poly::new(); let seed = generate_random_seed(); @@ -321,6 +322,7 @@ mod vec_tests { temp.pointwise_mul(&poly_vec_1[i]); comp_poly.add(&temp); } + comp_poly.barrett_reduce(); assert_eq!(poly, comp_poly); } @@ -337,6 +339,7 @@ mod vec_tests { temp.pointwise_mul(&poly_vec_1[i]); comp_poly.add(&temp); } + comp_poly.barrett_reduce(); assert_eq!(poly, comp_poly); } @@ -353,6 +356,7 @@ mod vec_tests { temp.pointwise_mul(&poly_vec_1[i]); comp_poly.add(&temp); } + comp_poly.barrett_reduce(); assert_eq!(poly, comp_poly); } diff --git a/src/vectors.rs b/src/vectors.rs index f806288..344ed0c 100644 --- a/src/vectors.rs +++ b/src/vectors.rs @@ -2,7 +2,7 @@ use core::num::TryFromIntError; use crate::{ matrix::{Mat1024, Mat512, Mat768}, - params::{Eta, GetSecLevel, SecurityLevel, K, POLYBYTES, N, Q}, + params::{Eta, GetSecLevel, SecurityLevel, K, N, POLYBYTES, Q}, polynomials::Poly, }; use tinyvec::ArrayVec; @@ -117,8 +117,14 @@ macro_rules! impl_polyvec { for k in 0..4 { temp[k] = u16::try_from(self[i].coeffs[4 * j + k])?; - temp[k] = temp[k].wrapping_add(u16::try_from((i16::try_from(temp[k])? >> 15) & i16::try_from(Q)?)?); - temp[k] = u16::try_from((((u32::from(temp[k]) << 10) + u32::try_from(Q)? / 2) / u32::try_from(Q)?) & 0x3ff)?; + temp[k] = temp[k].wrapping_add(u16::try_from( + (i16::try_from(temp[k])? >> 15) & i16::try_from(Q)?, + )?); + temp[k] = u16::try_from( + (((u32::from(temp[k]) << 10) + u32::try_from(Q)? / 2) + / u32::try_from(Q)?) + & 0x3ff, + )?; } let index = (i * (N / 4) + j) * 5; @@ -140,8 +146,14 @@ macro_rules! impl_polyvec { for k in 0..8 { temp[k] = u16::try_from(self[i].coeffs[8 * j + k])?; - temp[k] = temp[k].wrapping_add(u16::try_from((i16::try_from(temp[k])? >> 15) & i16::try_from(Q)?)?); - temp[k] = u16::try_from((((u32::from(temp[k]) << 11) + u32::try_from(Q)? / 2) / u32::try_from(Q)?) & 0x7ff)?; + temp[k] = temp[k].wrapping_add(u16::try_from( + (i16::try_from(temp[k])? >> 15) & i16::try_from(Q)?, + )?); + temp[k] = u16::try_from( + (((u32::from(temp[k]) << 11) + u32::try_from(Q)? / 2) + / u32::try_from(Q)?) + & 0x7ff, + )?; } let index = (i * (N / 8) + j) * 11; @@ -178,12 +190,15 @@ macro_rules! impl_polyvec { let temp = (0..4).map(|k| { let shift = (2 * k) as u32; - let val = u16::from(buf[index + k] >> shift) | u16::from(buf[index + k + 1]) << (8 - shift); + let val = u16::from(buf[index + k] >> shift) + | u16::from(buf[index + k + 1]) << (8 - shift); val }); - + for (k, val) in temp.enumerate() { - self[i].coeffs[4 * j + k] = i16::try_from(((u32::from(val) & 0x3ff) * u32::try_from(Q)? + 512) >> 10)?; + self[i].coeffs[4 * j + k] = i16::try_from( + ((u32::from(val) & 0x3ff) * u32::try_from(Q)? + 512) >> 10, + )?; } } } @@ -195,7 +210,8 @@ macro_rules! impl_polyvec { let temp = (0..8).map(|k| { let shift = ((3 * k) % 8) as u32; - let mut val = u16::from(buf[index + k] >> shift) | u16::from(buf[index + k + 1]) << (8 - shift); + let mut val = u16::from(buf[index + k] >> shift) + | u16::from(buf[index + k + 1]) << (8 - shift); if k % 3 == 2 { let mut extra = u16::from(buf[index + k + 2]); if k == 2 { @@ -210,7 +226,9 @@ macro_rules! impl_polyvec { }); for (k, val) in temp.enumerate() { - self[i].coeffs[8 * j + k] = i16::try_from((u32::from(val & 0x7ff) * u32::try_from(Q)? + 1024) >> 11)?; + self[i].coeffs[8 * j + k] = i16::try_from( + (u32::from(val & 0x7ff) * u32::try_from(Q)? + 1024) >> 11, + )?; } } } @@ -245,5 +263,6 @@ impl Poly { temp.pointwise_mul(&multiplier_poly); self.add(&temp); } + self.barrett_reduce(); } }