use base2k::{ AddNormal, Backend, FFT64, FillUniform, Module, ScalarZnxDftOps, ScalarZnxDftToRef, Scratch, VecZnx, VecZnxAlloc, VecZnxBigAlloc, VecZnxBigOps, VecZnxBigScratch, VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxDftToMut, VecZnxToMut, VecZnxToRef, ZnxInfos, }; use sampling::source::Source; use crate::{ elem::{Ciphertext, Infos, Plaintext}, keys::SecretKey, }; pub trait EncryptSk { fn encrypt( module: &Module, res: &mut Ciphertext, pt: Option<&Plaintext

>, sk: &SecretKey, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch, sigma: f64, bound: f64, ) where S: ScalarZnxDftToRef; fn encrypt_scratch_bytes(module: &Module, size: usize) -> usize; } impl EncryptSk for Ciphertext where C: VecZnxToMut + ZnxInfos, P: VecZnxToRef + ZnxInfos, { fn encrypt( module: &Module, ct: &mut Ciphertext, pt: Option<&Plaintext

>, sk: &SecretKey, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch, sigma: f64, bound: f64, ) where S: ScalarZnxDftToRef, { let log_base2k: usize = ct.log_base2k(); let log_q: usize = ct.log_q(); let mut ct_mut: VecZnx<&mut [u8]> = ct.to_mut(); let size: usize = ct_mut.size(); // c1 = a ct_mut.fill_uniform(log_base2k, 1, size, source_xa); let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size); { let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size); module.vec_znx_dft(&mut c0_dft, 0, &ct_mut, 1); // c0_dft = DFT(a) * DFT(s) module.svp_apply_inplace(&mut c0_dft, 0, &sk.data().to_ref(), 0); // c0_big = IDFT(c0_dft) module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0); } // c0_big = m - c0_big if let Some(pt) = pt { module.vec_znx_big_sub_small_b_inplace(&mut c0_big, 0, pt, 0); } // c0_big += e c0_big.add_normal(log_base2k, 0, log_q, source_xe, sigma, bound); // c0 = norm(c0_big = -as + m + e) module.vec_znx_big_normalize(log_base2k, &mut ct_mut, 0, &c0_big, 0, scratch_1); } fn encrypt_scratch_bytes(module: &Module, size: usize) -> usize { (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size) } } impl Ciphertext where C: VecZnxToMut + ZnxInfos, { pub fn encrypt_sk( &mut self, module: &Module, pt: Option<&Plaintext

>, sk: &SecretKey, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch, sigma: f64, bound: f64, ) where P: VecZnxToRef + ZnxInfos, S: ScalarZnxDftToRef, { >::encrypt( module, self, pt, sk, source_xa, source_xe, scratch, sigma, bound, ); } pub fn encrypt_sk_scratch_bytes

(module: &Module, size: usize) -> usize where Self: EncryptSk, { >::encrypt_scratch_bytes(module, size) } } pub trait EncryptZeroSk { fn encrypt_zero( module: &Module, res: &mut D, sk: &SecretKey, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch, sigma: f64, bound: f64, ) where S: ScalarZnxDftToRef; fn encrypt_zero_scratch_bytes(module: &Module, size: usize) -> usize; } impl EncryptZeroSk for C where C: VecZnxDftToMut + ZnxInfos + Infos, { fn encrypt_zero( module: &Module, ct: &mut C, sk: &SecretKey, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch, sigma: f64, bound: f64, ) where S: ScalarZnxDftToRef, { let log_base2k: usize = ct.log_base2k(); let log_q: usize = ct.log_q(); let mut ct_mut: VecZnxDft<&mut [u8], FFT64> = ct.to_mut(); let size: usize = ct_mut.size(); // ct[1] = DFT(a) { let (mut tmp_znx, _) = scratch.tmp_vec_znx(module, 1, size); tmp_znx.fill_uniform(log_base2k, 1, size, source_xa); module.vec_znx_dft(&mut ct_mut, 1, &tmp_znx, 0); } let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size); { let (mut tmp_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size); // c0_dft = DFT(a) * DFT(s) module.svp_apply(&mut tmp_dft, 0, &sk.data().to_ref(), 0, &ct_mut, 1); // c0_big = IDFT(c0_dft) module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut tmp_dft, 0); } // c0_big += e c0_big.add_normal(log_base2k, 0, log_q, source_xe, sigma, bound); // c0 = norm(c0_big = -as + e) let (mut tmp_znx, scratch_2) = scratch_1.tmp_vec_znx(module, 1, size); module.vec_znx_big_normalize(log_base2k, &mut tmp_znx, 0, &c0_big, 0, scratch_2); // ct[0] = DFT(-as + e) module.vec_znx_dft(&mut ct_mut, 0, &tmp_znx, 0); } fn encrypt_zero_scratch_bytes(module: &Module, size: usize) -> usize{ (module.bytes_of_vec_znx(1, size) | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size) + module.bytes_of_vec_znx(1, size) + module.vec_znx_big_normalize_tmp_bytes() } } #[cfg(test)] mod tests { use base2k::{FFT64, Module, ScratchOwned, VecZnx, Scalar}; use sampling::source::Source; use crate::{elem::{Ciphertext, Infos, Plaintext}, keys::SecretKey}; #[test] fn encrypt_sk_vec_znx_fft64() { let module: Module = Module::::new(32); let log_base2k: usize = 8; let log_q: usize = 54; let sigma: f64 = 3.2; let bound: f64 = sigma * 6; let mut ct: Ciphertext>> = Ciphertext::>>::new(&module, log_base2k, log_q, 2); let mut pt: Plaintext>> = Plaintext::>>::new(&module, log_base2k, log_q); let mut source_xe = Source::new([0u8; 32]); let mut source_xa: Source = Source::new([0u8; 32]); let mut scratch: ScratchOwned = ScratchOwned::new(ct.encrypt_encsk_scratch_bytes(&module, ct.size())); let mut sk: SecretKey>> = SecretKey::new(&module); let mut sk_prep sk.svp_prepare(&module, &mut sk_prep); ct.encrypt_sk( &module, Some(&pt), &sk_prep, &mut source_xa, &mut source_xe, scratch.borrow(), sigma, bound, ); } }