arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/test_fft64/glwe_packing.rs
core/src/test_fft64/glwe_packing.rsRaw
  1use crate::{AutomorphismKey, GLWECiphertext, GLWEOps, GLWEPlaintext, GLWESecret, StreamPacker};
  2use std::collections::HashMap;
  3
  4use backend::{Encoding, FFT64, Module, ScratchOwned, Stats};
  5use sampling::source::Source;
  6
  7#[test]
  8fn packing() {
  9    let log_n: usize = 5;
 10    let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
 11
 12    let mut source_xs: Source = Source::new([0u8; 32]);
 13    let mut source_xe: Source = Source::new([0u8; 32]);
 14    let mut source_xa: Source = Source::new([0u8; 32]);
 15
 16    let basek: usize = 18;
 17    let k_ct: usize = 36;
 18    let pt_k: usize = 18;
 19    let rank: usize = 3;
 20    let sigma: f64 = 3.2;
 21    let digits: usize = 1;
 22    let k_ksk: usize = k_ct + basek * digits;
 23
 24    let rows: usize = k_ct.div_ceil(basek * digits);
 25
 26    let mut scratch: ScratchOwned = ScratchOwned::new(
 27        GLWECiphertext::encrypt_sk_scratch_space(&module, basek, k_ct)
 28            | GLWECiphertext::decrypt_scratch_space(&module, basek, k_ct)
 29            | AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_ksk, rank)
 30            | StreamPacker::scratch_space(&module, basek, k_ct, k_ksk, digits, rank),
 31    );
 32
 33    let mut sk: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
 34    sk.fill_ternary_prob(&module, 0.5, &mut source_xs);
 35
 36    let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct);
 37    let mut data: Vec<i64> = vec![0i64; module.n()];
 38    data.iter_mut().enumerate().for_each(|(i, x)| {
 39        *x = i as i64;
 40    });
 41    pt.data.encode_vec_i64(0, basek, pt_k, &data, 32);
 42
 43    let gal_els: Vec<i64> = StreamPacker::galois_elements(&module);
 44
 45    let mut auto_keys: HashMap<i64, AutomorphismKey<Vec<u8>, FFT64>> = HashMap::new();
 46    gal_els.iter().for_each(|gal_el| {
 47        let mut key: AutomorphismKey<Vec<u8>, FFT64> = AutomorphismKey::alloc(&module, basek, k_ksk, rows, digits, rank);
 48        key.generate_from_sk(
 49            &module,
 50            *gal_el,
 51            &sk,
 52            &mut source_xa,
 53            &mut source_xe,
 54            sigma,
 55            scratch.borrow(),
 56        );
 57        auto_keys.insert(*gal_el, key);
 58    });
 59
 60    let log_batch: usize = 0;
 61
 62    let mut packer: StreamPacker = StreamPacker::new(&module, log_batch, basek, k_ct, rank);
 63
 64    let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_ct, rank);
 65
 66    ct.encrypt_sk(
 67        &module,
 68        &pt,
 69        &sk,
 70        &mut source_xa,
 71        &mut source_xe,
 72        sigma,
 73        scratch.borrow(),
 74    );
 75
 76    let mut res: Vec<GLWECiphertext<Vec<u8>>> = Vec::new();
 77
 78    (0..module.n() >> log_batch).for_each(|i| {
 79        ct.encrypt_sk(
 80            &module,
 81            &pt,
 82            &sk,
 83            &mut source_xa,
 84            &mut source_xe,
 85            sigma,
 86            scratch.borrow(),
 87        );
 88
 89        pt.rotate_inplace(&module, -(1 << log_batch)); // X^-batch * pt
 90
 91        if reverse_bits_msb(i, log_n as u32) % 5 == 0 {
 92            packer.add(&module, &mut res, Some(&ct), &auto_keys, scratch.borrow());
 93        } else {
 94            packer.add(
 95                &module,
 96                &mut res,
 97                None::<&GLWECiphertext<Vec<u8>>>,
 98                &auto_keys,
 99                scratch.borrow(),
100            )
101        }
102    });
103
104    packer.flush(&module, &mut res, &auto_keys, scratch.borrow());
105    packer.reset();
106
107    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct);
108
109    res.iter().enumerate().for_each(|(i, res_i)| {
110        let mut data: Vec<i64> = vec![0i64; module.n()];
111        data.iter_mut().enumerate().for_each(|(i, x)| {
112            if i % 5 == 0 {
113                *x = reverse_bits_msb(i, log_n as u32) as i64;
114            }
115        });
116        pt_want.data.encode_vec_i64(0, basek, pt_k, &data, 32);
117
118        res_i.decrypt(&module, &mut pt, &sk, scratch.borrow());
119
120        if i & 1 == 0 {
121            pt.sub_inplace_ab(&module, &pt_want);
122        } else {
123            pt.add_inplace(&module, &pt_want);
124        }
125
126        let noise_have = pt.data.std(0, basek).log2();
127        // println!("noise_have: {}", noise_have);
128        assert!(
129            noise_have < -((k_ct - basek) as f64),
130            "noise: {}",
131            noise_have
132        );
133    });
134}
135
136#[inline(always)]
137fn reverse_bits_msb(x: usize, n: u32) -> usize {
138    x.reverse_bits() >> (usize::BITS - n)
139}