Skip to content

Commit

Permalink
fix kyber slash attack
Browse files Browse the repository at this point in the history
  • Loading branch information
supinie committed May 27, 2024
1 parent 32503aa commit 57e3b9a
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 40 deletions.
8 changes: 4 additions & 4 deletions src/field_operations.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::params::Q;
use crate::params::{Q_I16, Q_I32};

// given -2^15 q <= x < 2^15 q, returns -q < y < q with y congruent to x * 2^-16 mod q
// Example:
Expand All @@ -9,7 +9,7 @@ use crate::params::Q;
pub fn montgomery_reduce(x: i32) -> i16 {
const QPRIME: i32 = 62209;
let m = x.wrapping_mul(QPRIME) as i16;
let t = (x - i32::from(m).wrapping_mul(Q as i32)) >> 16;
let t = (x - i32::from(m).wrapping_mul(Q_I32)) >> 16;
t as i16
}

Expand Down Expand Up @@ -43,15 +43,15 @@ pub fn barrett_reduce(x: i16) -> i16 {
// x - ⌊x 20156/2²⁶⌋ q = [
// [ x mod q otherwise
let inside_floor = (i32::from(x).wrapping_mul(APPROXIMATION) >> 26) as i16;
x.wrapping_sub(inside_floor.wrapping_mul(Q as i16))
x.wrapping_sub(inside_floor.wrapping_mul(Q_I16))
}

// given x, if x < Q return x, otherwise return x - Q
// Example:
// let x = conditional_sub_q(y);
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
pub const fn conditional_sub_q(x: i16) -> i16 {
const Q_16: i16 = Q as i16;
const Q_16: i16 = Q_I16;
if x < Q_16 {
x
} else {
Expand Down
8 changes: 8 additions & 0 deletions src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@ use core::fmt::{Display, Formatter};
use num_enum::{IntoPrimitive, TryFromPrimitive};

pub const N: usize = 256;

pub const Q: usize = 3329;
pub const Q_I16: i16 = Q as i16;
pub const Q_U16: u16 = Q as u16;
pub const Q_I32: i32 = Q as i32;
pub const Q_U32: u32 = Q as u32;

pub const Q_DIV: u64 = 80635;
pub const Q_DIV_VEC: u64 = 1290167;

pub const SYMBYTES: usize = 32; // size of hashes

Expand Down
27 changes: 12 additions & 15 deletions src/polynomials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod sample;
use crate::{
errors::{CrystalsError, PackingError},
field_operations::{barrett_reduce, conditional_sub_q, mont_form, montgomery_reduce},
params::{SecurityLevel, N, POLYBYTES, Q, SYMBYTES},
params::{SecurityLevel, N, POLYBYTES, Q, Q_I16, Q_U16, Q_U32, Q_DIV, SYMBYTES},
polynomials::ntt::ZETAS,
};
use core::num::TryFromIntError;
Expand Down Expand Up @@ -247,9 +247,9 @@ impl Poly<Normalised> {
let mut buf = [0u8; POLYBYTES];
for i in 0..N / 2 {
let mut t0 = self.coeffs[2 * i];
t0 += (t0 >> 15) & Q as i16;
t0 += (t0 >> 15) & Q_I16;
let mut t1 = self.coeffs[2 * i + 1];
t1 += (t1 >> 15) & Q as i16;
t1 += (t1 >> 15) & Q_I16;

buf[3 * i] = t0 as u8;
buf[3 * i + 1] = ((t0 >> 8) | (t1 << 4)) as u8;
Expand All @@ -267,15 +267,16 @@ impl Poly<Normalised> {
// ```
pub(crate) fn write_msg(&self) -> Result<[u8; SYMBYTES], TryFromIntError> {
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
let q_16 = i16::try_from(Q)?;
let buf = self
.coeffs
.chunks_exact(8)
.map(|chunk| {
chunk
.iter()
.map(|&coeff| coeff + ((coeff >> 15) & q_16))
.map(|coeff| (((coeff << 1) + q_16 / 2) / q_16) & 1)
.map(|&coeff| coeff + ((coeff >> 15) & Q_I16))
.map(i32::from)
.map(|coeff| (coeff << 1) + Q as i32 / 2)
.map(|t| ((t * 80635) >> 28) & 1)
.enumerate()
.try_fold(0, |accumulator, (index, coeff)| {
let shifted_coeff = u8::try_from(coeff << index)?;
Expand Down Expand Up @@ -316,11 +317,9 @@ impl Poly<Normalised> {
{
for (coeff, t_elem) in coeff_chunk.iter().zip(t.iter_mut()) {
let mut temp = *coeff;
temp += (temp >> 15) & i16::try_from(Q)?;
temp += (temp >> 15) & Q_I16;
*t_elem = u8::try_from(
((((u16::try_from(temp)?) << 4) + u16::try_from(Q)? / 2)
/ u16::try_from(Q)?)
& 15,
(((((u64::try_from(temp)?) << 4) + u64::from(Q_U16 / 2)) * Q_DIV) >> 28) & 0xf,
)?;
}

Expand All @@ -339,11 +338,9 @@ impl Poly<Normalised> {
{
for (coeff, t_elem) in coeff_chunk.iter().zip(t.iter_mut()) {
let mut temp = *coeff;
temp += (temp >> 15) & i16::try_from(Q)?;
temp += (temp >> 15) & Q_I16;
*t_elem = u8::try_from(
((((u32::try_from(temp)?) << 5) + u32::try_from(Q)? / 2)
/ u32::try_from(Q)?)
& 31,
(((((u64::try_from(temp)?) << 5) + u64::from(Q_U32 / 2)) * (Q_DIV / 2)) >> 27) & 0x1f,
)?;
}

Expand Down Expand Up @@ -471,7 +468,7 @@ impl Poly<Normalised> {
];
for (coeff, t_elem) in coeffs_chunk.iter_mut().zip(temp.iter()) {
*coeff = i16::try_from(
((u32::from(*t_elem) & 31) * u32::try_from(Q)? + 16) >> 5,
((u32::from(*t_elem) & 31) * Q_U32 + 16) >> 5,
)?;
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/tests/polynomials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,13 +464,13 @@ pub(in crate::tests) mod poly_tests {

#[test]
fn write_read_msg_test(
message in prop::array::uniform32(u8::MIN..u8::MAX)
message in prop::array::uniform32(u8::MIN..u8::MAX),
poly in new_poly()
) {
let poly = Poly::read_msg(&message).unwrap();
let comp_message = poly.normalise().write_msg().unwrap();
let poly_from_msg = Poly::read_msg(&message).unwrap();
let comp_message = poly_from_msg.normalise().write_msg().unwrap();

assert_eq!(message, comp_message);
}

}
}
24 changes: 7 additions & 17 deletions src/vectors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
errors::{CrystalsError, PackingError},
params::{Eta, SecurityLevel, K, N, POLYBYTES, Q},
params::{Eta, SecurityLevel, K, N, POLYBYTES, Q_I16, Q_U32, Q_DIV_VEC},
polynomials::{Barrett, Montgomery, Normalised, Poly, Reduced, State, Unnormalised, Unreduced},
};
use tinyvec::{array_vec, ArrayVec};
Expand Down Expand Up @@ -183,8 +183,8 @@ impl PolyVec<Normalised> {
for (coeff, t_elem) in coeff_chunk.iter().zip(t.iter_mut()) {
*t_elem = *coeff as u16;
*t_elem =
t_elem.wrapping_add((((*t_elem as i16) >> 15) & Q as i16) as u16);
*t_elem = (((((u32::from(*t_elem)) << 10) + Q as u32 / 2) / Q as u32)
t_elem.wrapping_add((((*t_elem as i16) >> 15) & Q_I16) as u16);
*t_elem = (((((u64::from(*t_elem) << 10) + u64::from(Q_U32 / 2)) * Q_DIV_VEC) >> 32)
& 0x3ff) as u16;
}

Expand Down Expand Up @@ -224,8 +224,8 @@ impl PolyVec<Normalised> {
for (coeff, t_elem) in coeff_chunk.iter().zip(t.iter_mut()) {
*t_elem = *coeff as u16;
*t_elem =
t_elem.wrapping_add((((*t_elem as i16) >> 15) & Q as i16) as u16);
*t_elem = (((((u32::from(*t_elem)) << 11) + Q as u32 / 2) / Q as u32)
t_elem.wrapping_add((((*t_elem as i16) >> 15) & Q_I16) as u16);
*t_elem = (((((u64::from(*t_elem) << 11) + u64::from(Q_U32 / 2)) * (Q_DIV_VEC / 2)) >> 31)
& 0x7ff) as u16;
}

Expand Down Expand Up @@ -302,7 +302,7 @@ impl PolyVec<Normalised> {
u16::from(buf_tuple[0] >> (2 * (i % 4)))
| u16::from(buf_tuple[1]) << (8 - 2 * (i % 4))
})
.map(|coeff| (((u32::from(coeff) & 0x3ff) * Q as u32 + 512) >> 10) as i16)
.map(|coeff| (((u32::from(coeff) & 0x3ff) * Q_U32 + 512) >> 10) as i16)
.collect::<ArrayVec<[i16; N]>>()
.into_inner();

Expand Down Expand Up @@ -334,7 +334,7 @@ impl PolyVec<Normalised> {
u16::from(chunk[9] >> 5) | u16::from(chunk[10]) << 3,
]
})
.map(|coeff| ((u32::from(coeff & 0x7ff) * Q as u32 + 1024) >> 11) as i16)
.map(|coeff| ((u32::from(coeff & 0x7ff) * Q_U32 + 1024) >> 11) as i16)
.collect::<ArrayVec<[i16; N]>>()
.into_inner();

Expand All @@ -352,16 +352,6 @@ impl PolyVec<Normalised> {
}
}

// match polyvec_result {
// Ok(polynomials) => Ok(Self {
// polynomials,
// sec_level: sec_level.k(),
// }),
// Err(err) => Err(err),
// }
// }
// }

impl PolyVec<Montgomery> {
// derive a noise polyvec using a given seed and nonce
pub(crate) fn derive_noise(sec_level: SecurityLevel, seed: &[u8], nonce: u8, eta: Eta) -> Self {
Expand Down

0 comments on commit 57e3b9a

Please sign in to comment.