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