L² algorithm
This commit is contained in:
		
							
								
								
									
										13
									
								
								src/agcd.rs
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/agcd.rs
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| use crate::bkz::bkz_reduce; | use crate::bkz::bkz_reduce; | ||||||
| use crate::deep_lll::deep_lll; | use crate::deep_lll::deep_lll; | ||||||
| // use crate::lll::lattice_reduce; | use crate::lll::lattice_reduce; | ||||||
| use crate::matrix::Matrix; | use crate::matrix::Matrix; | ||||||
| use crate::utils::abs; | use crate::utils::abs; | ||||||
| use lll_rs::l2::bigl2; | use lll_rs::l2::bigl2; | ||||||
| @@ -8,7 +8,8 @@ use rug::{Integer, Rational}; | |||||||
|  |  | ||||||
| pub fn agcd(ciphertexts: Vec<Integer>, noise_bits: usize, algorithm: u8) -> Integer { | pub fn agcd(ciphertexts: Vec<Integer>, noise_bits: usize, algorithm: u8) -> Integer { | ||||||
|     // 1. Build lattice matrix basis |     // 1. Build lattice matrix basis | ||||||
|     let basis_matrix = Matrix::new_lattice(noise_bits, ciphertexts.clone()).unwrap(); |     let mut basis_matrix = Matrix::new_lattice(noise_bits, ciphertexts.clone()).unwrap(); | ||||||
|  |     println!("basis: {:?}\n\n\n\n", basis_matrix); | ||||||
|  |  | ||||||
|     // 2. reduce with LLL, and extract first element of shortest vector |     // 2. reduce with LLL, and extract first element of shortest vector | ||||||
|     let mut lll_matrix = basis_matrix.to_lll_matrix(); |     let mut lll_matrix = basis_matrix.to_lll_matrix(); | ||||||
| @@ -27,10 +28,10 @@ pub fn agcd(ciphertexts: Vec<Integer>, noise_bits: usize, algorithm: u8) -> Inte | |||||||
|             let reduced = deep_lll(basis_matrix.clone(), Rational::from((51, 100))).unwrap(); |             let reduced = deep_lll(basis_matrix.clone(), Rational::from((51, 100))).unwrap(); | ||||||
|             reduced.columns[0][0].clone() |             reduced.columns[0][0].clone() | ||||||
|         } |         } | ||||||
|         // 3u8 => { |         3u8 => { | ||||||
|         //     lattice_reduce(&mut basis_matrix, 0.51, 0.75); |             lattice_reduce(&mut basis_matrix, 0.51, 0.75); | ||||||
|         //     lll_matrix[0][0].clone() |             basis_matrix[0][0].clone() | ||||||
|         // } |         } | ||||||
|         _ => panic!("Unknown algorithm value: {}", algorithm), |         _ => panic!("Unknown algorithm value: {}", algorithm), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| use crate::matrix::Matrix; | use crate::matrix::Matrix; | ||||||
| use rug::{Rational, Integer}; | use rug::{Integer, Rational}; | ||||||
|  |  | ||||||
| /// Perform DeepLLL reduction on a given lattice basis represented by Matrix. | /// Perform DeepLLL reduction on a given lattice basis represented by Matrix. | ||||||
| /// 1/4 < delta < 1. | /// 1/4 < delta < 1. | ||||||
| @@ -78,7 +78,12 @@ fn gramm_schmidt(mat: &Matrix<Integer>) -> (Vec<Vec<Rational>>, Vec<Rational>) { | |||||||
| } | } | ||||||
|  |  | ||||||
| /// Size-reduce column k in-place | /// Size-reduce column k in-place | ||||||
| fn size_reduce(mat: &mut Matrix<Integer>, mu: &mut [Vec<Rational>], b_star_sq: &mut [Rational], k: usize) { | fn size_reduce( | ||||||
|  |     mat: &mut Matrix<Integer>, | ||||||
|  |     mu: &mut [Vec<Rational>], | ||||||
|  |     b_star_sq: &mut [Rational], | ||||||
|  |     k: usize, | ||||||
|  | ) { | ||||||
|     let mut updated = true; |     let mut updated = true; | ||||||
|     while updated { |     while updated { | ||||||
|         updated = false; |         updated = false; | ||||||
|   | |||||||
							
								
								
									
										112
									
								
								src/lll.rs
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								src/lll.rs
									
									
									
									
									
								
							| @@ -1,22 +1,122 @@ | |||||||
|  | use lll_rs::vector::BigVector; | ||||||
|  | use lll_rs::matrix::Matrix as LLLMatrix; | ||||||
| use crate::matrix::Matrix; | use crate::matrix::Matrix; | ||||||
| use lll_rs::{matrix::Matrix as LLLMatrix, vector::BigVector}; |  | ||||||
| use rug::{Integer, Rational}; | use rug::{Integer, Rational}; | ||||||
| use std::cmp::max; | use std::cmp::max; | ||||||
| use std::ops::Sub; |  | ||||||
|  |  | ||||||
|  | /// Lattice reduction (L² algorithm, improved LLL) | ||||||
|  | pub fn lattice_reduce(basis: &mut Matrix<Integer>, eta: f64, delta: f64) { | ||||||
|  |     assert!(0.25 < delta && delta < 1.); | ||||||
|  |     assert!(0.5 < eta && eta * eta < delta); | ||||||
|  |     let d = basis.n; | ||||||
|  |     let mut gram: Matrix<Integer> = Matrix::init(d, d); // Gram matrix (upper triangular) | ||||||
|  |     let mut r: Matrix<Rational> = Matrix::init(d, d);   // r_ij matrix | ||||||
|  |     let mut mu: Matrix<Rational> = Matrix::init(d, d);  // Gram coefficient matrix | ||||||
|  |     // Gram matrix | ||||||
|  |     for i in 0..d { | ||||||
|  |         for j in 0..=i { | ||||||
|  |             gram[i][j] = basis[i].clone() * basis[j].clone(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     let eta_minus = Rational::from_f64((eta + 0.5) / 2.).unwrap(); | ||||||
|  |     let delta_plus = Rational::from_f64((delta + 1.) / 2.).unwrap(); | ||||||
|  |  | ||||||
|  |     r[0][0] = Rational::from(&gram[0][0]); | ||||||
|  |     let mut k = 1; | ||||||
|  |     while k < d { | ||||||
|  |         size_reduce( | ||||||
|  |             k, | ||||||
|  |             d, | ||||||
|  |             basis, | ||||||
|  |             &mut gram, | ||||||
|  |             &mut mu, | ||||||
|  |             &mut r, | ||||||
|  |             Rational::from(&eta_minus), | ||||||
|  |         ); | ||||||
|  |         let delta_criterion = Rational::from(&delta_plus * &r[k - 1][k - 1]); | ||||||
|  |         let scalar_criterion = &r[k][k] + Rational::from(&mu[k][k - 1]).square() * &r[k - 1][k - 1]; | ||||||
|  |         // Lovazs condition | ||||||
|  |         if delta_criterion < scalar_criterion { | ||||||
|  |             k += 1; | ||||||
|  |         } else { | ||||||
|  |             basis.swap(k, k - 1); | ||||||
|  |             // Updating Gram matrix | ||||||
|  |             for j in 0..d { | ||||||
|  |                 if j < k { | ||||||
|  |                     gram[k][j] = basis[k].clone() * basis[j].clone(); | ||||||
|  |                     gram[k - 1][j] = basis[k - 1].clone() * basis[j].clone(); | ||||||
|  |                 } else { | ||||||
|  |                     gram[j][k] = basis[k].clone() * basis[j].clone(); | ||||||
|  |                     gram[j][k - 1] = basis[k - 1].clone() * basis[j].clone(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             // Updating mu and r | ||||||
|  |             for i in 0..=k { | ||||||
|  |                 for j in 0..=i { | ||||||
|  |                     r[i][j] = Rational::from(&gram[i][j]) | ||||||
|  |                         - (0..j) | ||||||
|  |                             .map(|index| Rational::from(&mu[j][index] * &r[i][index])) | ||||||
|  |                             .sum::<Rational>(); | ||||||
|  |                     mu[i][j] = Rational::from(&r[i][j] / &r[j][j]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             k = max(1, k - 1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | fn size_reduce( | ||||||
|  |     k: usize, | ||||||
|  |     d: usize, | ||||||
|  |     basis: &mut Matrix<Integer>, | ||||||
|  |     gram: &mut Matrix<Integer>, | ||||||
|  |     mu: &mut Matrix<Rational>, | ||||||
|  |     r: &mut Matrix<Rational>, | ||||||
|  |     eta: Rational, | ||||||
|  | ) { | ||||||
|  |     // Update mu and r | ||||||
|  |     for i in 0..=k { | ||||||
|  |         r[k][i] = Rational::from(&gram[k][i]) | ||||||
|  |             - (0..i) | ||||||
|  |                 .map(|index| Rational::from(&mu[i][index] * &r[k][index])) | ||||||
|  |                 .sum::<Rational>(); | ||||||
|  |         mu[k][i] = Rational::from(&r[k][i] / &r[i][i]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (0..k).any(|index| mu[k][index] > eta) { | ||||||
|  |         for i in (0..k).rev() { | ||||||
|  |             let (_, x) = Rational::from(&mu[k][i]).fract_round(Integer::new()); | ||||||
|  |             basis[k] = basis[k].clone() - basis[i].mul_scalar(&x); | ||||||
|  |             // Updating Gram matrix | ||||||
|  |             for j in 0..d { | ||||||
|  |                 if j < k { | ||||||
|  |                     gram[k][j] = basis[k].clone() * basis[j].clone(); | ||||||
|  |                 } else { | ||||||
|  |                     gram[j][k] = basis[k].clone() * basis[j].clone(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             for j in 0..i { | ||||||
|  |                 let shift = Rational::from(&mu[i][j]); | ||||||
|  |                 mu[k][j] -= Rational::from(&x) * shift; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         size_reduce(k, d, basis, gram, mu, r, eta); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// conversion to LLLMatrix | ||||||
| impl Matrix<Integer> { | impl Matrix<Integer> { | ||||||
|     pub fn to_lll_matrix(&self) -> LLLMatrix<BigVector> { |     pub fn to_lll_matrix(&self) -> LLLMatrix<BigVector> { | ||||||
|         let n = self.n; |         let n = self.n; | ||||||
|         let mut lll_mat = LLLMatrix::init(n, n); |         let mut lll_mat = LLLMatrix::init(n, n); | ||||||
|  |  | ||||||
|         for row_idx in 0..n { |         for row_idx in 0..n { | ||||||
|             let mut elements = Vec::with_capacity(n); |             let mut elements = Vec::with_capacity(n); | ||||||
|  |  | ||||||
|             for col_idx in 0..n { |             for col_idx in 0..n { | ||||||
|                 let val = self[(row_idx, col_idx)].clone(); |                 let val = self[(col_idx, row_idx)].clone(); | ||||||
|                 elements.push(val); |                 elements.push(val); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             lll_mat[row_idx] = BigVector::from_vector(elements); |             lll_mat[row_idx] = BigVector::from_vector(elements); | ||||||
|         } |         } | ||||||
|         lll_mat |         lll_mat | ||||||
|   | |||||||
| @@ -1,9 +1,6 @@ | |||||||
| use crate::vector::Vector; | use crate::vector::Vector; | ||||||
| use rug::{ops::Pow, Integer}; | use rug::{ops::Pow, Integer}; | ||||||
| use std::{ | use std::ops::{Index, IndexMut}; | ||||||
|     fmt, |  | ||||||
|     ops::{Index, IndexMut}, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #[derive(Debug, PartialEq, Clone)] | #[derive(Debug, PartialEq, Clone)] | ||||||
| pub struct Matrix<T> { | pub struct Matrix<T> { | ||||||
| @@ -12,12 +9,19 @@ pub struct Matrix<T> { | |||||||
|     pub columns: Vec<Vector<T>>, |     pub columns: Vec<Vector<T>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T> Matrix<T> { | impl<T: Default> Matrix<T> { | ||||||
|  |     pub fn init(n: usize, m: usize) -> Self { | ||||||
|  |         let mut columns = Vec::with_capacity(n); | ||||||
|  |         for _ in 0..n { | ||||||
|  |             columns.push(Vector::init(m)); | ||||||
|  |         } | ||||||
|  |         Self { n, m, columns } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn new(n: usize, m: usize, values: Vec<T>) -> Option<Self> { |     pub fn new(n: usize, m: usize, values: Vec<T>) -> Option<Self> { | ||||||
|         if n * m != values.len() { |         if n * m != values.len() { | ||||||
|             return None; |             return None; | ||||||
|         } |         } | ||||||
|         // avoid requiring Vec<T>: Clone by building manually |  | ||||||
|         let mut columns = Vec::with_capacity(n); |         let mut columns = Vec::with_capacity(n); | ||||||
|         for _ in 0..n { |         for _ in 0..n { | ||||||
|             columns.push(Vec::with_capacity(m)); |             columns.push(Vec::with_capacity(m)); | ||||||
| @@ -32,6 +36,10 @@ impl<T> Matrix<T> { | |||||||
|             columns: columns.into_iter().map(Vector::from_vec).collect(), |             columns: columns.into_iter().map(Vector::from_vec).collect(), | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn swap(&mut self, i: usize, j: usize) { | ||||||
|  |         self.columns.swap(i, j); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T> Matrix<T> | impl<T> Matrix<T> | ||||||
| @@ -40,19 +48,22 @@ where | |||||||
| { | { | ||||||
|     pub fn new_lattice(noise_bits: usize, ciphertexts: Vec<T>) -> Option<Self> { |     pub fn new_lattice(noise_bits: usize, ciphertexts: Vec<T>) -> Option<Self> { | ||||||
|         let n = ciphertexts.len(); |         let n = ciphertexts.len(); | ||||||
|         let mut columns = vec![Vec::with_capacity(n); n]; |         if n < 1 { | ||||||
|  |             return None; | ||||||
|  |         } | ||||||
|  |         let mut columns = vec![vec![]; n]; | ||||||
|  |  | ||||||
|         // First row: [2^(noise+1), ciphertexts[1], ciphertexts[2], ...] |         // First column: [2^(noise_bits+1), ciphertexts[1], ciphertexts[2], ..., ciphertexts[n-1]] | ||||||
|         let two_pow = Integer::from(2u64).pow((noise_bits + 1) as u32); |         let two_pow = Integer::from(2u64).pow((noise_bits + 1) as u32); | ||||||
|         columns[0].push(T::from(two_pow)); |         columns[0].push(T::from(two_pow)); | ||||||
|         for i in 1..n { |         for i in 1..n { | ||||||
|             columns[i].push(ciphertexts[i].clone()); |             columns[0].push(ciphertexts[i].clone()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Subsequent rows form identity matrix with ciphertexts[0] |         // Subsequent columns: identity matrix with ciphertexts[0] | ||||||
|         for i in 1..n { |         for j in 1..n { | ||||||
|             for (j, column) in columns.iter_mut().enumerate().take(n) { |             for i in 0..n { | ||||||
|                 column.push(if i == j { |                 columns[j].push(if i == j { | ||||||
|                     ciphertexts[0].clone() |                     ciphertexts[0].clone() | ||||||
|                 } else { |                 } else { | ||||||
|                     T::default() |                     T::default() | ||||||
| @@ -89,6 +100,27 @@ impl<T> IndexMut<(usize, usize)> for Matrix<T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl<T> Index<usize> for Matrix<T> { | ||||||
|  |     type Output = Vector<T>; | ||||||
|  |     /// `matrix[col]` yields a `&Vector<T>` representing that column. | ||||||
|  |     fn index(&self, col: usize) -> &Self::Output { | ||||||
|  |         if col >= self.columns.len() { | ||||||
|  |             panic!("Matrix column index out of bounds"); | ||||||
|  |         } | ||||||
|  |         &self.columns[col] | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T> IndexMut<usize> for Matrix<T> { | ||||||
|  |     /// `matrix[col] = …` or `matrix[col][row] = …` to mutate a column (or element). | ||||||
|  |     fn index_mut(&mut self, col: usize) -> &mut Self::Output { | ||||||
|  |         if col >= self.columns.len() { | ||||||
|  |             panic!("Matrix column index out of bounds"); | ||||||
|  |         } | ||||||
|  |         &mut self.columns[col] | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use super::*; |     use super::*; | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ use std::{ | |||||||
|     ops::{Add, Index, IndexMut, Mul, Sub}, |     ops::{Add, Index, IndexMut, Mul, Sub}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #[derive(Clone, PartialEq)] | #[derive(PartialEq)] | ||||||
| pub struct Vector<T> { | pub struct Vector<T> { | ||||||
|     pub elements: Vec<T>, |     pub elements: Vec<T>, | ||||||
| } | } | ||||||
| @@ -44,6 +44,14 @@ where | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl<T: Clone> Clone for Vector<T> { | ||||||
|  |     fn clone(&self) -> Self { | ||||||
|  |         Vector { | ||||||
|  |             elements: self.elements.clone(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl<T> Add for Vector<T> | impl<T> Add for Vector<T> | ||||||
| where | where | ||||||
|     T: Add<Output = T>, |     T: Add<Output = T>, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user