arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/schemes/src/tfhe/blind_rotation/tests/generic_blind_rotation.rs
schemes/src/tfhe/blind_rotation/tests/generic_blind_rotation.rsRaw
  1use backend::hal::{
  2    api::{
  3        ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApply, SvpApplyInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare,
  4        VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace,
  5        VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAdd, VecZnxDftAddInplace,
  6        VecZnxDftAllocBytes, VecZnxDftFromVecZnx, VecZnxDftSubABInplace, VecZnxDftToVecZnxBig, VecZnxDftToVecZnxBigConsume,
  7        VecZnxDftToVecZnxBigTmpBytes, VecZnxDftZero, VecZnxFillUniform, VecZnxMulXpMinusOneInplace, VecZnxNormalize,
  8        VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxSub, VecZnxSubABInplace,
  9        VecZnxSwithcDegree, VmpApply, VmpApplyAdd, VmpApplyTmpBytes, VmpPMatAlloc, VmpPrepare, ZnxView,
 10    },
 11    layouts::{Backend, Module, ScratchOwned},
 12    oep::{
 13        ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl,
 14        TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, VecZnxBigAllocBytesImpl, VecZnxDftAllocBytesImpl,
 15    },
 16};
 17use sampling::source::Source;
 18
 19use crate::tfhe::blind_rotation::{
 20    BlincRotationExecute, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, BlindRotationKeyPrepared, CGGI,
 21    LookUpTable, cggi_blind_rotate_scratch_space, mod_switch_2n,
 22};
 23
 24use core::layouts::{
 25    GLWECiphertext, GLWEPlaintext, GLWESecret, Infos, LWECiphertext, LWECiphertextToRef, LWEPlaintext, LWESecret,
 26    prepared::{GLWESecretPrepared, PrepareAlloc},
 27};
 28
 29pub fn test_blind_rotation<B: Backend>(module: &Module<B>, n_lwe: usize, block_size: usize, extension_factor: usize)
 30where
 31    Module<B>: VecZnxBigAllocBytes
 32        + VecZnxDftAllocBytes
 33        + SvpPPolAllocBytes
 34        + VmpApplyTmpBytes
 35        + VecZnxBigNormalizeTmpBytes
 36        + VecZnxDftToVecZnxBigTmpBytes
 37        + VecZnxDftToVecZnxBig<B>
 38        + VecZnxDftAdd<B>
 39        + VecZnxDftAddInplace<B>
 40        + VecZnxDftFromVecZnx<B>
 41        + VecZnxDftZero<B>
 42        + SvpApply<B>
 43        + VecZnxDftSubABInplace<B>
 44        + VecZnxBigAddSmallInplace<B>
 45        + VecZnxRotate
 46        + VecZnxAddInplace
 47        + VecZnxSubABInplace
 48        + VecZnxNormalize<B>
 49        + VecZnxNormalizeInplace<B>
 50        + VecZnxCopy
 51        + VecZnxMulXpMinusOneInplace
 52        + SvpPrepare<B>
 53        + SvpPPolAlloc<B>
 54        + SvpApplyInplace<B>
 55        + VecZnxDftToVecZnxBigConsume<B>
 56        + VecZnxBigAddInplace<B>
 57        + VecZnxBigNormalize<B>
 58        + VecZnxNormalizeTmpBytes
 59        + VecZnxFillUniform
 60        + VecZnxAddNormal
 61        + VecZnxAddScalarInplace
 62        + VecZnxRotateInplace
 63        + VecZnxSwithcDegree
 64        + VecZnxSub
 65        + VmpPMatAlloc<B>
 66        + VmpPrepare<B>
 67        + VmpApply<B>
 68        + VmpApplyAdd<B>,
 69    B: VecZnxDftAllocBytesImpl<B>
 70        + VecZnxBigAllocBytesImpl<B>
 71        + ScratchOwnedAllocImpl<B>
 72        + ScratchOwnedBorrowImpl<B>
 73        + TakeVecZnxDftImpl<B>
 74        + TakeVecZnxBigImpl<B>
 75        + TakeVecZnxDftSliceImpl<B>
 76        + ScratchAvailableImpl<B>
 77        + TakeVecZnxImpl<B>
 78        + TakeVecZnxSliceImpl<B>,
 79{
 80    let n: usize = module.n();
 81    let basek: usize = 19;
 82    let k_lwe: usize = 24;
 83    let k_brk: usize = 3 * basek;
 84    let rows_brk: usize = 2; // Ensures first limb is noise-free.
 85    let k_lut: usize = 1 * basek;
 86    let k_res: usize = 2 * basek;
 87    let rank: usize = 1;
 88
 89    let log_message_modulus = 4;
 90
 91    let message_modulus: usize = 1 << log_message_modulus;
 92
 93    let mut source_xs: Source = Source::new([2u8; 32]);
 94    let mut source_xe: Source = Source::new([2u8; 32]);
 95    let mut source_xa: Source = Source::new([1u8; 32]);
 96
 97    let mut scratch: ScratchOwned<B> = ScratchOwned::<B>::alloc(BlindRotationKey::generate_from_sk_scratch_space(
 98        module, n, basek, k_brk, rank,
 99    ));
100
101    let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
102    sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
103    let sk_glwe_dft: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow());
104
105    let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
106    sk_lwe.fill_binary_block(block_size, &mut source_xs);
107
108    let mut scratch_br: ScratchOwned<B> = ScratchOwned::<B>::alloc(cggi_blind_rotate_scratch_space(
109        module,
110        n,
111        block_size,
112        extension_factor,
113        basek,
114        k_res,
115        k_brk,
116        rows_brk,
117        rank,
118    ));
119
120    let mut brk: BlindRotationKey<Vec<u8>, CGGI> =
121        BlindRotationKey::<Vec<u8>, CGGI>::alloc(n, n_lwe, basek, k_brk, rows_brk, rank);
122
123    brk.encrypt_sk(
124        module,
125        &sk_glwe_dft,
126        &sk_lwe,
127        &mut source_xa,
128        &mut source_xe,
129        3.2,
130        scratch.borrow(),
131    );
132
133    let mut lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe);
134
135    let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe);
136
137    let x: i64 = 15 % (message_modulus as i64);
138
139    pt_lwe.encode_i64(x, log_message_modulus + 1);
140
141    lwe.encrypt_sk(
142        module,
143        &pt_lwe,
144        &sk_lwe,
145        &mut source_xa,
146        &mut source_xe,
147        3.2,
148    );
149
150    let f = |x: i64| -> i64 { 2 * x + 1 };
151
152    let mut f_vec: Vec<i64> = vec![0i64; message_modulus];
153    f_vec
154        .iter_mut()
155        .enumerate()
156        .for_each(|(i, x)| *x = f(i as i64));
157
158    let mut lut: LookUpTable = LookUpTable::alloc(n, basek, k_lut, extension_factor);
159    lut.set(module, &f_vec, log_message_modulus + 1);
160
161    let mut res: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_res, rank);
162
163    let brk_prepared: BlindRotationKeyPrepared<Vec<u8>, CGGI, B> = brk.prepare_alloc(module, scratch.borrow());
164
165    brk_prepared.execute(module, &mut res, &lwe, &lut, scratch_br.borrow());
166
167    let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_res);
168
169    res.decrypt(module, &mut pt_have, &sk_glwe_dft, scratch.borrow());
170
171    let mut lwe_2n: Vec<i64> = vec![0i64; lwe.n() + 1]; // TODO: from scratch space
172
173    mod_switch_2n(
174        2 * lut.domain_size(),
175        &mut lwe_2n,
176        &lwe.to_ref(),
177        lut.rotation_direction(),
178    );
179
180    let pt_want: i64 = (lwe_2n[0]
181        + lwe_2n[1..]
182            .iter()
183            .zip(sk_lwe.raw())
184            .map(|(x, y)| x * y)
185            .sum::<i64>())
186        & (2 * lut.domain_size() - 1) as i64;
187
188    lut.rotate(module, pt_want);
189
190    // First limb should be exactly equal (test are parameterized such that the noise does not reach
191    // the first limb)
192    assert_eq!(pt_have.data.at(0, 0), lut.data[0].at(0, 0));
193
194    // Verify that it effectively compute f(x)
195    let mut have: i64 = pt_have.decode_coeff_i64(log_message_modulus + 1, 0);
196
197    // Get positive representative and assert equality
198    have = (have + message_modulus as i64) % (message_modulus as i64);
199
200    assert_eq!(have, f(x) % (message_modulus as i64));
201}