arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/examples/encryption.rs
poulpy-core/examples/encryption.rsRaw
  1use poulpy_core::{
  2    layouts::{
  3        prepared::GLWESecretPrepared, Base2K, Degree, GLWELayout, GLWEPlaintext, GLWEPlaintextLayout, GLWESecret, LWEInfos, Rank,
  4        TorusPrecision, GLWE,
  5    },
  6    GLWESub, SIGMA,
  7};
  8
  9#[cfg(all(feature = "enable-avx", target_arch = "x86_64"))]
 10pub use poulpy_cpu_avx::FFT64Avx as BackendImpl;
 11
 12#[cfg(not(all(feature = "enable-avx", target_arch = "x86_64")))]
 13pub use poulpy_cpu_ref::FFT64Ref as BackendImpl;
 14
 15use poulpy_hal::{
 16    api::{ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform},
 17    layouts::{Module, ScratchOwned},
 18    source::Source,
 19};
 20
 21fn main() {
 22    // Ring degree
 23    let log_n: usize = 10;
 24
 25    let n: Degree = Degree(1 << log_n);
 26
 27    // Base-2-k (implicit digit decomposition)
 28    let base2k: Base2K = Base2K(14);
 29
 30    // Ciphertext Torus precision (equivalent to ciphertext modulus)
 31    let k_ct: TorusPrecision = TorusPrecision(27);
 32
 33    // Plaintext Torus precision (equivament to plaintext modulus)
 34    let k_pt: TorusPrecision = TorusPrecision(base2k.into());
 35
 36    // GLWE rank
 37    let rank: Rank = Rank(1);
 38
 39    // Instantiate Module (DFT Tables)
 40    let module: Module<BackendImpl> = Module::<BackendImpl>::new(n.0 as u64);
 41
 42    let glwe_ct_infos: GLWELayout = GLWELayout {
 43        n,
 44        base2k,
 45        k: k_ct,
 46        rank,
 47    };
 48
 49    let glwe_pt_infos: GLWEPlaintextLayout = GLWEPlaintextLayout { n, base2k, k: k_pt };
 50
 51    // Allocates ciphertext & plaintexts
 52    let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_ct_infos);
 53    let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_pt_infos);
 54    let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_pt_infos);
 55
 56    // CPRNG
 57    let mut source_xs: Source = Source::new([0u8; 32]);
 58    let mut source_xe: Source = Source::new([1u8; 32]);
 59    let mut source_xa: Source = Source::new([2u8; 32]);
 60
 61    // Scratch space
 62    let mut scratch: ScratchOwned<BackendImpl> = ScratchOwned::alloc(
 63        GLWE::encrypt_sk_tmp_bytes(&module, &glwe_ct_infos) | GLWE::decrypt_tmp_bytes(&module, &glwe_ct_infos),
 64    );
 65
 66    // Generate secret-key
 67    let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_ct_infos);
 68    sk.fill_ternary_prob(0.5, &mut source_xs);
 69
 70    // Backend-prepared secret
 71    let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BackendImpl> = GLWESecretPrepared::alloc(&module, rank);
 72    sk_prepared.prepare(&module, &sk);
 73
 74    // DBG:
 75    // obtain pk from sk
 76    let mut pk = poulpy_core::layouts::GLWEPublicKey::alloc_from_infos(&glwe_ct_infos);
 77    pk.generate(&module, &sk_prepared, &mut source_xa, &mut source_xe);
 78    // Backend-prepared publickey:
 79    let mut pk_prepared: poulpy_core::layouts::GLWEPublicKeyPrepared<Vec<u8>, BackendImpl> =
 80        poulpy_core::layouts::GLWEPublicKeyPrepared::alloc(&module, base2k, k_ct, rank);
 81    pk_prepared.prepare(&module, &pk);
 82
 83    // Uniform plaintext
 84    module.vec_znx_fill_uniform(base2k.into(), &mut pt_want.data, 0, &mut source_xa);
 85
 86    // Encryption
 87    // ct.encrypt_sk(
 88    //     &module,
 89    //     &pt_want,
 90    //     &sk_prepared,
 91    //     &mut source_xa,
 92    //     &mut source_xe,
 93    //     scratch.borrow(),
 94    // );
 95
 96    // DBG: encrypt with public key
 97    ct.encrypt_pk(
 98        &module,
 99        &pt_want,
100        &pk_prepared,
101        &mut source_xa,
102        &mut source_xe,
103        scratch.borrow(),
104    );
105    dbg!("encrypted");
106
107    // Decryption
108    ct.decrypt(&module, &mut pt_have, &sk_prepared, scratch.borrow());
109
110    // Diff between pt - Dec(Enc(pt))
111    module.glwe_sub_inplace(&mut pt_want, &pt_have);
112
113    // Ideal vs. actual noise
114    let noise_have: f64 = pt_want.data.stats(base2k.into(), 0).std() * (ct.k().as_u32() as f64).exp2();
115    let noise_want: f64 = SIGMA;
116
117    // Check
118    assert!(noise_have <= noise_want + 0.2);
119}