bkz using LLL oracle
This commit is contained in:
14
src/agcd.rs
14
src/agcd.rs
@@ -1,16 +1,21 @@
|
||||
use crate::bkz::bkz_reduce;
|
||||
use crate::matrix::Matrix;
|
||||
use crate::utils::abs;
|
||||
use lll_rs::l2::bigl2;
|
||||
use rug::Integer;
|
||||
|
||||
pub fn agcd(ciphertexts: Vec<Integer>, noise_bits: usize) -> Integer {
|
||||
pub fn agcd(ciphertexts: Vec<Integer>, noise_bits: usize, algorithm: u8) -> Integer {
|
||||
// 1. Build lattice matrix basis
|
||||
let basis_matrix = Matrix::new_lattice(noise_bits, ciphertexts.clone()).unwrap();
|
||||
|
||||
// 2. reduce with LLL
|
||||
let mut lll_matrix = basis_matrix.to_lll_matrix();
|
||||
println!("basis: {:?}", lll_matrix);
|
||||
bigl2::lattice_reduce(&mut lll_matrix, 0.51, 0.75);
|
||||
match algorithm {
|
||||
0u8 => bigl2::lattice_reduce(&mut lll_matrix, 0.51, 0.75),
|
||||
1u8 => bkz_reduce(&mut lll_matrix, 16, 0.75, 0.75, 10),
|
||||
_ => panic!(),
|
||||
}
|
||||
println!("basis after reduction: {:?}", lll_matrix);
|
||||
|
||||
// 3. Extract shortest vector
|
||||
@@ -36,7 +41,10 @@ pub fn agcd(ciphertexts: Vec<Integer>, noise_bits: usize) -> Integer {
|
||||
let p_guess = abs((x0 - r0) / q0);
|
||||
|
||||
println!("Recovered p: {}", p_guess);
|
||||
println!("Approximate GCD with noise_bits={}: {}", noise_bits, p_guess);
|
||||
println!(
|
||||
"Approximate GCD with noise_bits={}: {}",
|
||||
noise_bits, p_guess
|
||||
);
|
||||
|
||||
p_guess
|
||||
}
|
||||
|
122
src/bkz.rs
Normal file
122
src/bkz.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
use lll_rs::vector::Vector;
|
||||
use lll_rs::{l2::bigl2, matrix::Matrix as LLLMatrix, vector::BigVector};
|
||||
use rug::Integer;
|
||||
use std::cmp::min;
|
||||
|
||||
/// Gram-Schmidt orthogonalization
|
||||
fn compute_gram_schmidt(
|
||||
basis: &LLLMatrix<BigVector>,
|
||||
) -> (Vec<BigVector>, Vec<Vec<Integer>>, Vec<Integer>) {
|
||||
let n = basis.dimensions().1;
|
||||
let mut orthogonal = Vec::with_capacity(n);
|
||||
let mut mu = vec![vec![Integer::new(); n]; n];
|
||||
let mut b = Vec::with_capacity(n);
|
||||
|
||||
for i in 0..n {
|
||||
let mut gs = basis[i].clone();
|
||||
for j in 0..i {
|
||||
let numerator = inner_product(&gs, &orthogonal[j]);
|
||||
let denominator: &Integer = &b[j];
|
||||
mu[i][j] = numerator.clone() / denominator.clone();
|
||||
|
||||
gs = gs.sub(&orthogonal[j].clone().mulf(&mu[i][j].clone()));
|
||||
}
|
||||
let norm = inner_product(&gs, &gs);
|
||||
b.push(norm);
|
||||
orthogonal.push(gs);
|
||||
}
|
||||
|
||||
(orthogonal, mu, b)
|
||||
}
|
||||
|
||||
/// BigVectors product
|
||||
fn inner_product(a: &BigVector, b: &BigVector) -> Integer {
|
||||
assert!(a.dimension() == b.dimension());
|
||||
let mut sum = Integer::new();
|
||||
for i in 0..a.dimension() {
|
||||
sum += &a[i] * &b[i];
|
||||
}
|
||||
sum
|
||||
}
|
||||
|
||||
/// vectors orthogonal projection
|
||||
fn project_block(
|
||||
basis: &LLLMatrix<BigVector>,
|
||||
start: usize,
|
||||
end: usize,
|
||||
orthogonal: &[BigVector],
|
||||
mu: &[Vec<Integer>],
|
||||
) -> LLLMatrix<BigVector> {
|
||||
let mut projected = LLLMatrix::init(end - start, basis.dimensions().0);
|
||||
|
||||
for (idx, i) in (start..end).enumerate() {
|
||||
let mut v = basis[i].clone();
|
||||
for (j, ortho_vec) in orthogonal.iter().enumerate().take(start) {
|
||||
let coeff = &mu[i][j];
|
||||
v = v.sub(&ortho_vec.clone().mulf(&coeff.clone()));
|
||||
}
|
||||
|
||||
projected[idx] = v;
|
||||
}
|
||||
|
||||
projected
|
||||
}
|
||||
|
||||
/// BKZ reduction using LLL as SVP‐oracle
|
||||
pub fn bkz_reduce(
|
||||
basis: &mut LLLMatrix<BigVector>,
|
||||
block_size: usize,
|
||||
delta: f64,
|
||||
eta: f64,
|
||||
max_rounds: usize,
|
||||
) {
|
||||
let n = basis.dimensions().1;
|
||||
|
||||
for _ in 0..max_rounds {
|
||||
let (orthogonal, mu, _b) = compute_gram_schmidt(basis);
|
||||
|
||||
for k in 0..n {
|
||||
let l = min(k + block_size, n);
|
||||
if l - k < 2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut projected = project_block(basis, k, l, &orthogonal, &mu);
|
||||
bigl2::lattice_reduce(&mut projected, delta, eta);
|
||||
|
||||
for (i_block, i) in (k..l).enumerate() {
|
||||
basis[i] = projected[i_block].clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
bigl2::lattice_reduce(basis, delta, eta);
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::matrix::Matrix;
|
||||
use rug::Integer;
|
||||
|
||||
#[test]
|
||||
fn test_bkz_reduction() {
|
||||
let ciphertexts = vec![Integer::from(5), Integer::from(8), Integer::from(12)];
|
||||
let noise_bits = 2;
|
||||
|
||||
let basis_matrix = Matrix::new_lattice(noise_bits, ciphertexts).unwrap();
|
||||
let mut lll_matrix = basis_matrix.to_lll_matrix();
|
||||
|
||||
bkz_reduce(&mut lll_matrix, 5, 0.51, 0.75, 3);
|
||||
|
||||
let shortest_vector = &lll_matrix[0];
|
||||
let mut norm = Integer::from(0);
|
||||
for i in 0..=lll_matrix.dimensions().0 - 1 {
|
||||
norm += &shortest_vector[i] * &shortest_vector[i];
|
||||
}
|
||||
assert!(
|
||||
norm > Integer::from(0),
|
||||
"Shortest vector should not be zero"
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
mod agcd;
|
||||
mod bkz;
|
||||
mod file;
|
||||
mod lll;
|
||||
mod matrix;
|
||||
@@ -23,6 +24,9 @@ enum Commands {
|
||||
Agcd {
|
||||
/// (default './input.txt')
|
||||
path: Option<PathBuf>,
|
||||
/// Algorithm variant to use (default: 0)
|
||||
#[arg(short = 'a', long, default_value_t = 0u8)]
|
||||
algorithm: u8,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -30,11 +34,11 @@ fn main() -> std::io::Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
match &cli.command {
|
||||
Commands::Agcd { path } => {
|
||||
Commands::Agcd { path, algorithm } => {
|
||||
let path = path.as_deref().unwrap_or(Path::new("./input.txt"));
|
||||
let input = parse_file(path)?;
|
||||
|
||||
agcd(input.numbers, input.noise_bits);
|
||||
agcd(input.numbers, input.noise_bits, *algorithm);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
Reference in New Issue
Block a user