From 4c55a7df444779419b22285d8dcbdd8a0f3f2694 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bossuat Date: Wed, 14 May 2025 16:57:57 +0200 Subject: [PATCH] updated ggsw product noise prediction & added test for ggsw x glwe of rank > 1 --- core/src/test_fft64/ggsw.rs | 5 +- core/src/test_fft64/glwe.rs | 114 +++++++++++++++++++----------------- 2 files changed, 62 insertions(+), 57 deletions(-) diff --git a/core/src/test_fft64/ggsw.rs b/core/src/test_fft64/ggsw.rs index c514ef9..9420831 100644 --- a/core/src/test_fft64/ggsw.rs +++ b/core/src/test_fft64/ggsw.rs @@ -576,6 +576,7 @@ pub(crate) fn noise_rgsw_product( var_a1_err: f64, var_gct_err_lhs: f64, var_gct_err_rhs: f64, + rank: f64, a_logq: usize, b_logq: usize, ) -> f64 { @@ -590,9 +591,9 @@ pub(crate) fn noise_rgsw_product( // lhs = a_cols * n * (var_base * var_gct_err_lhs + var_e_a * var_msg * p^2) // rhs = a_cols * n * var_base * var_gct_err_rhs * var_xs - let mut noise: f64 = 2.0 * (a_cols as f64) * n * var_base * (var_gct_err_lhs + var_xs * var_gct_err_rhs); + let mut noise: f64 = (rank + 1.0) * (a_cols as f64) * n * var_base * (var_gct_err_lhs + var_xs * var_gct_err_rhs); noise += var_msg * var_a0_err * a_scale * a_scale * n; - noise += var_msg * var_a1_err * a_scale * a_scale * n * var_xs; + noise += var_msg * var_a1_err * a_scale * a_scale * n * var_xs * rank; noise = noise.sqrt(); noise /= b_scale; noise.log2().min(-1.0) // max noise is [-2^{-1}, 2^{-1}] diff --git a/core/src/test_fft64/glwe.rs b/core/src/test_fft64/glwe.rs index 5f2c876..008e761 100644 --- a/core/src/test_fft64/glwe.rs +++ b/core/src/test_fft64/glwe.rs @@ -40,6 +40,24 @@ fn encrypt_pk() { }); } +#[test] +fn keyswitch() { + (1..4).for_each(|rank_in| { + (1..4).for_each(|rank_out| { + println!("test keyswitch rank_in: {} rank_out: {}", rank_in, rank_out); + test_keyswitch(12, 12, 60, 45, 60, rank_in, rank_out, 3.2); + }); + }); +} + +#[test] +fn keyswitch_inplace() { + (1..4).for_each(|rank| { + println!("test keyswitch_inplace rank: {}", rank); + test_keyswitch_inplace(12, 12, 60, 45, rank, 3.2); + }); +} + 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); @@ -195,16 +213,6 @@ fn test_encrypt_pk(log_n: usize, basek: usize, k_ct: usize, k_pk: usize, sigma: ); } -#[test] -fn keyswitch() { - (1..4).for_each(|rank_in| { - (1..4).for_each(|rank_out| { - println!("test keyswitch rank_in: {} rank_out: {}", rank_in, rank_out); - test_keyswitch(12, 12, 60, 45, 60, rank_in, rank_out, 3.2); - }); - }); -} - fn test_keyswitch( log_n: usize, basek: usize, @@ -307,21 +315,14 @@ fn test_keyswitch( ); } -#[test] -fn keyswich_inplace() { - let module: Module = Module::::new(2048); - let basek: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe: usize = 45; - let rows: usize = (log_k_rlwe + basek - 1) / basek; - let rank: usize = 1; +fn test_keyswitch_inplace(log_n: usize, basek: usize, k_ksk: usize, k_ct: usize, rank: usize, sigma: f64) { + let module: Module = Module::::new(1 << log_n); + let rows: usize = (k_ct + basek - 1) / basek; - let sigma: f64 = 3.2; - - let mut ct_grlwe: GLWESwitchingKey, FFT64> = GLWESwitchingKey::new(&module, basek, log_k_grlwe, rows, rank, rank); - let mut ct_rlwe: GLWECiphertext> = GLWECiphertext::new(&module, basek, log_k_rlwe, rank); - let mut pt_want: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, log_k_rlwe); - let mut pt_have: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, log_k_rlwe); + let mut ct_grlwe: GLWESwitchingKey, FFT64> = GLWESwitchingKey::new(&module, basek, k_ksk, rows, rank, rank); + let mut ct_rlwe: GLWECiphertext> = GLWECiphertext::new(&module, basek, k_ct, rank); + let mut pt_want: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, k_ct); + let mut pt_have: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, k_ct); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]); @@ -387,8 +388,8 @@ fn keyswich_inplace() { sigma * sigma, 0f64, rank as f64, - log_k_rlwe, - log_k_grlwe, + k_ct, + k_ksk, ); assert!( @@ -401,22 +402,23 @@ fn keyswich_inplace() { #[test] fn external_product() { - let module: Module = Module::::new(2048); - let basek: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe_in: usize = 45; - let log_k_rlwe_out: usize = 60; - let rows: usize = (log_k_rlwe_in + basek - 1) / basek; - let rank: usize = 1; + (1..4).for_each(|rank| { + println!("test external_product rank: {}", rank); + test_external_product(12, 12, 60, 45, 60, rank, 3.2); + }); +} - let sigma: f64 = 3.2; +fn test_external_product(log_n: usize, basek: usize, k_ggsw: usize, k_ct_in: usize, k_ct_out: usize, rank: usize, sigma: f64) { + let module: Module = Module::::new(1 << log_n); - let mut ct_rgsw: GGSWCiphertext, FFT64> = GGSWCiphertext::new(&module, basek, log_k_grlwe, rows, rank); - let mut ct_rlwe_in: GLWECiphertext> = GLWECiphertext::new(&module, basek, log_k_rlwe_in, rank); - let mut ct_rlwe_out: GLWECiphertext> = GLWECiphertext::new(&module, basek, log_k_rlwe_out, rank); + let rows: usize = (k_ct_in + basek - 1) / basek; + + let mut ct_rgsw: GGSWCiphertext, FFT64> = GGSWCiphertext::new(&module, basek, k_ggsw, rows, rank); + let mut ct_rlwe_in: GLWECiphertext> = GLWECiphertext::new(&module, basek, k_ct_in, rank); + let mut ct_rlwe_out: GLWECiphertext> = GLWECiphertext::new(&module, basek, k_ct_out, rank); let mut pt_rgsw: ScalarZnx> = module.new_scalar_znx(1); - let mut pt_want: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, log_k_rlwe_in); - let mut pt_have: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, log_k_rlwe_out); + let mut pt_want: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, k_ct_in); + let mut pt_have: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, k_ct_out); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]); @@ -498,8 +500,9 @@ fn external_product() { var_a1_err, var_gct_err_lhs, var_gct_err_rhs, - log_k_rlwe_in, - log_k_grlwe, + rank as f64, + k_ct_in, + k_ggsw, ); assert!( @@ -512,21 +515,21 @@ fn external_product() { #[test] fn external_product_inplace() { - let module: Module = Module::::new(2048); - let basek: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe_in: usize = 45; - let log_k_rlwe_out: usize = 60; - let rows: usize = (log_k_rlwe_in + basek - 1) / basek; - let rank: usize = 1; + (1..4).for_each(|rank| { + println!("test external_product rank: {}", rank); + test_external_product_inplace(12, 15, 60, 60, rank, 3.2); + }); +} - let sigma: f64 = 3.2; +fn test_external_product_inplace(log_n: usize, basek: usize, k_ggsw: usize, k_ct: usize, rank: usize, sigma: f64) { + let module: Module = Module::::new(1 << log_n); + let rows: usize = (k_ct + basek - 1) / basek; - let mut ct_rgsw: GGSWCiphertext, FFT64> = GGSWCiphertext::new(&module, basek, log_k_grlwe, rows, rank); - let mut ct_rlwe: GLWECiphertext> = GLWECiphertext::new(&module, basek, log_k_rlwe_in, rank); + let mut ct_rgsw: GGSWCiphertext, FFT64> = GGSWCiphertext::new(&module, basek, k_ggsw, rows, rank); + let mut ct_rlwe: GLWECiphertext> = GLWECiphertext::new(&module, basek, k_ct, rank); let mut pt_rgsw: ScalarZnx> = module.new_scalar_znx(1); - let mut pt_want: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, log_k_rlwe_in); - let mut pt_have: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, log_k_rlwe_out); + let mut pt_want: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, k_ct); + let mut pt_have: GLWEPlaintext> = GLWEPlaintext::new(&module, basek, k_ct); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]); @@ -602,8 +605,9 @@ fn external_product_inplace() { var_a1_err, var_gct_err_lhs, var_gct_err_rhs, - log_k_rlwe_in, - log_k_grlwe, + rank as f64, + k_ct, + k_ggsw, ); assert!(