diff --git a/src/lll.rs b/src/lll.rs new file mode 100644 index 0000000..3ee5513 --- /dev/null +++ b/src/lll.rs @@ -0,0 +1,22 @@ +use lll_rs::{matrix::Matrix as LLLMatrix, vector::BigVector}; + +use crate::matrix::Matrix; + +impl Matrix { + pub fn to_lll_matrix(&self) -> LLLMatrix { + let n = self.n; + let mut lll_mat = LLLMatrix::init(n, n); + + for row_idx in 0..n { + let mut elements = Vec::with_capacity(n); + + for col_idx in 0..n { + let val = self[(row_idx, col_idx)].clone(); + elements.push(val); + } + + lll_mat[row_idx] = BigVector::from_vector(elements); + } + lll_mat + } +} diff --git a/src/main.rs b/src/main.rs index 01b8298..3066464 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,42 @@ +use rug::Integer; +use crate::matrix::Matrix; +use lll_rs::lll::biglll; +mod lll; mod matrix; fn main() { - println!(""); + // 1. Build lattice matrix basis + let ciphertexts = vec![ +Integer::from(37459), +Integer::from(8227), +Integer::from(44119), +Integer::from(22575), +Integer::from(9249), +Integer::from(38483), +Integer::from(26181), + ]; + let noise_bits = 2; + let basis_matrix = Matrix::new_lattice(noise_bits, ciphertexts.clone()).unwrap(); + + println!("matrix: {:?}", basis_matrix); + + // 2. reduce with LLL + let mut lll_matrix = basis_matrix.to_lll_matrix(); + biglll::lattice_reduce(&mut lll_matrix); + + // 3. Extract shortest vector + let shortest_vector = &lll_matrix[0]; + println!("Shortest vector: {:?}", shortest_vector); + + // 4. q0 candidate + let q0 = &shortest_vector[0] / (Integer::from(1) << (noise_bits + 1)); + + // 5. Find p + // compute r0 = x0 (mod q0) + // and p = (x0 − r0)/q0. + let x0 = &ciphertexts[0]; + let r0 = x0 % q0.clone(); + let p_guess = (x0 - r0) / q0; + + println!("Recovered p: {}", p_guess); } diff --git a/src/matrix.rs b/src/matrix.rs index 81163a2..f3fefbb 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -11,14 +11,14 @@ macro_rules! int { #[derive(Debug, PartialEq)] pub struct Matrix { - pub n: usize, //rows + pub n: usize, // rows pub m: usize, // columns values: Vec, } impl Matrix { pub fn new(n: usize, m: usize, values: Vec) -> Option { - if n*m == values.len() { + if n * m == values.len() { Some(Matrix { n, m, values }) } else { None @@ -29,8 +29,8 @@ impl Matrix { let n = ciphertexts.len(); let mut values = Vec::with_capacity(n * n); - // First row: [2^noise_bits, ciphertexts[1], ..., ciphertexts[t]] - values.push(int!(2u64).pow(noise_bits as u32)); + // First row: [2^(noise_bits+1), ciphertexts[1], ..., ciphertexts[t]] + values.push(int!(2u64).pow(noise_bits as u32 + 1)); values.extend_from_slice(&ciphertexts[1..]); // -x0 on diagonal, 0 everywhere else @@ -48,7 +48,7 @@ impl Matrix { impl Index<(usize, usize)> for Matrix { type Output = Element; fn index(&self, index: (usize, usize)) -> &Self::Output { - if index.0>=self.m || index.1 >= self.n { + if index.0 >= self.m || index.1 >= self.n { panic!(); } &self.values[(self.n * index.0) + index.1] @@ -57,7 +57,7 @@ impl Index<(usize, usize)> for Matrix { impl IndexMut<(usize, usize)> for Matrix { fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output { - if index.0>=self.m || index.1 >= self.n { + if index.0 >= self.m || index.1 >= self.n { panic!(); } &mut self.values[(self.n * index.0) + index.1] @@ -91,7 +91,12 @@ mod tests { m[(1, 0)] = int!(5); assert_eq!(m[(1, 0)], int!(5)); - let m2 = Matrix::new(3, 2, vec![int!(1), int!(2), int!(3), int!(4), int!(5), int!(6)]).unwrap(); + let m2 = Matrix::new( + 3, + 2, + vec![int!(1), int!(2), int!(3), int!(4), int!(5), int!(6)], + ) + .unwrap(); assert_eq!(m2[(0, 2)], int!(3)); assert_eq!(m2[(1, 0)], int!(4)); let result = panic::catch_unwind(|| { @@ -111,7 +116,7 @@ mod tests { let noise_bits = 2; let expected_values = vec![ - int!(4), + int!(8), int!(8), int!(12), int!(0),