arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/test_fft64/rgsw.rs
core/src/test_fft64/rgsw.rsRaw
  1#[cfg(test)]
  2mod tests {
  3    use base2k::{
  4        FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxDftOps, ScratchOwned, Stats, VecZnxBig, VecZnxBigAlloc, VecZnxBigOps,
  5        VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxOps, ZnxZero,
  6    };
  7    use sampling::source::Source;
  8
  9    use crate::{
 10        elem::{GetRow, Infos},
 11        keys::{SecretKey, SecretKeyDft},
 12        rgsw::RGSWCt,
 13        rlwe::{RLWECt, RLWECtDft, RLWEPt},
 14        test_fft64::rgsw::noise_rgsw_rlwe_product,
 15    };
 16
 17    #[test]
 18    fn encrypt_rgsw_sk() {
 19        let module: Module<FFT64> = Module::<FFT64>::new(2048);
 20        let log_base2k: usize = 8;
 21        let log_k_ct: usize = 54;
 22        let rows: usize = 4;
 23
 24        let sigma: f64 = 3.2;
 25        let bound: f64 = sigma * 6.0;
 26
 27        let mut ct: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_ct, rows);
 28        let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct);
 29        let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct);
 30        let mut pt_scalar: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1);
 31
 32        let mut source_xs: Source = Source::new([0u8; 32]);
 33        let mut source_xe: Source = Source::new([0u8; 32]);
 34        let mut source_xa: Source = Source::new([0u8; 32]);
 35
 36        pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs);
 37
 38        let mut scratch: ScratchOwned = ScratchOwned::new(
 39            RGSWCt::encrypt_sk_scratch_space(&module, ct.size()) | RLWECtDft::decrypt_scratch_space(&module, ct.size()),
 40        );
 41
 42        let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module);
 43        sk.fill_ternary_prob(0.5, &mut source_xs);
 44
 45        let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module);
 46        sk_dft.dft(&module, &sk);
 47
 48        ct.encrypt_sk(
 49            &module,
 50            &pt_scalar,
 51            &sk_dft,
 52            &mut source_xa,
 53            &mut source_xe,
 54            sigma,
 55            bound,
 56            scratch.borrow(),
 57        );
 58
 59        let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_ct);
 60        let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct.size());
 61        let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct.size());
 62
 63        (0..ct.cols()).for_each(|col_j| {
 64            (0..ct.rows()).for_each(|row_i| {
 65                module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_scalar, 0);
 66
 67                if col_j == 1 {
 68                    module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0);
 69                    module.svp_apply_inplace(&mut pt_dft, 0, &sk_dft, 0);
 70                    module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0);
 71                    module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow());
 72                }
 73
 74                ct.get_row(&module, row_i, col_j, &mut ct_rlwe_dft);
 75
 76                ct_rlwe_dft.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow());
 77
 78                module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0);
 79
 80                let std_pt: f64 = pt_have.data.std(0, log_base2k) * (log_k_ct as f64).exp2();
 81                assert!((sigma - std_pt).abs() <= 0.2, "{} {}", sigma, std_pt);
 82
 83                pt_want.data.zero();
 84            });
 85        });
 86
 87        module.free();
 88    }
 89}
 90
 91#[allow(dead_code)]
 92pub(crate) fn noise_rgsw_rlwe_product(
 93    n: f64,
 94    log_base2k: usize,
 95    var_xs: f64,
 96    var_msg: f64,
 97    var_a0_err: f64,
 98    var_a1_err: f64,
 99    var_gct_err_lhs: f64,
100    var_gct_err_rhs: f64,
101    a_logq: usize,
102    b_logq: usize,
103) -> f64 {
104    let a_logq: usize = a_logq.min(b_logq);
105    let a_cols: usize = (a_logq + log_base2k - 1) / log_base2k;
106
107    let b_scale = 2.0f64.powi(b_logq as i32);
108    let a_scale: f64 = 2.0f64.powi((b_logq - a_logq) as i32);
109
110    let base: f64 = (1 << (log_base2k)) as f64;
111    let var_base: f64 = base * base / 12f64;
112
113    // lhs = a_cols * n * (var_base * var_gct_err_lhs + var_e_a * var_msg * p^2)
114    // rhs = a_cols * n * var_base * var_gct_err_rhs * var_xs
115    let mut noise: f64 = 2.0 * (a_cols as f64) * n * var_base * (var_gct_err_lhs + var_xs * var_gct_err_rhs);
116    noise += var_msg * var_a0_err * a_scale * a_scale * n;
117    noise += var_msg * var_a1_err * a_scale * a_scale * n * var_xs;
118    noise = noise.sqrt();
119    noise /= b_scale;
120    noise.log2().min(-1.0) // max noise is [-2^{-1}, 2^{-1}]
121}