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