use rug::Integer

This commit is contained in:
Sam Hadow 2025-04-02 17:39:42 +02:00
parent 0c0049194e
commit 7bc9d1f735
2 changed files with 39 additions and 21 deletions

View File

@ -6,3 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
lll-rs = "0.2.0"
rug = "1.27.0"

View File

@ -1,7 +1,14 @@
type Element = f64; use rug::ops::Pow;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
type Element = rug::Integer;
macro_rules! int {
($x:expr) => {
rug::Integer::from($x)
};
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Matrix { pub struct Matrix {
pub n: usize, pub n: usize,
@ -22,14 +29,14 @@ impl Matrix {
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, ciphertexts[1], ..., ciphertexts[t]]
values.push((2.0f64).powi(noise_bits as i32)); values.push(int!(2u64).pow(noise_bits as u32));
values.extend_from_slice(&ciphertexts[1..]); values.extend_from_slice(&ciphertexts[1..]);
// -x0 on diagonal, 0 everywhere else // -x0 on diagonal, 0 everywhere else
let x0 = ciphertexts[0]; let x0 = &ciphertexts[0];
for i in 0..n - 1 { for i in 0..n - 1 {
let mut row = vec![0.0; n]; let mut row = vec![int!(0); n];
row[i] = -x0; row[i] = -x0.clone();
values.extend(row); values.extend(row);
} }
@ -38,7 +45,7 @@ impl Matrix {
} }
impl Index<(usize, usize)> for Matrix { impl Index<(usize, usize)> for Matrix {
type Output = f64; type Output = Element;
fn index(&self, index: (usize, usize)) -> &Self::Output { fn index(&self, index: (usize, usize)) -> &Self::Output {
&self.values[(self.n * index.0) + index.1] &self.values[(self.n * index.0) + index.1]
} }
@ -58,31 +65,40 @@ mod tests {
assert_eq!( assert_eq!(
Matrix { Matrix {
n: 2, n: 2,
values: Vec::from([1.0, 2.0, 3.0, 4.0]) values: vec![int!(1), int!(2), int!(3), int!(4)],
}, },
Matrix::new(2, Vec::from([1.0, 2.0, 3.0, 4.0])).unwrap() Matrix::new(2, vec![int!(1), int!(2), int!(3), int!(4)]).unwrap()
); );
assert!(Matrix::new(3, Vec::from([1.0, 2.0])).is_none()); assert!(Matrix::new(3, vec![int!(1), int!(2)]).is_none());
} }
#[test] #[test]
fn indexes() { fn indexes() {
let mut m = Matrix::new(2, vec![1.0, 2.0, 3.0, 4.0]).unwrap(); let mut m = Matrix::new(2, vec![int!(1), int!(2), int!(3), int!(4)]).unwrap();
assert_eq!(m[(0, 0)], 1.0);
assert_eq!(m[(1, 0)], 3.0);
m[(1, 0)] = 5.0; assert_eq!(m[(0, 0)], int!(1));
assert_eq!(m[(1, 0)], 5.0); assert_eq!(m[(1, 0)], int!(3));
m[(1, 0)] = int!(5);
assert_eq!(m[(1, 0)], int!(5));
} }
#[test] #[test]
fn test_new_lattice() { fn test_new_lattice() {
let ciphertexts = vec![5.0, 8.0, 12.0]; // x0=5.0, x1=8.0, x2=12.0 let ciphertexts = vec![int!(5), int!(8), int!(12)];
let noise_bits = 2; let noise_bits = 2;
// Expected matrix (3x3): let expected_values = vec![
// [ 2^2, x1, x2 ] = [4.0, 8.0, 12.0] int!(4),
// [ -x0, 0, 0 ] = [-5.0, 0.0, 0.0] int!(8),
// [ 0, -x0, 0 ] = [0.0, -5.0, 0.0] int!(12),
let expected_values = vec![4.0, 8.0, 12.0, -5.0, 0.0, 0.0, 0.0, -5.0, 0.0]; int!(-5),
int!(0),
int!(0),
int!(0),
int!(-5),
int!(0),
];
let lattice = Matrix::new_lattice(noise_bits, ciphertexts).unwrap(); let lattice = Matrix::new_lattice(noise_bits, ciphertexts).unwrap();
assert_eq!(lattice.n, 3); assert_eq!(lattice.n, 3);