SDA lattice attack, need to fix LLL part

This commit is contained in:
Sam Hadow 2025-04-04 10:15:20 +02:00
parent 1620037cd1
commit 6dc394c162
3 changed files with 73 additions and 9 deletions

22
src/lll.rs Normal file
View File

@ -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<BigVector> {
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
}
}

View File

@ -1,5 +1,42 @@
use rug::Integer;
use crate::matrix::Matrix;
use lll_rs::lll::biglll;
mod lll;
mod matrix; mod matrix;
fn main() { 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);
} }

View File

@ -11,14 +11,14 @@ macro_rules! int {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Matrix { pub struct Matrix {
pub n: usize, //rows pub n: usize, // rows
pub m: usize, // columns pub m: usize, // columns
values: Vec<Element>, values: Vec<Element>,
} }
impl Matrix { impl Matrix {
pub fn new(n: usize, m: usize, values: Vec<Element>) -> Option<Self> { pub fn new(n: usize, m: usize, values: Vec<Element>) -> Option<Self> {
if n*m == values.len() { if n * m == values.len() {
Some(Matrix { n, m, values }) Some(Matrix { n, m, values })
} else { } else {
None None
@ -29,8 +29,8 @@ impl Matrix {
let n = ciphertexts.len(); let n = ciphertexts.len();
let mut values = Vec::with_capacity(n * n); let mut values = Vec::with_capacity(n * n);
// First row: [2^noise_bits, ciphertexts[1], ..., ciphertexts[t]] // First row: [2^(noise_bits+1), ciphertexts[1], ..., ciphertexts[t]]
values.push(int!(2u64).pow(noise_bits as u32)); values.push(int!(2u64).pow(noise_bits as u32 + 1));
values.extend_from_slice(&ciphertexts[1..]); values.extend_from_slice(&ciphertexts[1..]);
// -x0 on diagonal, 0 everywhere else // -x0 on diagonal, 0 everywhere else
@ -48,7 +48,7 @@ impl Matrix {
impl Index<(usize, usize)> for Matrix { impl Index<(usize, usize)> for Matrix {
type Output = Element; type Output = Element;
fn index(&self, index: (usize, usize)) -> &Self::Output { 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!(); panic!();
} }
&self.values[(self.n * index.0) + index.1] &self.values[(self.n * index.0) + index.1]
@ -57,7 +57,7 @@ impl Index<(usize, usize)> for Matrix {
impl IndexMut<(usize, usize)> for Matrix { impl IndexMut<(usize, usize)> for Matrix {
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output { 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!(); panic!();
} }
&mut self.values[(self.n * index.0) + index.1] &mut self.values[(self.n * index.0) + index.1]
@ -91,7 +91,12 @@ mod tests {
m[(1, 0)] = int!(5); m[(1, 0)] = int!(5);
assert_eq!(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[(0, 2)], int!(3));
assert_eq!(m2[(1, 0)], int!(4)); assert_eq!(m2[(1, 0)], int!(4));
let result = panic::catch_unwind(|| { let result = panic::catch_unwind(|| {
@ -111,7 +116,7 @@ mod tests {
let noise_bits = 2; let noise_bits = 2;
let expected_values = vec![ let expected_values = vec![
int!(4), int!(8),
int!(8), int!(8),
int!(12), int!(12),
int!(0), int!(0),