From 4d4b43a4e52e53550fe8f4021e482220be31640c Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bossuat Date: Fri, 13 Jun 2025 09:20:14 +0200 Subject: [PATCH] Re-organized code for glwe testing --- core/src/glwe/mod.rs | 3 + core/src/glwe/test_fft64/automorphism.rs | 1 + core/src/glwe/test_fft64/encryption.rs | 180 ++++++++++++++++++ .../test_fft64/external_product.rs} | 0 core/src/glwe/test_fft64/keyswitch.rs | 1 + core/src/glwe/test_fft64/mod.rs | 6 + .../test_fft64/packing.rs} | 0 core/src/{ => glwe}/test_fft64/trace.rs | 0 core/src/test_fft64/mod.rs | 3 - 9 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 core/src/glwe/test_fft64/automorphism.rs create mode 100644 core/src/glwe/test_fft64/encryption.rs rename core/src/{test_fft64/glwe.rs => glwe/test_fft64/external_product.rs} (100%) create mode 100644 core/src/glwe/test_fft64/keyswitch.rs create mode 100644 core/src/glwe/test_fft64/mod.rs rename core/src/{test_fft64/glwe_packing.rs => glwe/test_fft64/packing.rs} (100%) rename core/src/{ => glwe}/test_fft64/trace.rs (100%) diff --git a/core/src/glwe/mod.rs b/core/src/glwe/mod.rs index ed3395d..7f0c7aa 100644 --- a/core/src/glwe/mod.rs +++ b/core/src/glwe/mod.rs @@ -29,3 +29,6 @@ pub use public_key::*; pub use secret::*; #[allow(unused_imports)] pub use trace::*; + +#[cfg(test)] +mod test_fft64; diff --git a/core/src/glwe/test_fft64/automorphism.rs b/core/src/glwe/test_fft64/automorphism.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/core/src/glwe/test_fft64/automorphism.rs @@ -0,0 +1 @@ + diff --git a/core/src/glwe/test_fft64/encryption.rs b/core/src/glwe/test_fft64/encryption.rs new file mode 100644 index 0000000..06490c5 --- /dev/null +++ b/core/src/glwe/test_fft64/encryption.rs @@ -0,0 +1,180 @@ +use backend::{Decoding, Encoding, FFT64, Module, ScratchOwned, Stats, VecZnxOps, ZnxZero}; +use itertools::izip; +use sampling::source::Source; + +use crate::{FourierGLWECiphertext, GLWECiphertext, GLWEPlaintext, GLWEPublicKey, GLWESecret, Infos}; + +#[test] +fn encrypt_sk() { + let log_n: usize = 8; + (1..4).for_each(|rank| { + println!("test encrypt_sk rank: {}", rank); + test_encrypt_sk(log_n, 8, 54, 30, 3.2, rank); + }); +} + +#[test] +fn encrypt_zero_sk() { + let log_n: usize = 8; + (1..4).for_each(|rank| { + println!("test encrypt_zero_sk rank: {}", rank); + test_encrypt_zero_sk(log_n, 8, 64, 3.2, rank); + }); +} + +#[test] +fn encrypt_pk() { + let log_n: usize = 8; + (1..4).for_each(|rank| { + println!("test encrypt_pk rank: {}", rank); + test_encrypt_pk(log_n, 8, 64, 64, 3.2, rank) + }); +} + +fn test_encrypt_sk(log_n: usize, basek: usize, k_ct: usize, k_pt: usize, sigma: f64, rank: usize) { + let module: Module = Module::::new(1 << log_n); + + let mut ct: GLWECiphertext> = GLWECiphertext::alloc(&module, basek, k_ct, rank); + let mut pt: GLWEPlaintext> = GLWEPlaintext::alloc(&module, basek, k_pt); + + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); + + let mut scratch: ScratchOwned = ScratchOwned::new( + GLWECiphertext::encrypt_sk_scratch_space(&module, basek, ct.k()) + | GLWECiphertext::decrypt_scratch_space(&module, basek, ct.k()), + ); + + let mut sk: GLWESecret, FFT64> = GLWESecret::alloc(&module, rank); + sk.fill_ternary_prob(&module, 0.5, &mut source_xs); + + let mut data_want: Vec = vec![0i64; module.n()]; + + data_want + .iter_mut() + .for_each(|x| *x = source_xa.next_i64() & 0xFF); + + pt.data.encode_vec_i64(0, basek, k_pt, &data_want, 10); + + ct.encrypt_sk( + &module, + &pt, + &sk, + &mut source_xa, + &mut source_xe, + sigma, + scratch.borrow(), + ); + + pt.data.zero(); + + ct.decrypt(&module, &mut pt, &sk, scratch.borrow()); + + let mut data_have: Vec = vec![0i64; module.n()]; + + pt.data + .decode_vec_i64(0, basek, pt.size() * basek, &mut data_have); + + // TODO: properly assert the decryption noise through std(dec(ct) - pt) + let scale: f64 = (1 << (pt.size() * basek - k_pt)) as f64; + izip!(data_want.iter(), data_have.iter()).for_each(|(a, b)| { + let b_scaled = (*b as f64) / scale; + assert!( + (*a as f64 - b_scaled).abs() < 0.1, + "{} {}", + *a as f64, + b_scaled + ) + }); +} + +fn test_encrypt_zero_sk(log_n: usize, basek: usize, k_ct: usize, sigma: f64, rank: usize) { + let module: Module = Module::::new(1 << log_n); + + let mut pt: GLWEPlaintext> = GLWEPlaintext::alloc(&module, basek, k_ct); + + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([1u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); + + let mut sk: GLWESecret, FFT64> = GLWESecret::alloc(&module, rank); + sk.fill_ternary_prob(&module, 0.5, &mut source_xs); + + let mut ct_dft: FourierGLWECiphertext, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_ct, rank); + + let mut scratch: ScratchOwned = ScratchOwned::new( + FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_ct) + | FourierGLWECiphertext::encrypt_sk_scratch_space(&module, basek, k_ct, rank), + ); + + ct_dft.encrypt_zero_sk( + &module, + &sk, + &mut source_xa, + &mut source_xe, + sigma, + scratch.borrow(), + ); + ct_dft.decrypt(&module, &mut pt, &sk, scratch.borrow()); + + assert!((sigma - pt.data.std(0, basek) * (k_ct as f64).exp2()) <= 0.2); +} + +fn test_encrypt_pk(log_n: usize, basek: usize, k_ct: usize, k_pk: usize, sigma: f64, rank: usize) { + let module: Module = Module::::new(1 << log_n); + + let mut ct: GLWECiphertext> = GLWECiphertext::alloc(&module, basek, k_ct, rank); + let mut pt_want: GLWEPlaintext> = GLWEPlaintext::alloc(&module, basek, k_ct); + + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xu: Source = Source::new([0u8; 32]); + + let mut sk: GLWESecret, FFT64> = GLWESecret::alloc(&module, rank); + sk.fill_ternary_prob(&module, 0.5, &mut source_xs); + + let mut pk: GLWEPublicKey, FFT64> = GLWEPublicKey::alloc(&module, basek, k_pk, rank); + pk.generate_from_sk(&module, &sk, &mut source_xa, &mut source_xe, sigma); + + let mut scratch: ScratchOwned = ScratchOwned::new( + GLWECiphertext::encrypt_sk_scratch_space(&module, basek, ct.k()) + | GLWECiphertext::decrypt_scratch_space(&module, basek, ct.k()) + | GLWECiphertext::encrypt_pk_scratch_space(&module, basek, pk.k()), + ); + + let mut data_want: Vec = vec![0i64; module.n()]; + + data_want + .iter_mut() + .for_each(|x| *x = source_xa.next_i64() & 0); + + pt_want.data.encode_vec_i64(0, basek, k_ct, &data_want, 10); + + ct.encrypt_pk( + &module, + &pt_want, + &pk, + &mut source_xu, + &mut source_xe, + sigma, + scratch.borrow(), + ); + + let mut pt_have: GLWEPlaintext> = GLWEPlaintext::alloc(&module, basek, k_ct); + + ct.decrypt(&module, &mut pt_have, &sk, scratch.borrow()); + + module.vec_znx_sub_ab_inplace(&mut pt_want.data, 0, &pt_have.data, 0); + + let noise_have: f64 = pt_want.data.std(0, basek).log2(); + let noise_want: f64 = ((((rank as f64) + 1.0) * module.n() as f64 * 0.5 * sigma * sigma).sqrt()).log2() - (k_ct as f64); + + assert!( + (noise_have - noise_want).abs() < 0.2, + "{} {}", + noise_have, + noise_want + ); +} diff --git a/core/src/test_fft64/glwe.rs b/core/src/glwe/test_fft64/external_product.rs similarity index 100% rename from core/src/test_fft64/glwe.rs rename to core/src/glwe/test_fft64/external_product.rs diff --git a/core/src/glwe/test_fft64/keyswitch.rs b/core/src/glwe/test_fft64/keyswitch.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/core/src/glwe/test_fft64/keyswitch.rs @@ -0,0 +1 @@ + diff --git a/core/src/glwe/test_fft64/mod.rs b/core/src/glwe/test_fft64/mod.rs new file mode 100644 index 0000000..e3f5425 --- /dev/null +++ b/core/src/glwe/test_fft64/mod.rs @@ -0,0 +1,6 @@ +pub mod automorphism; +pub mod encryption; +pub mod external_product; +pub mod keyswitch; +pub mod packing; +pub mod trace; diff --git a/core/src/test_fft64/glwe_packing.rs b/core/src/glwe/test_fft64/packing.rs similarity index 100% rename from core/src/test_fft64/glwe_packing.rs rename to core/src/glwe/test_fft64/packing.rs diff --git a/core/src/test_fft64/trace.rs b/core/src/glwe/test_fft64/trace.rs similarity index 100% rename from core/src/test_fft64/trace.rs rename to core/src/glwe/test_fft64/trace.rs diff --git a/core/src/test_fft64/mod.rs b/core/src/test_fft64/mod.rs index 73a58e9..4c0f513 100644 --- a/core/src/test_fft64/mod.rs +++ b/core/src/test_fft64/mod.rs @@ -1,11 +1,8 @@ mod automorphism_key; mod gglwe; mod ggsw; -mod glwe; mod glwe_fourier; -mod glwe_packing; mod tensor_key; -mod trace; pub(crate) fn var_noise_gglwe_product( n: f64,