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