arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/tests/generics/packing.rs
core/src/tests/generics/packing.rsRaw
  1use std::collections::HashMap;
  2
  3use backend::hal::{
  4    api::{
  5        ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, VecZnxAddInplace,
  6        VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxBigAddInplace,
  7        VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, VecZnxBigNormalize,
  8        VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallBInplace, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftFromVecZnx,
  9        VecZnxDftToVecZnxBigConsume, VecZnxFillUniform, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace,
 10        VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, VecZnxSubABInplace,
 11        VecZnxSwithcDegree, VmpApply, VmpApplyAdd, VmpApplyTmpBytes, VmpPMatAlloc, VmpPrepare,
 12    },
 13    layouts::{Backend, Module, ScratchOwned},
 14    oep::{
 15        ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl,
 16        TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl,
 17    },
 18};
 19use sampling::source::Source;
 20
 21use crate::{
 22    GLWEOperations, GLWEPacker,
 23    layouts::{
 24        GGLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret,
 25        prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, PrepareAlloc},
 26    },
 27};
 28
 29pub fn test_glwe_packing<B: Backend>(module: &Module<B>)
 30where
 31    Module<B>: VecZnxDftAllocBytes
 32        + VecZnxAutomorphism
 33        + VecZnxBigAutomorphismInplace<B>
 34        + VecZnxBigSubSmallBInplace<B>
 35        + VecZnxNegateInplace
 36        + VecZnxRshInplace
 37        + VecZnxRotateInplace
 38        + VecZnxBigNormalize<B>
 39        + VecZnxDftFromVecZnx<B>
 40        + VecZnxRotate
 41        + SvpApplyInplace<B>
 42        + VecZnxDftToVecZnxBigConsume<B>
 43        + VecZnxFillUniform
 44        + VecZnxSubABInplace
 45        + VecZnxAddInplace
 46        + VecZnxNormalizeInplace<B>
 47        + VecZnxAddNormal
 48        + VecZnxNormalize<B>
 49        + VecZnxSub
 50        + SvpPrepare<B>
 51        + SvpPPolAllocBytes
 52        + SvpPPolAlloc<B>
 53        + VecZnxBigAllocBytes
 54        + VecZnxBigAddInplace<B>
 55        + VecZnxBigAddSmallInplace<B>
 56        + VecZnxNormalizeTmpBytes
 57        + VecZnxAddScalarInplace
 58        + VmpPMatAlloc<B>
 59        + VmpPrepare<B>
 60        + VmpApplyTmpBytes
 61        + VmpApply<B>
 62        + VmpApplyAdd<B>
 63        + VecZnxBigNormalizeTmpBytes
 64        + VecZnxSwithcDegree
 65        + VecZnxAutomorphismInplace
 66        + VecZnxCopy,
 67    B: TakeVecZnxDftImpl<B>
 68        + TakeVecZnxBigImpl<B>
 69        + TakeSvpPPolImpl<B>
 70        + ScratchOwnedAllocImpl<B>
 71        + ScratchOwnedBorrowImpl<B>
 72        + ScratchAvailableImpl<B>
 73        + TakeScalarZnxImpl<B>
 74        + TakeVecZnxImpl<B>,
 75{
 76    let mut source_xs: Source = Source::new([0u8; 32]);
 77    let mut source_xe: Source = Source::new([0u8; 32]);
 78    let mut source_xa: Source = Source::new([0u8; 32]);
 79
 80    let n: usize = module.n();
 81    let basek: usize = 18;
 82    let k_ct: usize = 36;
 83    let pt_k: usize = 18;
 84    let rank: usize = 3;
 85    let sigma: f64 = 3.2;
 86    let digits: usize = 1;
 87    let k_ksk: usize = k_ct + basek * digits;
 88
 89    let rows: usize = k_ct.div_ceil(basek * digits);
 90
 91    let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
 92        GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, k_ct)
 93            | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, n, basek, k_ksk, rank)
 94            | GLWEPacker::scratch_space(module, n, basek, k_ct, k_ksk, digits, rank),
 95    );
 96
 97    let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
 98    sk.fill_ternary_prob(0.5, &mut source_xs);
 99    let sk_dft: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
100
101    let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
102    let mut data: Vec<i64> = vec![0i64; n];
103    data.iter_mut().enumerate().for_each(|(i, x)| {
104        *x = i as i64;
105    });
106
107    pt.encode_vec_i64(&data, pt_k);
108
109    let gal_els: Vec<i64> = GLWEPacker::galois_elements(module);
110
111    let mut auto_keys: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new();
112    let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_ksk, rows, digits, rank);
113    gal_els.iter().for_each(|gal_el| {
114        tmp.encrypt_sk(
115            module,
116            *gal_el,
117            &sk,
118            &mut source_xa,
119            &mut source_xe,
120            sigma,
121            scratch.borrow(),
122        );
123        let atk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = tmp.prepare_alloc(module, scratch.borrow());
124        auto_keys.insert(*gal_el, atk_prepared);
125    });
126
127    let log_batch: usize = 0;
128
129    let mut packer: GLWEPacker = GLWEPacker::new(n, log_batch, basek, k_ct, rank);
130
131    let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
132
133    ct.encrypt_sk(
134        module,
135        &pt,
136        &sk_dft,
137        &mut source_xa,
138        &mut source_xe,
139        sigma,
140        scratch.borrow(),
141    );
142
143    let log_n: usize = module.log_n();
144
145    (0..n >> log_batch).for_each(|i| {
146        ct.encrypt_sk(
147            module,
148            &pt,
149            &sk_dft,
150            &mut source_xa,
151            &mut source_xe,
152            sigma,
153            scratch.borrow(),
154        );
155
156        pt.rotate_inplace(module, -(1 << log_batch)); // X^-batch * pt
157
158        if reverse_bits_msb(i, log_n as u32) % 5 == 0 {
159            packer.add(module, Some(&ct), &auto_keys, scratch.borrow());
160        } else {
161            packer.add(
162                module,
163                None::<&GLWECiphertext<Vec<u8>>>,
164                &auto_keys,
165                scratch.borrow(),
166            )
167        }
168    });
169
170    let mut res = GLWECiphertext::alloc(n, basek, k_ct, rank);
171    packer.flush(module, &mut res);
172
173    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
174    let mut data: Vec<i64> = vec![0i64; n];
175    data.iter_mut().enumerate().for_each(|(i, x)| {
176        if i % 5 == 0 {
177            *x = reverse_bits_msb(i, log_n as u32) as i64;
178        }
179    });
180
181    pt_want.encode_vec_i64(&data, pt_k);
182
183    res.decrypt(module, &mut pt, &sk_dft, scratch.borrow());
184
185    pt.sub_inplace_ab(module, &pt_want);
186
187    let noise_have: f64 = pt.std().log2();
188    // println!("noise_have: {}", noise_have);
189    assert!(
190        noise_have < -((k_ct - basek) as f64),
191        "noise: {}",
192        noise_have
193    );
194}
195
196#[inline(always)]
197fn reverse_bits_msb(x: usize, n: u32) -> usize {
198    x.reverse_bits() >> (usize::BITS - n)
199}