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>(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: Backend
 68        + TakeVecZnxDftImpl<B>
 69        + TakeVecZnxBigImpl<B>
 70        + TakeSvpPPolImpl<B>
 71        + ScratchOwnedAllocImpl<B>
 72        + ScratchOwnedBorrowImpl<B>
 73        + ScratchAvailableImpl<B>
 74        + TakeScalarZnxImpl<B>
 75        + TakeVecZnxImpl<B>,
 76{
 77    let mut source_xs: Source = Source::new([0u8; 32]);
 78    let mut source_xe: Source = Source::new([0u8; 32]);
 79    let mut source_xa: Source = Source::new([0u8; 32]);
 80
 81    let n: usize = module.n();
 82    let basek: usize = 18;
 83    let k_ct: usize = 36;
 84    let pt_k: usize = 18;
 85    let rank: usize = 3;
 86    let sigma: f64 = 3.2;
 87    let digits: usize = 1;
 88    let k_ksk: usize = k_ct + basek * digits;
 89
 90    let rows: usize = k_ct.div_ceil(basek * digits);
 91
 92    let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
 93        GLWECiphertext::encrypt_sk_scratch_space(module, n, basek, k_ct)
 94            | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, n, basek, k_ksk, rank)
 95            | GLWEPacker::scratch_space(module, n, basek, k_ct, k_ksk, digits, rank),
 96    );
 97
 98    let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
 99    sk.fill_ternary_prob(0.5, &mut source_xs);
100    let sk_dft: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
101
102    let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
103    let mut data: Vec<i64> = vec![0i64; n];
104    data.iter_mut().enumerate().for_each(|(i, x)| {
105        *x = i as i64;
106    });
107
108    pt.encode_vec_i64(&data, pt_k);
109
110    let gal_els: Vec<i64> = GLWEPacker::galois_elements(module);
111
112    let mut auto_keys: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new();
113    let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_ksk, rows, digits, rank);
114    gal_els.iter().for_each(|gal_el| {
115        tmp.encrypt_sk(
116            module,
117            *gal_el,
118            &sk,
119            &mut source_xa,
120            &mut source_xe,
121            sigma,
122            scratch.borrow(),
123        );
124        let atk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = tmp.prepare_alloc(module, scratch.borrow());
125        auto_keys.insert(*gal_el, atk_prepared);
126    });
127
128    let log_batch: usize = 0;
129
130    let mut packer: GLWEPacker = GLWEPacker::new(n, log_batch, basek, k_ct, rank);
131
132    let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
133
134    ct.encrypt_sk(
135        module,
136        &pt,
137        &sk_dft,
138        &mut source_xa,
139        &mut source_xe,
140        sigma,
141        scratch.borrow(),
142    );
143
144    let log_n: usize = module.log_n();
145
146    (0..n >> log_batch).for_each(|i| {
147        ct.encrypt_sk(
148            module,
149            &pt,
150            &sk_dft,
151            &mut source_xa,
152            &mut source_xe,
153            sigma,
154            scratch.borrow(),
155        );
156
157        pt.rotate_inplace(module, -(1 << log_batch)); // X^-batch * pt
158
159        if reverse_bits_msb(i, log_n as u32).is_multiple_of(5) {
160            packer.add(module, Some(&ct), &auto_keys, scratch.borrow());
161        } else {
162            packer.add(
163                module,
164                None::<&GLWECiphertext<Vec<u8>>>,
165                &auto_keys,
166                scratch.borrow(),
167            )
168        }
169    });
170
171    let mut res = GLWECiphertext::alloc(n, basek, k_ct, rank);
172    packer.flush(module, &mut res);
173
174    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
175    let mut data: Vec<i64> = vec![0i64; n];
176    data.iter_mut().enumerate().for_each(|(i, x)| {
177        if i.is_multiple_of(5) {
178            *x = reverse_bits_msb(i, log_n as u32) as i64;
179        }
180    });
181
182    pt_want.encode_vec_i64(&data, pt_k);
183
184    res.decrypt(module, &mut pt, &sk_dft, scratch.borrow());
185
186    pt.sub_inplace_ab(module, &pt_want);
187
188    let noise_have: f64 = pt.std().log2();
189    // println!("noise_have: {}", noise_have);
190    assert!(
191        noise_have < -((k_ct - basek) as f64),
192        "noise: {}",
193        noise_have
194    );
195}
196
197#[inline(always)]
198fn reverse_bits_msb(x: usize, n: u32) -> usize {
199    x.reverse_bits() >> (usize::BITS - n)
200}