Some traits updates + added missing tests for products on RGSWCt
@@ -66,92 +66,88 @@ where
VecZnxDft<A, B>: VecZnxDftToRef<B>; } -pub trait ProdByScratchSpace { - fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize; - fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize; +pub trait ProdInplaceScratchSpace { + fn prod_by_grlwe_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize; + fn prod_by_rgsw_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize; } -pub trait ProdBy<D> { - fn prod_by_grlwe<R>(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>; - - fn prod_by_rgsw<R>(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>; +pub trait ProdInplace<MUT, REF> +where + MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>, +{ + fn prod_by_grlwe_inplace(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch); + fn prod_by_rgsw_inplace(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch); } -pub trait FromProdByScratchSpace { - fn from_prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize; - fn from_prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize; +pub trait ProdScratchSpace { + fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize; + fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize; } -pub trait FromProdBy<D, L> { - fn from_prod_by_grlwe<R>(&mut self, module: &Module<FFT64>, lhs: &L, rhs: &GRLWECt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>; +pub trait Product<MUT, REF> +where + MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>, +{ + type Lhs; - fn from_prod_by_rgsw<R>(&mut self, module: &Module<FFT64>, lhs: &L, rhs: &RGSWCt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>; + fn prod_by_grlwe(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch); + fn prod_by_rgsw(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch); } -pub(crate) trait MatZnxDftProducts<D, C>: Infos -where - MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos, -{ - fn mul_rlwe<R, A>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, a: &RLWECt<A>, scratch: &mut Scratch) - where - MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>, - VecZnx<R>: VecZnxToMut, - VecZnx<A>: VecZnxToRef; +pub(crate) trait MatRLWEProductScratchSpace { + fn prod_with_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize; - fn mul_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize; - - fn mul_rlwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, mat_size: usize) -> usize { - Self::mul_rlwe_scratch_space(module, res_size, res_size, mat_size) + fn prod_with_rlwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, mat_size: usize) -> usize { + Self::prod_with_rlwe_scratch_space(module, res_size, res_size, mat_size) } - fn mul_rlwe_dft_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, mat_size: usize) -> usize { - (Self::mul_rlwe_scratch_space(module, res_size, a_size, mat_size) | module.vec_znx_idft_tmp_bytes()) + fn prod_with_rlwe_dft_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, mat_size: usize) -> usize { + (Self::prod_with_rlwe_scratch_space(module, res_size, a_size, mat_size) | module.vec_znx_idft_tmp_bytes()) + module.bytes_of_vec_znx(2, a_size) + module.bytes_of_vec_znx(2, res_size) } - fn mul_rlwe_dft_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, mat_size: usize) -> usize { - (Self::mul_rlwe_inplace_scratch_space(module, res_size, mat_size) | module.vec_znx_idft_tmp_bytes()) + fn prod_with_rlwe_dft_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, mat_size: usize) -> usize { + (Self::prod_with_rlwe_inplace_scratch_space(module, res_size, mat_size) | module.vec_znx_idft_tmp_bytes()) + module.bytes_of_vec_znx(2, res_size) } - fn mul_mat_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, mat_size: usize) -> usize { - Self::mul_rlwe_dft_inplace_scratch_space(module, res_size, mat_size) + module.bytes_of_vec_znx_dft(2, a_size) + fn prod_with_mat_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, mat_size: usize) -> usize { + Self::prod_with_rlwe_dft_scratch_space(module, res_size, a_size, mat_size) + + module.bytes_of_vec_znx_dft(2, a_size) + + module.bytes_of_vec_znx_dft(2, res_size) } - fn mul_mat_rlwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, mat_size: usize) -> usize { - Self::mul_rlwe_dft_inplace_scratch_space(module, res_size, mat_size) + module.bytes_of_vec_znx_dft(2, res_size) + fn prod_with_mat_rlwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, mat_size: usize) -> usize { + Self::prod_with_rlwe_dft_inplace_scratch_space(module, res_size, mat_size) + module.bytes_of_vec_znx_dft(2, res_size) } +} - fn mul_rlwe_inplace<R>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, scratch: &mut Scratch) +pub(crate) trait MatRLWEProduct: Infos { + fn prod_with_rlwe<MUT, REF>(&self, module: &Module<FFT64>, res: &mut RLWECt<MUT>, a: &RLWECt<REF>, scratch: &mut Scratch) where - MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos, - VecZnx<R>: VecZnxToMut + VecZnxToRef, + VecZnx<MUT>: VecZnxToMut, + VecZnx<REF>: VecZnxToRef; + + fn prod_with_rlwe_inplace<MUT>(&self, module: &Module<FFT64>, res: &mut RLWECt<MUT>, scratch: &mut Scratch) + where + VecZnx<MUT>: VecZnxToMut + VecZnxToRef, { unsafe { - let res_ptr: *mut RLWECt<R> = res as *mut RLWECt<R>; // This is ok because [Self::mul_rlwe] only updates res at the end. - self.mul_rlwe(&module, &mut *res_ptr, &*res_ptr, scratch); + let res_ptr: *mut RLWECt<MUT> = res as *mut RLWECt<MUT>; // This is ok because [Self::mul_rlwe] only updates res at the end. + self.prod_with_rlwe(&module, &mut *res_ptr, &*res_ptr, scratch); } } - fn mul_rlwe_dft<R, A>( + fn prod_with_rlwe_dft<MUT, REF>( &self, module: &Module<FFT64>, - res: &mut RLWECtDft<R, FFT64>, - a: &RLWECtDft<A, FFT64>, + res: &mut RLWECtDft<MUT, FFT64>, + a: &RLWECtDft<REF, FFT64>, scratch: &mut Scratch, ) where - MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos, - VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64> + ZnxInfos, - VecZnxDft<A, FFT64>: VecZnxDftToRef<FFT64> + ZnxInfos, + VecZnxDft<MUT, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64> + ZnxInfos, + VecZnxDft<REF, FFT64>: VecZnxDftToRef<FFT64> + ZnxInfos, { let log_base2k: usize = self.log_base2k();@@ -180,15 +176,15 @@ log_base2k: res.log_base2k(),
log_k: res.log_k(), }; - self.mul_rlwe(module, &mut res_idft, &a_idft, scratch_2); + self.prod_with_rlwe(module, &mut res_idft, &a_idft, scratch_2); module.vec_znx_dft(res, 0, &res_idft, 0); module.vec_znx_dft(res, 1, &res_idft, 1); } - fn mul_rlwe_dft_inplace<R>(&self, module: &Module<FFT64>, res: &mut RLWECtDft<R, FFT64>, scratch: &mut Scratch) + fn prod_with_rlwe_dft_inplace<MUT>(&self, module: &Module<FFT64>, res: &mut RLWECtDft<MUT, FFT64>, scratch: &mut Scratch) where - VecZnxDft<R, FFT64>: VecZnxDftToRef<FFT64> + VecZnxDftToMut<FFT64>, + VecZnxDft<MUT, FFT64>: VecZnxDftToRef<FFT64> + VecZnxDftToMut<FFT64>, { let log_base2k: usize = self.log_base2k();@@ -209,47 +205,55 @@ };
res.idft(module, &mut res_idft, scratch_1); - self.mul_rlwe_inplace(module, &mut res_idft, scratch_1); + self.prod_with_rlwe_inplace(module, &mut res_idft, scratch_1); module.vec_znx_dft(res, 0, &res_idft, 0); module.vec_znx_dft(res, 1, &res_idft, 1); } - fn mul_mat_rlwe<R, A>(&self, module: &Module<FFT64>, res: &mut R, a: &A, scratch: &mut Scratch) + fn prod_with_mat_rlwe<RES, LHS>(&self, module: &Module<FFT64>, res: &mut RES, a: &LHS, scratch: &mut Scratch) where - A: GetRow<FFT64> + Infos, - R: SetRow<FFT64> + Infos, + LHS: GetRow<FFT64> + Infos, + RES: SetRow<FFT64> + Infos, { let (tmp_row_data, scratch1) = scratch.tmp_vec_znx_dft(module, 2, a.size()); - let mut tmp_row: RLWECtDft<&mut [u8], FFT64> = RLWECtDft::<&mut [u8], FFT64> { + let mut tmp_a_row: RLWECtDft<&mut [u8], FFT64> = RLWECtDft::<&mut [u8], FFT64> { data: tmp_row_data, log_base2k: a.log_base2k(), log_k: a.log_k(), }; + let (tmp_res_data, scratch2) = scratch1.tmp_vec_znx_dft(module, 2, res.size()); + + let mut tmp_res_row: RLWECtDft<&mut [u8], FFT64> = RLWECtDft::<&mut [u8], FFT64> { + data: tmp_res_data, + log_base2k: res.log_base2k(), + log_k: res.log_k(), + }; + let min_rows: usize = res.rows().min(a.rows()); (0..res.rows()).for_each(|row_i| { (0..res.cols()).for_each(|col_j| { - a.get_row(module, row_i, col_j, &mut tmp_row); - self.mul_rlwe_dft_inplace(module, &mut tmp_row, scratch1); - res.set_row(module, row_i, col_j, &tmp_row); + a.get_row(module, row_i, col_j, &mut tmp_a_row); + self.prod_with_rlwe_dft(module, &mut tmp_res_row, &tmp_a_row, scratch2); + res.set_row(module, row_i, col_j, &tmp_res_row); }); }); - tmp_row.data.zero(); + tmp_res_row.data.zero(); (min_rows..res.rows()).for_each(|row_i| { (0..self.cols()).for_each(|col_j| { - res.set_row(module, row_i, col_j, &tmp_row); + res.set_row(module, row_i, col_j, &tmp_res_row); }); }); } - fn mul_mat_rlwe_inplace<R>(&self, module: &Module<FFT64>, res: &mut R, scratch: &mut Scratch) + fn prod_with_mat_rlwe_inplace<RES>(&self, module: &Module<FFT64>, res: &mut RES, scratch: &mut Scratch) where - R: GetRow<FFT64> + SetRow<FFT64> + Infos, + RES: GetRow<FFT64> + SetRow<FFT64> + Infos, { let (tmp_row_data, scratch1) = scratch.tmp_vec_znx_dft(module, 2, res.size());@@ -262,7 +266,7 @@
(0..res.rows()).for_each(|row_i| { (0..res.cols()).for_each(|col_j| { res.get_row(module, row_i, col_j, &mut tmp_row); - self.mul_rlwe_dft_inplace(module, &mut tmp_row, scratch1); + self.prod_with_rlwe_dft_inplace(module, &mut tmp_row, scratch1); res.set_row(module, row_i, col_j, &tmp_row); }); });
@@ -7,7 +7,10 @@ };
use sampling::source::Source; use crate::{ - elem::{FromProdBy, FromProdByScratchSpace, GetRow, Infos, MatZnxDftProducts, ProdBy, ProdByScratchSpace, SetRow}, + elem::{ + GetRow, Infos, MatRLWEProduct, MatRLWEProductScratchSpace, ProdInplace, ProdInplaceScratchSpace, ProdScratchSpace, + Product, SetRow, + }, keys::SecretKeyDft, rgsw::RGSWCt, rlwe::{RLWECt, RLWECtDft, RLWEPt},@@ -27,18 +30,6 @@ data: module.new_mat_znx_dft(rows, 1, 2, derive_size(log_base2k, log_k)),
log_base2k: log_base2k, log_k: log_k, } - } -} - -impl<C> GRLWECt<C, FFT64> -where - MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>, -{ - pub fn get_row<R>(&self, module: &Module<FFT64>, row_i: usize, res: &mut RLWECtDft<R, FFT64>) - where - VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64>, - { - module.vmp_extract_row(res, self, row_i, 0); } }@@ -202,18 +193,20 @@ module.vmp_prepare_row(self, row_i, col_j, a);
} } -impl<C> MatZnxDftProducts<GRLWECt<C, FFT64>, C> for GRLWECt<C, FFT64> -where - MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos, -{ - fn mul_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize { +impl MatRLWEProductScratchSpace for GRLWECt<Vec<u8>, FFT64> { + fn prod_with_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize { module.bytes_of_vec_znx_dft(2, grlwe_size) + (module.vec_znx_big_normalize_tmp_bytes() | (module.vmp_apply_tmp_bytes(res_size, a_size, a_size, 1, 2, grlwe_size) + module.bytes_of_vec_znx_dft(1, a_size))) } +} - fn mul_rlwe<R, A>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, a: &RLWECt<A>, scratch: &mut Scratch) +impl<C> MatRLWEProduct for GRLWECt<C, FFT64> +where + MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos, +{ + fn prod_with_rlwe<R, A>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, a: &RLWECt<A>, scratch: &mut Scratch) where MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>, VecZnx<R>: VecZnxToMut,@@ -247,79 +240,52 @@ module.vec_znx_big_normalize(log_base2k, res, 1, &res_big, 1, scratch1);
} } -impl ProdByScratchSpace for GRLWECt<Vec<u8>, FFT64> { - fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { - <GRLWECt<Vec<u8>, FFT64> as MatZnxDftProducts<GRLWECt<Vec<u8>, FFT64>, Vec<u8>>>::mul_mat_rlwe_inplace_scratch_space( - module, lhs, rhs, - ) +impl ProdInplaceScratchSpace for GRLWECt<Vec<u8>, FFT64> { + fn prod_by_grlwe_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { + <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_mat_rlwe_inplace_scratch_space(module, lhs, rhs) } - fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { - <RGSWCt<Vec<u8>, FFT64> as MatZnxDftProducts<RGSWCt<Vec<u8>, FFT64>, Vec<u8>>>::mul_mat_rlwe_inplace_scratch_space( - module, lhs, rhs, - ) + fn prod_by_rgsw_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { + <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_mat_rlwe_inplace_scratch_space(module, lhs, rhs) } } -impl FromProdByScratchSpace for GRLWECt<Vec<u8>, FFT64> { - fn from_prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { - <GRLWECt<Vec<u8>, FFT64> as MatZnxDftProducts<GRLWECt<Vec<u8>, FFT64>, Vec<u8>>>::mul_mat_rlwe_scratch_space( - module, res_size, lhs, rhs, - ) +impl ProdScratchSpace for GRLWECt<Vec<u8>, FFT64> { + fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { + <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_mat_rlwe_scratch_space(module, res_size, lhs, rhs) } - fn from_prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { - <RGSWCt<Vec<u8>, FFT64> as MatZnxDftProducts<RGSWCt<Vec<u8>, FFT64>, Vec<u8>>>::mul_mat_rlwe_scratch_space( - module, res_size, lhs, rhs, - ) + fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { + <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_mat_rlwe_scratch_space(module, res_size, lhs, rhs) } } -impl<MUT> ProdBy<GRLWECt<MUT, FFT64>> for GRLWECt<MUT, FFT64> +impl<MUT, REF> ProdInplace<MUT, REF> for GRLWECt<MUT, FFT64> where GRLWECt<MUT, FFT64>: GetRow<FFT64> + SetRow<FFT64> + Infos, + MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>, { - fn prod_by_grlwe<R>(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_mat_rlwe_inplace(module, self, scratch); + fn prod_by_grlwe_inplace(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_mat_rlwe_inplace(module, self, scratch); } - fn prod_by_rgsw<R>(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_mat_rlwe_inplace(module, self, scratch); + fn prod_by_rgsw_inplace(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_mat_rlwe_inplace(module, self, scratch); } } -impl<MUT, REF> FromProdBy<GRLWECt<MUT, FFT64>, GRLWECt<REF, FFT64>> for GRLWECt<MUT, FFT64> +impl<MUT, REF> Product<MUT, REF> for GRLWECt<MUT, FFT64> where - GRLWECt<MUT, FFT64>: GetRow<FFT64> + SetRow<FFT64> + Infos, - GRLWECt<REF, FFT64>: GetRow<FFT64> + Infos, + MatZnxDft<MUT, FFT64>: MatZnxDftToRef<FFT64> + MatZnxDftToMut<FFT64>, + MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>, { - fn from_prod_by_grlwe<R>( - &mut self, - module: &Module<FFT64>, - lhs: &GRLWECt<REF, FFT64>, - rhs: &GRLWECt<R, FFT64>, - scratch: &mut Scratch, - ) where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_mat_rlwe(module, self, lhs, scratch); + type Lhs = GRLWECt<REF, FFT64>; + + fn prod_by_grlwe(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_mat_rlwe(module, self, lhs, scratch); } - fn from_prod_by_rgsw<R>( - &mut self, - module: &Module<FFT64>, - lhs: &GRLWECt<REF, FFT64>, - rhs: &RGSWCt<R, FFT64>, - scratch: &mut Scratch, - ) where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_mat_rlwe(module, self, lhs, scratch); + fn prod_by_rgsw(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_mat_rlwe(module, self, lhs, scratch); } }
@@ -3,5 +3,6 @@ pub mod grlwe;
pub mod keys; pub mod rgsw; pub mod rlwe; +#[cfg(test)] mod test_fft64; mod utils;
@@ -7,7 +7,10 @@ };
use sampling::source::Source; use crate::{ - elem::{FromProdBy, FromProdByScratchSpace, GetRow, Infos, MatZnxDftProducts, ProdBy, ProdByScratchSpace, SetRow}, + elem::{ + GetRow, Infos, MatRLWEProduct, MatRLWEProductScratchSpace, ProdInplace, ProdInplaceScratchSpace, ProdScratchSpace, + Product, SetRow, + }, grlwe::GRLWECt, keys::SecretKeyDft, rlwe::{RLWECt, RLWECtDft, RLWEPt, encrypt_rlwe_sk},@@ -184,17 +187,19 @@ module.vmp_prepare_row(self, row_i, col_j, a);
} } -impl<C> MatZnxDftProducts<RGSWCt<C, FFT64>, C> for RGSWCt<C, FFT64> -where - MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos, -{ - fn mul_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, rgsw_size: usize) -> usize { +impl MatRLWEProductScratchSpace for RGSWCt<Vec<u8>, FFT64> { + fn prod_with_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, rgsw_size: usize) -> usize { module.bytes_of_vec_znx_dft(2, rgsw_size) + ((module.bytes_of_vec_znx_dft(2, a_size) + module.vmp_apply_tmp_bytes(res_size, a_size, a_size, 2, 2, rgsw_size)) | module.vec_znx_big_normalize_tmp_bytes()) } +} - fn mul_rlwe<R, A>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, a: &RLWECt<A>, scratch: &mut Scratch) +impl<C> MatRLWEProduct for RGSWCt<C, FFT64> +where + MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos, +{ + fn prod_with_rlwe<R, A>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, a: &RLWECt<A>, scratch: &mut Scratch) where MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>, VecZnx<R>: VecZnxToMut,@@ -227,79 +232,52 @@ module.vec_znx_big_normalize(log_base2k, res, 1, &res_big, 1, scratch1);
} } -impl ProdByScratchSpace for RGSWCt<Vec<u8>, FFT64> { - fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { - <GRLWECt<Vec<u8>, FFT64> as MatZnxDftProducts<GRLWECt<Vec<u8>, FFT64>, Vec<u8>>>::mul_mat_rlwe_inplace_scratch_space( - module, lhs, rhs, - ) +impl ProdInplaceScratchSpace for RGSWCt<Vec<u8>, FFT64> { + fn prod_by_grlwe_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { + <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_mat_rlwe_inplace_scratch_space(module, lhs, rhs) } - fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { - <RGSWCt<Vec<u8>, FFT64> as MatZnxDftProducts<RGSWCt<Vec<u8>, FFT64>, Vec<u8>>>::mul_mat_rlwe_inplace_scratch_space( - module, lhs, rhs, - ) + fn prod_by_rgsw_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { + <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_mat_rlwe_inplace_scratch_space(module, lhs, rhs) } } -impl FromProdByScratchSpace for RGSWCt<Vec<u8>, FFT64> { - fn from_prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { - <GRLWECt<Vec<u8>, FFT64> as MatZnxDftProducts<GRLWECt<Vec<u8>, FFT64>, Vec<u8>>>::mul_mat_rlwe_scratch_space( - module, res_size, lhs, rhs, - ) +impl ProdScratchSpace for RGSWCt<Vec<u8>, FFT64> { + fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { + <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_mat_rlwe_scratch_space(module, res_size, lhs, rhs) } - fn from_prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { - <RGSWCt<Vec<u8>, FFT64> as MatZnxDftProducts<RGSWCt<Vec<u8>, FFT64>, Vec<u8>>>::mul_mat_rlwe_scratch_space( - module, res_size, lhs, rhs, - ) + fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { + <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_mat_rlwe_scratch_space(module, res_size, lhs, rhs) } } -impl<MUT> ProdBy<RGSWCt<MUT, FFT64>> for RGSWCt<MUT, FFT64> +impl<MUT, REF> ProdInplace<MUT, REF> for RGSWCt<MUT, FFT64> where RGSWCt<MUT, FFT64>: GetRow<FFT64> + SetRow<FFT64> + Infos, + MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>, { - fn prod_by_grlwe<R>(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_mat_rlwe_inplace(module, self, scratch); + fn prod_by_grlwe_inplace(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_mat_rlwe_inplace(module, self, scratch); } - fn prod_by_rgsw<R>(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_mat_rlwe_inplace(module, self, scratch); + fn prod_by_rgsw_inplace(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_mat_rlwe_inplace(module, self, scratch); } } -impl<MUT, REF> FromProdBy<RGSWCt<MUT, FFT64>, RGSWCt<REF, FFT64>> for RGSWCt<MUT, FFT64> +impl<MUT, REF> Product<MUT, REF> for RGSWCt<MUT, FFT64> where - RGSWCt<MUT, FFT64>: GetRow<FFT64> + SetRow<FFT64> + Infos, - RGSWCt<REF, FFT64>: GetRow<FFT64> + Infos, + MatZnxDft<MUT, FFT64>: MatZnxDftToRef<FFT64> + MatZnxDftToMut<FFT64>, + MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>, { - fn from_prod_by_grlwe<R>( - &mut self, - module: &Module<FFT64>, - lhs: &RGSWCt<REF, FFT64>, - rhs: &GRLWECt<R, FFT64>, - scratch: &mut Scratch, - ) where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_mat_rlwe(module, self, lhs, scratch); + type Lhs = RGSWCt<REF, FFT64>; + + fn prod_by_grlwe(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_mat_rlwe(module, self, lhs, scratch); } - fn from_prod_by_rgsw<R>( - &mut self, - module: &Module<FFT64>, - lhs: &RGSWCt<REF, FFT64>, - rhs: &RGSWCt<R, FFT64>, - scratch: &mut Scratch, - ) where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_mat_rlwe(module, self, lhs, scratch); + fn prod_by_rgsw(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_mat_rlwe(module, self, lhs, scratch); } }
@@ -6,7 +6,7 @@ };
use sampling::source::Source; use crate::{ - elem::{FromProdBy, FromProdByScratchSpace, Infos, MatZnxDftProducts, ProdBy, ProdByScratchSpace}, + elem::{Infos, MatRLWEProduct, MatRLWEProductScratchSpace, ProdInplace, ProdInplaceScratchSpace, ProdScratchSpace, Product}, grlwe::GRLWECt, keys::{PublicKey, SecretDistribution, SecretKeyDft}, rgsw::RGSWCt,@@ -84,70 +84,54 @@ module.vec_znx_dft(res, 1, self, 1);
} } -impl ProdByScratchSpace for RLWECt<Vec<u8>> { - fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { - <GRLWECt<Vec<u8>, FFT64> as MatZnxDftProducts<GRLWECt<Vec<u8>, FFT64>, Vec<u8>>>::mul_rlwe_inplace_scratch_space( - module, lhs, rhs, - ) +impl ProdInplaceScratchSpace for RLWECt<Vec<u8>> { + fn prod_by_grlwe_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { + <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_inplace_scratch_space(module, lhs, rhs) } - fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { - <RGSWCt<Vec<u8>, FFT64> as MatZnxDftProducts<RGSWCt<Vec<u8>, FFT64>, Vec<u8>>>::mul_rlwe_inplace_scratch_space( - module, lhs, rhs, - ) + fn prod_by_rgsw_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { + <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_inplace_scratch_space(module, lhs, rhs) } } -impl FromProdByScratchSpace for RLWECt<Vec<u8>> { - fn from_prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { - <GRLWECt<Vec<u8>, FFT64> as MatZnxDftProducts<GRLWECt<Vec<u8>, FFT64>, Vec<u8>>>::mul_rlwe_scratch_space( - module, res_size, lhs, rhs, - ) +impl ProdScratchSpace for RLWECt<Vec<u8>> { + fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { + <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_scratch_space(module, res_size, lhs, rhs) } - fn from_prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { - <RGSWCt<Vec<u8>, FFT64> as MatZnxDftProducts<RGSWCt<Vec<u8>, FFT64>, Vec<u8>>>::mul_rlwe_scratch_space( - module, res_size, lhs, rhs, - ) + fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { + <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_scratch_space(module, res_size, lhs, rhs) } } -impl<MUT> ProdBy<RLWECt<MUT>> for RLWECt<MUT> +impl<MUT, REF> ProdInplace<MUT, REF> for RLWECt<MUT> where VecZnx<MUT>: VecZnxToMut + VecZnxToRef, + MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>, { - fn prod_by_grlwe<R>(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_rlwe_inplace(module, self, scratch); + fn prod_by_grlwe_inplace(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_rlwe_inplace(module, self, scratch); } - fn prod_by_rgsw<R>(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_rlwe_inplace(module, self, scratch); + fn prod_by_rgsw_inplace(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_rlwe_inplace(module, self, scratch); } } -impl<MUT, REF> FromProdBy<RLWECt<MUT>, RLWECt<REF>> for RLWECt<MUT> +impl<MUT, REF> Product<MUT, REF> for RLWECt<MUT> where VecZnx<MUT>: VecZnxToMut + VecZnxToRef, VecZnx<REF>: VecZnxToRef, + MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>, { - fn from_prod_by_grlwe<R>(&mut self, module: &Module<FFT64>, lhs: &RLWECt<REF>, rhs: &GRLWECt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_rlwe(module, self, lhs, scratch); + type Lhs = RLWECt<REF>; + + fn prod_by_grlwe(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_rlwe(module, self, lhs, scratch); } - fn from_prod_by_rgsw<R>(&mut self, module: &Module<FFT64>, lhs: &RLWECt<REF>, rhs: &RGSWCt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_rlwe(module, self, lhs, scratch); + fn prod_by_rgsw(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_rlwe(module, self, lhs, scratch); } }@@ -496,7 +480,7 @@ }
impl<C> RLWECtDft<C, FFT64> where - VecZnxDft<C, FFT64>: VecZnxDftToRef<FFT64>, + RLWECtDft<C, FFT64>: VecZnxDftToRef<FFT64>, { #[allow(dead_code)] pub(crate) fn idft_scratch_space(module: &Module<FFT64>, size: usize) -> usize {@@ -505,7 +489,7 @@ }
pub(crate) fn idft<R>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, scratch: &mut Scratch) where - VecZnx<R>: VecZnxToMut, + RLWECt<R>: VecZnxToMut, { #[cfg(debug_assertions)] {@@ -518,8 +502,8 @@ let min_size: usize = self.size().min(res.size());
let (mut res_big, scratch1) = scratch.tmp_vec_znx_big(module, 2, min_size); - module.vec_znx_idft(&mut res_big, 0, &self.data, 0, scratch1); - module.vec_znx_idft(&mut res_big, 1, &self.data, 1, scratch1); + module.vec_znx_idft(&mut res_big, 0, self, 0, scratch1); + module.vec_znx_idft(&mut res_big, 1, self, 1, scratch1); module.vec_znx_big_normalize(self.log_base2k(), res, 0, &res_big, 0, scratch1); module.vec_znx_big_normalize(self.log_base2k(), res, 1, &res_big, 1, scratch1); }@@ -665,79 +649,53 @@ decrypt_rlwe_dft(module, pt, self, sk_dft, scratch);
} } -impl ProdByScratchSpace for RLWECtDft<Vec<u8>, FFT64> { - fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { - <GRLWECt<Vec<u8>, FFT64> as MatZnxDftProducts<GRLWECt<Vec<u8>, FFT64>, Vec<u8>>>::mul_rlwe_dft_inplace_scratch_space( - module, lhs, rhs, - ) +impl ProdInplaceScratchSpace for RLWECtDft<Vec<u8>, FFT64> { + fn prod_by_grlwe_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { + <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_inplace_scratch_space(module, lhs, rhs) } - fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { - <RGSWCt<Vec<u8>, FFT64> as MatZnxDftProducts<RGSWCt<Vec<u8>, FFT64>, Vec<u8>>>::mul_rlwe_dft_inplace_scratch_space( - module, lhs, rhs, - ) + fn prod_by_rgsw_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize { + <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_inplace_scratch_space(module, lhs, rhs) } } -impl FromProdByScratchSpace for RLWECtDft<Vec<u8>, FFT64> { - fn from_prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { - <GRLWECt<Vec<u8>, FFT64> as MatZnxDftProducts<GRLWECt<Vec<u8>, FFT64>, Vec<u8>>>::mul_rlwe_dft_scratch_space( - module, res_size, lhs, rhs, - ) +impl ProdScratchSpace for RLWECtDft<Vec<u8>, FFT64> { + fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { + <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_scratch_space(module, res_size, lhs, rhs) } - fn from_prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { - <RGSWCt<Vec<u8>, FFT64> as MatZnxDftProducts<RGSWCt<Vec<u8>, FFT64>, Vec<u8>>>::mul_rlwe_dft_scratch_space( - module, res_size, lhs, rhs, - ) + fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize { + <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_scratch_space(module, res_size, lhs, rhs) } } -impl<MUT> ProdBy<RLWECtDft<MUT, FFT64>> for RLWECtDft<MUT, FFT64> +impl<MUT, REF> ProdInplace<MUT, REF> for RLWECtDft<MUT, FFT64> where VecZnxDft<MUT, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>, + MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>, { - fn prod_by_grlwe<R>(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_rlwe_dft_inplace(module, self, scratch); + fn prod_by_grlwe_inplace(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_rlwe_dft_inplace(module, self, scratch); } - fn prod_by_rgsw<R>(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<R, FFT64>, scratch: &mut Scratch) - where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_rlwe_dft_inplace(module, self, scratch); + fn prod_by_rgsw_inplace(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_rlwe_dft_inplace(module, self, scratch); } } -impl<MUT, REF> FromProdBy<RLWECtDft<MUT, FFT64>, RLWECtDft<REF, FFT64>> for RLWECtDft<MUT, FFT64> +impl<MUT, REF> Product<MUT, REF> for RLWECtDft<MUT, FFT64> where VecZnxDft<MUT, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>, VecZnxDft<REF, FFT64>: VecZnxDftToRef<FFT64>, + MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>, { - fn from_prod_by_grlwe<R>( - &mut self, - module: &Module<FFT64>, - lhs: &RLWECtDft<REF, FFT64>, - rhs: &GRLWECt<R, FFT64>, - scratch: &mut Scratch, - ) where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_rlwe_dft(module, self, lhs, scratch); + type Lhs = RLWECtDft<REF, FFT64>; + + fn prod_by_grlwe(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_rlwe_dft(module, self, lhs, scratch); } - fn from_prod_by_rgsw<R>( - &mut self, - module: &Module<FFT64>, - lhs: &RLWECtDft<REF, FFT64>, - rhs: &RGSWCt<R, FFT64>, - scratch: &mut Scratch, - ) where - MatZnxDft<R, FFT64>: MatZnxDftToRef<FFT64>, - { - rhs.mul_rlwe_dft(module, self, lhs, scratch); + fn prod_by_rgsw(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) { + rhs.prod_with_rlwe_dft(module, self, lhs, scratch); } }
@@ -1,504 +1,499 @@
-#[cfg(test)] +use base2k::{FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, ZnxViewMut}; +use sampling::source::Source; -mod tests { - use base2k::{FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, ZnxViewMut}; - use sampling::source::Source; +use crate::{ + elem::{GetRow, Infos, ProdInplace, ProdInplaceScratchSpace, ProdScratchSpace, Product}, + grlwe::GRLWECt, + keys::{SecretKey, SecretKeyDft}, + rgsw::RGSWCt, + rlwe::{RLWECtDft, RLWEPt}, + test_fft64::rgsw::noise_rgsw_product, +}; - use crate::{ - elem::{FromProdBy, FromProdByScratchSpace, Infos, ProdBy, ProdByScratchSpace}, - grlwe::GRLWECt, - keys::{SecretKey, SecretKeyDft}, - rgsw::RGSWCt, - rlwe::{RLWECtDft, RLWEPt}, - test_fft64::{grlwe::noise_grlwe_rlwe_product, rgsw::noise_rgsw_rlwe_product}, - }; +#[test] +fn encrypt_sk() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 8; + let log_k_ct: usize = 54; + let rows: usize = 4; - #[test] - fn encrypt_sk() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 8; - let log_k_ct: usize = 54; - let rows: usize = 4; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let mut ct: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_ct, rows); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); + let mut pt_scalar: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); - let mut ct: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_ct, rows); - let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); - let mut pt_scalar: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs); - pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs); + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct.size()) | RLWECtDft::decrypt_scratch_space(&module, ct.size()), + ); - let mut scratch: ScratchOwned = ScratchOwned::new( - GRLWECt::encrypt_sk_scratch_space(&module, ct.size()) | RLWECtDft::decrypt_scratch_space(&module, ct.size()), - ); + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + ct.encrypt_sk( + &module, + &pt_scalar, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct.encrypt_sk( - &module, - &pt_scalar, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_ct); - let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_ct); + (0..ct.rows()).for_each(|row_i| { + ct.get_row(&module, row_i, 0, &mut ct_rlwe_dft); + ct_rlwe_dft.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); + module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &pt_scalar, 0); + let std_pt: f64 = pt.data.std(0, log_base2k) * (log_k_ct as f64).exp2(); + assert!((sigma - std_pt).abs() <= 0.2, "{} {}", sigma, std_pt); + }); - (0..ct.rows()).for_each(|row_i| { - ct.get_row(&module, row_i, &mut ct_rlwe_dft); - ct_rlwe_dft.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); - module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &pt_scalar, 0); - let std_pt: f64 = pt.data.std(0, log_base2k) * (log_k_ct as f64).exp2(); - assert!((sigma - std_pt).abs() <= 0.2, "{} {}", sigma, std_pt); - }); + module.free(); +} - module.free(); - } +#[test] +fn from_prod_by_grlwe() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let rows: usize = (log_k_grlwe + log_base2k - 1) / log_base2k; - #[test] - fn from_prod_by_grlwe() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let rows: usize = (log_k_grlwe + log_base2k - 1) / log_base2k; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let mut ct_grlwe_s0s1: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_grlwe_s1s2: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_grlwe_s0s2: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_grlwe_s0s1: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_grlwe_s1s2: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_grlwe_s0s2: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe_s0s1.size()) + | RLWECtDft::decrypt_scratch_space(&module, ct_grlwe_s0s2.size()) + | GRLWECt::prod_by_grlwe_scratch_space( + &module, + ct_grlwe_s0s2.size(), + ct_grlwe_s0s1.size(), + ct_grlwe_s1s2.size(), + ), + ); - let mut scratch: ScratchOwned = ScratchOwned::new( - GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe_s0s1.size()) - | RLWECtDft::decrypt_scratch_space(&module, ct_grlwe_s0s2.size()) - | GRLWECt::from_prod_by_grlwe_scratch_space( - &module, - ct_grlwe_s0s2.size(), - ct_grlwe_s0s1.size(), - ct_grlwe_s1s2.size(), - ), - ); + let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk0.fill_ternary_prob(0.5, &mut source_xs); + + let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk0_dft.dft(&module, &sk0); + + let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk1.fill_ternary_prob(0.5, &mut source_xs); - let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk0.fill_ternary_prob(0.5, &mut source_xs); + let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk1_dft.dft(&module, &sk1); - let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk0_dft.dft(&module, &sk0); + let mut sk2: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk2.fill_ternary_prob(0.5, &mut source_xs); - let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk1.fill_ternary_prob(0.5, &mut source_xs); + let mut sk2_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk2_dft.dft(&module, &sk2); - let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk1_dft.dft(&module, &sk1); + // GRLWE_{s1}(s0) = s0 -> s1 + ct_grlwe_s0s1.encrypt_sk( + &module, + &sk0.data, + &sk1_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); + + // GRLWE_{s2}(s1) -> s1 -> s2 + ct_grlwe_s1s2.encrypt_sk( + &module, + &sk1.data, + &sk2_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); + + // GRLWE_{s1}(s0) (x) GRLWE_{s2}(s1) = GRLWE_{s2}(s0) + ct_grlwe_s0s2.prod_by_grlwe(&module, &ct_grlwe_s0s1, &ct_grlwe_s1s2, scratch.borrow()); - let mut sk2: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk2.fill_ternary_prob(0.5, &mut source_xs); + let mut ct_rlwe_dft_s0s2: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_grlwe); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_grlwe); - let mut sk2_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk2_dft.dft(&module, &sk2); + (0..ct_grlwe_s0s2.rows()).for_each(|row_i| { + ct_grlwe_s0s2.get_row(&module, row_i, 0, &mut ct_rlwe_dft_s0s2); + ct_rlwe_dft_s0s2.decrypt(&module, &mut pt, &sk2_dft, scratch.borrow()); + module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &sk0, 0); - // GRLWE_{s1}(s0) = s0 -> s1 - ct_grlwe_s0s1.encrypt_sk( - &module, - &sk0.data, - &sk1_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), + let noise_have: f64 = pt.data.std(0, log_base2k).log2(); + let noise_want: f64 = noise_grlwe_rlwe_product( + module.n() as f64, + log_base2k, + 0.5, + 0.5, + 0f64, + sigma * sigma, + 0f64, + log_k_grlwe, + log_k_grlwe, ); - // GRLWE_{s2}(s1) -> s1 -> s2 - ct_grlwe_s1s2.encrypt_sk( - &module, - &sk1.data, - &sk2_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want ); + }); - // GRLWE_{s1}(s0) (x) GRLWE_{s2}(s1) = GRLWE_{s2}(s0) - ct_grlwe_s0s2.from_prod_by_grlwe(&module, &ct_grlwe_s0s1, &ct_grlwe_s1s2, scratch.borrow()); + module.free(); +} - let mut ct_rlwe_dft_s0s2: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_grlwe); - let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_grlwe); +#[test] +fn prod_by_grlwe() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let rows: usize = (log_k_grlwe + log_base2k - 1) / log_base2k; - (0..ct_grlwe_s0s2.rows()).for_each(|row_i| { - ct_grlwe_s0s2.get_row(&module, row_i, &mut ct_rlwe_dft_s0s2); - ct_rlwe_dft_s0s2.decrypt(&module, &mut pt, &sk2_dft, scratch.borrow()); - module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &sk0, 0); + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let noise_have: f64 = pt.data.std(0, log_base2k).log2(); - let noise_want: f64 = noise_grlwe_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - 0.5, - 0f64, - sigma * sigma, - 0f64, - log_k_grlwe, - log_k_grlwe, - ); + let mut ct_grlwe_s0s1: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_grlwe_s1s2: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); - }); + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe_s0s1.size()) + | RLWECtDft::decrypt_scratch_space(&module, ct_grlwe_s0s1.size()) + | GRLWECt::prod_by_grlwe_inplace_scratch_space(&module, ct_grlwe_s0s1.size(), ct_grlwe_s1s2.size()), + ); - module.free(); - } + let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk0.fill_ternary_prob(0.5, &mut source_xs); - #[test] - fn prod_by_grlwe() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let rows: usize = (log_k_grlwe + log_base2k - 1) / log_base2k; + let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk0_dft.dft(&module, &sk0); - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk1.fill_ternary_prob(0.5, &mut source_xs); - let mut ct_grlwe_s0s1: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_grlwe_s1s2: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk1_dft.dft(&module, &sk1); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut sk2: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk2.fill_ternary_prob(0.5, &mut source_xs); - let mut scratch: ScratchOwned = ScratchOwned::new( - GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe_s0s1.size()) - | RLWECtDft::decrypt_scratch_space(&module, ct_grlwe_s0s1.size()) - | GRLWECt::prod_by_grlwe_scratch_space(&module, ct_grlwe_s0s1.size(), ct_grlwe_s1s2.size()), - ); + let mut sk2_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk2_dft.dft(&module, &sk2); - let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk0.fill_ternary_prob(0.5, &mut source_xs); + // GRLWE_{s1}(s0) = s0 -> s1 + ct_grlwe_s0s1.encrypt_sk( + &module, + &sk0.data, + &sk1_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk0_dft.dft(&module, &sk0); + // GRLWE_{s2}(s1) -> s1 -> s2 + ct_grlwe_s1s2.encrypt_sk( + &module, + &sk1.data, + &sk2_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk1.fill_ternary_prob(0.5, &mut source_xs); + // GRLWE_{s1}(s0) (x) GRLWE_{s2}(s1) = GRLWE_{s2}(s0) + ct_grlwe_s0s1.prod_by_grlwe_inplace(&module, &ct_grlwe_s1s2, scratch.borrow()); - let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk1_dft.dft(&module, &sk1); + let ct_grlwe_s0s2: GRLWECt<Vec<u8>, FFT64> = ct_grlwe_s0s1; - let mut sk2: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk2.fill_ternary_prob(0.5, &mut source_xs); + let mut ct_rlwe_dft_s0s2: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_grlwe); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_grlwe); - let mut sk2_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk2_dft.dft(&module, &sk2); + (0..ct_grlwe_s0s2.rows()).for_each(|row_i| { + ct_grlwe_s0s2.get_row(&module, row_i, 0, &mut ct_rlwe_dft_s0s2); + ct_rlwe_dft_s0s2.decrypt(&module, &mut pt, &sk2_dft, scratch.borrow()); + module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &sk0, 0); - // GRLWE_{s1}(s0) = s0 -> s1 - ct_grlwe_s0s1.encrypt_sk( - &module, - &sk0.data, - &sk1_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), + let noise_have: f64 = pt.data.std(0, log_base2k).log2(); + let noise_want: f64 = noise_grlwe_rlwe_product( + module.n() as f64, + log_base2k, + 0.5, + 0.5, + 0f64, + sigma * sigma, + 0f64, + log_k_grlwe, + log_k_grlwe, ); - // GRLWE_{s2}(s1) -> s1 -> s2 - ct_grlwe_s1s2.encrypt_sk( - &module, - &sk1.data, - &sk2_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want ); + }); - // GRLWE_{s1}(s0) (x) GRLWE_{s2}(s1) = GRLWE_{s2}(s0) - ct_grlwe_s0s1.prod_by_grlwe(&module, &ct_grlwe_s1s2, scratch.borrow()); + module.free(); +} - let ct_grlwe_s0s2: GRLWECt<Vec<u8>, FFT64> = ct_grlwe_s0s1; +#[test] +fn from_prod_by_rgsw() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let rows: usize = (log_k_grlwe + log_base2k - 1) / log_base2k; - let mut ct_rlwe_dft_s0s2: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_grlwe); - let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_grlwe); + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - (0..ct_grlwe_s0s2.rows()).for_each(|row_i| { - ct_grlwe_s0s2.get_row(&module, row_i, &mut ct_rlwe_dft_s0s2); - ct_rlwe_dft_s0s2.decrypt(&module, &mut pt, &sk2_dft, scratch.borrow()); - module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &sk0, 0); + let mut ct_grlwe_in: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_grlwe_out: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); - let noise_have: f64 = pt.data.std(0, log_base2k).log2(); - let noise_want: f64 = noise_grlwe_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - 0.5, - 0f64, - sigma * sigma, - 0f64, - log_k_grlwe, - log_k_grlwe, - ); + let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + let mut pt_grlwe: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); - }); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - module.free(); - } + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe_in.size()) + | RLWECtDft::decrypt_scratch_space(&module, ct_grlwe_out.size()) + | GRLWECt::prod_by_rgsw_scratch_space( + &module, + ct_grlwe_out.size(), + ct_grlwe_in.size(), + ct_rgsw.size(), + ) + | RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()), + ); - #[test] - fn from_prod_by_rgsw() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let rows: usize = (log_k_grlwe + log_base2k - 1) / log_base2k; + let k: usize = 1; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + pt_rgsw.raw_mut()[k] = 1; // X^{k} + + pt_grlwe.fill_ternary_prob(0, 0.5, &mut source_xs); + + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); - let mut ct_grlwe_in: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_grlwe_out: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); + + // GRLWE_{s1}(s0) = s0 -> s1 + ct_grlwe_in.encrypt_sk( + &module, + &pt_grlwe, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); - let mut pt_grlwe: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + ct_rgsw.encrypt_sk( + &module, + &pt_rgsw, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + // GRLWE_(m) (x) RGSW_(X^k) = GRLWE_(m * X^k) + ct_grlwe_out.prod_by_rgsw(&module, &ct_grlwe_in, &ct_rgsw, scratch.borrow()); - let mut scratch: ScratchOwned = ScratchOwned::new( - GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe_in.size()) - | RLWECtDft::decrypt_scratch_space(&module, ct_grlwe_out.size()) - | GRLWECt::from_prod_by_rgsw_scratch_space( - &module, - ct_grlwe_out.size(), - ct_grlwe_in.size(), - ct_rgsw.size(), - ) - | RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()), - ); + let mut ct_rlwe_dft_s0s2: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_grlwe); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_grlwe); - let k: usize = 1; + module.vec_znx_rotate_inplace(k as i64, &mut pt_grlwe, 0); - pt_rgsw.raw_mut()[k] = 1; // X^{k} + (0..ct_grlwe_out.rows()).for_each(|row_i| { + ct_grlwe_out.get_row(&module, row_i, 0, &mut ct_rlwe_dft_s0s2); + ct_rlwe_dft_s0s2.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); + module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &pt_grlwe, 0); - pt_grlwe.fill_ternary_prob(0, 0.5, &mut source_xs); + let noise_have: f64 = pt.data.std(0, log_base2k).log2(); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); + let var_gct_err_lhs: f64 = sigma * sigma; + let var_gct_err_rhs: f64 = 0f64; - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} + let var_a0_err: f64 = sigma * sigma; + let var_a1_err: f64 = 1f64 / 12f64; - // GRLWE_{s1}(s0) = s0 -> s1 - ct_grlwe_in.encrypt_sk( - &module, - &pt_grlwe, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), + let noise_want: f64 = noise_rgsw_product( + module.n() as f64, + log_base2k, + 0.5, + var_msg, + var_a0_err, + var_a1_err, + var_gct_err_lhs, + var_gct_err_rhs, + log_k_grlwe, + log_k_grlwe, ); - ct_rgsw.encrypt_sk( - &module, - &pt_rgsw, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want ); + }); - // GRLWE_(m) (x) RGSW_(X^k) = GRLWE_(m * X^k) - ct_grlwe_out.from_prod_by_rgsw(&module, &ct_grlwe_in, &ct_rgsw, scratch.borrow()); + module.free(); +} - let mut ct_rlwe_dft_s0s2: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_grlwe); - let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_grlwe); +#[test] +fn prod_by_rgsw() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let rows: usize = (log_k_grlwe + log_base2k - 1) / log_base2k; - module.vec_znx_rotate_inplace(k as i64, &mut pt_grlwe, 0); + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - (0..ct_grlwe_out.rows()).for_each(|row_i| { - ct_grlwe_out.get_row(&module, row_i, &mut ct_rlwe_dft_s0s2); - ct_rlwe_dft_s0s2.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); - module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &pt_grlwe, 0); + let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); - let noise_have: f64 = pt.data.std(0, log_base2k).log2(); + let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + let mut pt_grlwe: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); - let var_gct_err_lhs: f64 = sigma * sigma; - let var_gct_err_rhs: f64 = 0f64; + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} - let var_a0_err: f64 = sigma * sigma; - let var_a1_err: f64 = 1f64 / 12f64; + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) + | RLWECtDft::decrypt_scratch_space(&module, ct_grlwe.size()) + | GRLWECt::prod_by_rgsw_inplace_scratch_space(&module, ct_grlwe.size(), ct_rgsw.size()) + | RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()), + ); - let noise_want: f64 = noise_rgsw_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - var_msg, - var_a0_err, - var_a1_err, - var_gct_err_lhs, - var_gct_err_rhs, - log_k_grlwe, - log_k_grlwe, - ); + let k: usize = 1; - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); - }); + pt_rgsw.raw_mut()[k] = 1; // X^{k} - module.free(); - } + pt_grlwe.fill_ternary_prob(0, 0.5, &mut source_xs); - #[test] - fn prod_by_rgsw() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let rows: usize = (log_k_grlwe + log_base2k - 1) / log_base2k; + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); - let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); + // GRLWE_{s1}(s0) = s0 -> s1 + ct_grlwe.encrypt_sk( + &module, + &pt_grlwe, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); - let mut pt_grlwe: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + ct_rgsw.encrypt_sk( + &module, + &pt_rgsw, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + // GRLWE_(m) (x) RGSW_(X^k) = GRLWE_(m * X^k) + ct_grlwe.prod_by_rgsw_inplace(&module, &ct_rgsw, scratch.borrow()); - let mut scratch: ScratchOwned = ScratchOwned::new( - GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) - | RLWECtDft::decrypt_scratch_space(&module, ct_grlwe.size()) - | GRLWECt::prod_by_rgsw_scratch_space(&module, ct_grlwe.size(), ct_rgsw.size()) - | RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()), - ); + let mut ct_rlwe_dft_s0s2: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_grlwe); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_grlwe); - let k: usize = 1; + module.vec_znx_rotate_inplace(k as i64, &mut pt_grlwe, 0); - pt_rgsw.raw_mut()[k] = 1; // X^{k} + (0..ct_grlwe.rows()).for_each(|row_i| { + ct_grlwe.get_row(&module, row_i, 0, &mut ct_rlwe_dft_s0s2); + ct_rlwe_dft_s0s2.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); + module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &pt_grlwe, 0); - pt_grlwe.fill_ternary_prob(0, 0.5, &mut source_xs); + let noise_have: f64 = pt.data.std(0, log_base2k).log2(); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); + let var_gct_err_lhs: f64 = sigma * sigma; + let var_gct_err_rhs: f64 = 0f64; - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} + let var_a0_err: f64 = sigma * sigma; + let var_a1_err: f64 = 1f64 / 12f64; - // GRLWE_{s1}(s0) = s0 -> s1 - ct_grlwe.encrypt_sk( - &module, - &pt_grlwe, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), + let noise_want: f64 = noise_rgsw_product( + module.n() as f64, + log_base2k, + 0.5, + var_msg, + var_a0_err, + var_a1_err, + var_gct_err_lhs, + var_gct_err_rhs, + log_k_grlwe, + log_k_grlwe, ); - ct_rgsw.encrypt_sk( - &module, - &pt_rgsw, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want ); + }); - // GRLWE_(m) (x) RGSW_(X^k) = GRLWE_(m * X^k) - ct_grlwe.prod_by_rgsw(&module, &ct_rgsw, scratch.borrow()); - - let mut ct_rlwe_dft_s0s2: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_grlwe); - let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_grlwe); - - module.vec_znx_rotate_inplace(k as i64, &mut pt_grlwe, 0); - - (0..ct_grlwe.rows()).for_each(|row_i| { - ct_grlwe.get_row(&module, row_i, &mut ct_rlwe_dft_s0s2); - ct_rlwe_dft_s0s2.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); - module.vec_znx_sub_scalar_inplace(&mut pt, 0, row_i, &pt_grlwe, 0); - - let noise_have: f64 = pt.data.std(0, log_base2k).log2(); - - let var_gct_err_lhs: f64 = sigma * sigma; - let var_gct_err_rhs: f64 = 0f64; - - let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} - let var_a0_err: f64 = sigma * sigma; - let var_a1_err: f64 = 1f64 / 12f64; - - let noise_want: f64 = noise_rgsw_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - var_msg, - var_a0_err, - var_a1_err, - var_gct_err_lhs, - var_gct_err_rhs, - log_k_grlwe, - log_k_grlwe, - ); - - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); - }); - - module.free(); - } + module.free(); } -#[allow(dead_code)] pub(crate) fn noise_grlwe_rlwe_product( n: f64, log_base2k: usize,
@@ -1,95 +1,582 @@
-#[cfg(test)] -mod tests { - use base2k::{ - FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxDftOps, ScratchOwned, Stats, VecZnxBig, VecZnxBigAlloc, VecZnxBigOps, - VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxOps, ZnxZero, - }; - use sampling::source::Source; +use base2k::{ + FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxDftOps, ScratchOwned, Stats, VecZnxBig, VecZnxBigAlloc, VecZnxBigOps, + VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxOps, VecZnxToMut, ZnxViewMut, ZnxZero, +}; +use sampling::source::Source; + +use crate::{ + elem::{GetRow, Infos, ProdInplace, ProdInplaceScratchSpace, ProdScratchSpace, Product}, + grlwe::GRLWECt, + keys::{SecretKey, SecretKeyDft}, + rgsw::RGSWCt, + rlwe::{RLWECtDft, RLWEPt}, + test_fft64::grlwe::noise_grlwe_rlwe_product, +}; + +#[test] +fn encrypt_rgsw_sk() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 8; + let log_k_ct: usize = 54; + let rows: usize = 4; + + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; + + let mut ct: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_ct, rows); + let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); + let mut pt_scalar: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); + + pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs); + + let mut scratch: ScratchOwned = ScratchOwned::new( + RGSWCt::encrypt_sk_scratch_space(&module, ct.size()) | RLWECtDft::decrypt_scratch_space(&module, ct.size()), + ); + + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); + + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); + + ct.encrypt_sk( + &module, + &pt_scalar, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); + + let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_ct); + let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct.size()); + let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct.size()); + + (0..ct.cols()).for_each(|col_j| { + (0..ct.rows()).for_each(|row_i| { + module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_scalar, 0); + + if col_j == 1 { + module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0); + module.svp_apply_inplace(&mut pt_dft, 0, &sk_dft, 0); + module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0); + module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow()); + } + + ct.get_row(&module, row_i, col_j, &mut ct_rlwe_dft); + + ct_rlwe_dft.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); + + module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); + + let std_pt: f64 = pt_have.data.std(0, log_base2k) * (log_k_ct as f64).exp2(); + assert!((sigma - std_pt).abs() <= 0.2, "{} {}", sigma, std_pt); + + pt_want.data.zero(); + }); + }); + + module.free(); +} + +#[test] +fn from_prod_by_grlwe() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let log_k_rgsw_in: usize = 45; + let log_k_rgsw_out: usize = 45; + let rows: usize = (log_k_rgsw_in + log_base2k - 1) / log_base2k; + + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; + + let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rgsw_in: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_rgsw_in, rows); + let mut ct_rgsw_out: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_rgsw_out, rows); + let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); + + // Random input plaintext + pt_rgsw.fill_ternary_prob(0, 0.5, &mut source_xs); + + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) + | RLWECtDft::decrypt_scratch_space(&module, ct_rgsw_out.size()) + | RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw_in.size()) + | RGSWCt::prod_by_grlwe_scratch_space( + &module, + ct_rgsw_out.size(), + ct_rgsw_in.size(), + ct_grlwe.size(), + ), + ); + + let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk0.fill_ternary_prob(0.5, &mut source_xs); + + let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk0_dft.dft(&module, &sk0); + + let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk1.fill_ternary_prob(0.5, &mut source_xs); + + let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk1_dft.dft(&module, &sk1); + + ct_grlwe.encrypt_sk( + &module, + &sk0.data, + &sk1_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); + + ct_rgsw_in.encrypt_sk( + &module, + &pt_rgsw, + &sk0_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); + + ct_rgsw_out.prod_by_grlwe(&module, &ct_rgsw_in, &ct_grlwe, scratch.borrow()); + + let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rgsw_out); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rgsw_out); + let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_rgsw_out.size()); + let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_rgsw_out.size()); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rgsw_out); + + (0..ct_rgsw_out.cols()).for_each(|col_j| { + (0..ct_rgsw_out.rows()).for_each(|row_i| { + module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_rgsw, 0); + + if col_j == 1 { + module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0); + module.svp_apply_inplace(&mut pt_dft, 0, &sk0_dft, 0); + module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0); + module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow()); + } + + ct_rgsw_out.get_row(&module, row_i, col_j, &mut ct_rlwe_dft); + ct_rlwe_dft.decrypt(&module, &mut pt, &sk1_dft, scratch.borrow()); + + module.vec_znx_sub_ab_inplace(&mut pt, 0, &pt_want, 0); + + let noise_have: f64 = pt.data.std(0, log_base2k).log2(); + let noise_want: f64 = noise_grlwe_rlwe_product( + module.n() as f64, + log_base2k, + 0.5, + 0.5, + 0f64, + sigma * sigma, + 0f64, + log_k_grlwe, + log_k_grlwe, + ); + + assert!( + (noise_have - noise_want).abs() <= 0.2, + "have: {} want: {}", + noise_have, + noise_want + ); + + pt_want.data.zero(); + }); + }); + + module.free(); +} + +#[test] +fn from_prod_by_grlwe_inplace() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let log_k_rgsw: usize = 45; + let rows: usize = (log_k_rgsw + log_base2k - 1) / log_base2k; + + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; + + let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_rgsw, rows); + let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); + + // Random input plaintext + pt_rgsw.fill_ternary_prob(0, 0.5, &mut source_xs); + + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) + | RLWECtDft::decrypt_scratch_space(&module, ct_rgsw.size()) + | RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()) + | RGSWCt::prod_by_grlwe_inplace_scratch_space(&module, ct_rgsw.size(), ct_grlwe.size()), + ); + + let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk0.fill_ternary_prob(0.5, &mut source_xs); + + let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk0_dft.dft(&module, &sk0); + + let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk1.fill_ternary_prob(0.5, &mut source_xs); + + let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk1_dft.dft(&module, &sk1); + + ct_grlwe.encrypt_sk( + &module, + &sk0.data, + &sk1_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); + + ct_rgsw.encrypt_sk( + &module, + &pt_rgsw, + &sk0_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); + + ct_rgsw.prod_by_grlwe_inplace(&module, &ct_grlwe, scratch.borrow()); + + let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rgsw); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rgsw); + let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_rgsw.size()); + let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_rgsw.size()); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rgsw); + + (0..ct_rgsw.cols()).for_each(|col_j| { + (0..ct_rgsw.rows()).for_each(|row_i| { + module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_rgsw, 0); + + if col_j == 1 { + module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0); + module.svp_apply_inplace(&mut pt_dft, 0, &sk0_dft, 0); + module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0); + module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow()); + } + + ct_rgsw.get_row(&module, row_i, col_j, &mut ct_rlwe_dft); + ct_rlwe_dft.decrypt(&module, &mut pt, &sk1_dft, scratch.borrow()); + + module.vec_znx_sub_ab_inplace(&mut pt, 0, &pt_want, 0); + + let noise_have: f64 = pt.data.std(0, log_base2k).log2(); + let noise_want: f64 = noise_grlwe_rlwe_product( + module.n() as f64, + log_base2k, + 0.5, + 0.5, + 0f64, + sigma * sigma, + 0f64, + log_k_grlwe, + log_k_grlwe, + ); + + assert!( + (noise_have - noise_want).abs() <= 0.2, + "have: {} want: {}", + noise_have, + noise_want + ); + + pt_want.data.zero(); + }); + }); + + module.free(); +} + +#[test] +fn from_prod_by_rgsw() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_rgsw_rhs: usize = 60; + let log_k_rgsw_lhs_in: usize = 45; + let log_k_rgsw_lhs_out: usize = 45; + let rows: usize = (log_k_rgsw_lhs_in + log_base2k - 1) / log_base2k; + + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; + + let mut ct_rgsw_rhs: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_rgsw_rhs, rows); + let mut ct_rgsw_lhs_in: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_rgsw_lhs_in, rows); + let mut ct_rgsw_lhs_out: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_rgsw_lhs_out, rows); + let mut pt_rgsw_lhs: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + let mut pt_rgsw_rhs: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); + + // Random input plaintext + pt_rgsw_lhs.fill_ternary_prob(0, 0.5, &mut source_xs); + + let k: usize = 1; + + pt_rgsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k} + + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_rgsw_rhs.size()) + | RLWECtDft::decrypt_scratch_space(&module, ct_rgsw_lhs_out.size()) + | RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw_lhs_in.size()) + | RGSWCt::prod_by_rgsw_scratch_space( + &module, + ct_rgsw_lhs_out.size(), + ct_rgsw_lhs_in.size(), + ct_rgsw_rhs.size(), + ), + ); + + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); + + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); + + ct_rgsw_rhs.encrypt_sk( + &module, + &pt_rgsw_rhs, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); + + ct_rgsw_lhs_in.encrypt_sk( + &module, + &pt_rgsw_lhs, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); + + ct_rgsw_lhs_out.prod_by_rgsw(&module, &ct_rgsw_lhs_in, &ct_rgsw_rhs, scratch.borrow()); + + let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rgsw_lhs_out); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rgsw_lhs_out); + let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_rgsw_lhs_out.size()); + let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_rgsw_lhs_out.size()); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rgsw_lhs_out); + + module.vec_znx_rotate_inplace(k as i64, &mut pt_rgsw_lhs, 0); + + (0..ct_rgsw_lhs_out.cols()).for_each(|col_j| { + (0..ct_rgsw_lhs_out.rows()).for_each(|row_i| { + module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_rgsw_lhs, 0); + + if col_j == 1 { + module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0); + module.svp_apply_inplace(&mut pt_dft, 0, &sk_dft, 0); + module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0); + module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow()); + } + + ct_rgsw_lhs_out.get_row(&module, row_i, col_j, &mut ct_rlwe_dft); + ct_rlwe_dft.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); + + module.vec_znx_sub_ab_inplace(&mut pt, 0, &pt_want, 0); + + let noise_have: f64 = pt.data.std(0, log_base2k).log2(); + + let var_gct_err_lhs: f64 = sigma * sigma; + let var_gct_err_rhs: f64 = 0f64; + + let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} + let var_a0_err: f64 = sigma * sigma; + let var_a1_err: f64 = 1f64 / 12f64; + + let noise_want: f64 = noise_rgsw_product( + module.n() as f64, + log_base2k, + 0.5, + var_msg, + var_a0_err, + var_a1_err, + var_gct_err_lhs, + var_gct_err_rhs, + log_k_rgsw_lhs_in, + log_k_rgsw_rhs, + ); + + assert!( + (noise_have - noise_want).abs() <= 0.1, + "have: {} want: {}", + noise_have, + noise_want + ); + + pt_want.data.zero(); + }); + }); + + module.free(); +} + +#[test] +fn from_prod_by_rgsw_inplace() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_rgsw_rhs: usize = 60; + let log_k_rgsw_lhs: usize = 45; + let rows: usize = (log_k_rgsw_lhs + log_base2k - 1) / log_base2k; + + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; + + let mut ct_rgsw_rhs: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_rgsw_rhs, rows); + let mut ct_rgsw_lhs: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_rgsw_lhs, rows); + let mut pt_rgsw_lhs: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + let mut pt_rgsw_rhs: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - use crate::{ - elem::{GetRow, Infos}, - keys::{SecretKey, SecretKeyDft}, - rgsw::RGSWCt, - rlwe::{RLWECt, RLWECtDft, RLWEPt}, - test_fft64::rgsw::noise_rgsw_rlwe_product, - }; + // Random input plaintext + pt_rgsw_lhs.fill_ternary_prob(0, 0.5, &mut source_xs); - #[test] - fn encrypt_rgsw_sk() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 8; - let log_k_ct: usize = 54; - let rows: usize = 4; + let k: usize = 1; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + pt_rgsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k} - let mut ct: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_ct, rows); - let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); - let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); - let mut pt_scalar: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_rgsw_rhs.size()) + | RLWECtDft::decrypt_scratch_space(&module, ct_rgsw_lhs.size()) + | RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw_lhs.size()) + | RGSWCt::prod_by_rgsw_inplace_scratch_space(&module, ct_rgsw_lhs.size(), ct_rgsw_rhs.size()), + ); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); - pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs); + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); - let mut scratch: ScratchOwned = ScratchOwned::new( - RGSWCt::encrypt_sk_scratch_space(&module, ct.size()) | RLWECtDft::decrypt_scratch_space(&module, ct.size()), - ); + ct_rgsw_rhs.encrypt_sk( + &module, + &pt_rgsw_rhs, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); + ct_rgsw_lhs.encrypt_sk( + &module, + &pt_rgsw_lhs, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + ct_rgsw_lhs.prod_by_rgsw_inplace(&module, &ct_rgsw_rhs, scratch.borrow()); - ct.encrypt_sk( - &module, - &pt_scalar, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rgsw_lhs); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rgsw_lhs); + let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_rgsw_lhs.size()); + let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_rgsw_lhs.size()); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rgsw_lhs); - let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_ct); - let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct.size()); - let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct.size()); + module.vec_znx_rotate_inplace(k as i64, &mut pt_rgsw_lhs, 0); - (0..ct.cols()).for_each(|col_j| { - (0..ct.rows()).for_each(|row_i| { - module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_scalar, 0); + (0..ct_rgsw_lhs.cols()).for_each(|col_j| { + (0..ct_rgsw_lhs.rows()).for_each(|row_i| { + module.vec_znx_add_scalar_inplace(&mut pt_want, 0, row_i, &pt_rgsw_lhs, 0); - if col_j == 1 { - module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0); - module.svp_apply_inplace(&mut pt_dft, 0, &sk_dft, 0); - module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0); - module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow()); - } + if col_j == 1 { + module.vec_znx_dft(&mut pt_dft, 0, &pt_want, 0); + module.svp_apply_inplace(&mut pt_dft, 0, &sk_dft, 0); + module.vec_znx_idft_tmp_a(&mut pt_big, 0, &mut pt_dft, 0); + module.vec_znx_big_normalize(log_base2k, &mut pt_want, 0, &pt_big, 0, scratch.borrow()); + } - ct.get_row(&module, row_i, col_j, &mut ct_rlwe_dft); + ct_rgsw_lhs.get_row(&module, row_i, col_j, &mut ct_rlwe_dft); + ct_rlwe_dft.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); - ct_rlwe_dft.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); + module.vec_znx_sub_ab_inplace(&mut pt, 0, &pt_want, 0); - module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); + let noise_have: f64 = pt.data.std(0, log_base2k).log2(); - let std_pt: f64 = pt_have.data.std(0, log_base2k) * (log_k_ct as f64).exp2(); - assert!((sigma - std_pt).abs() <= 0.2, "{} {}", sigma, std_pt); + let var_gct_err_lhs: f64 = sigma * sigma; + let var_gct_err_rhs: f64 = 0f64; + + let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} + let var_a0_err: f64 = sigma * sigma; + let var_a1_err: f64 = 1f64 / 12f64; + + let noise_want: f64 = noise_rgsw_product( + module.n() as f64, + log_base2k, + 0.5, + var_msg, + var_a0_err, + var_a1_err, + var_gct_err_lhs, + var_gct_err_rhs, + log_k_rgsw_lhs, + log_k_rgsw_rhs, + ); - pt_want.data.zero(); - }); + assert!( + (noise_have - noise_want).abs() <= 0.1, + "have: {} want: {}", + noise_have, + noise_want + ); + + pt_want.data.zero(); }); + }); - module.free(); - } + module.free(); } -#[allow(dead_code)] -pub(crate) fn noise_rgsw_rlwe_product( +pub(crate) fn noise_rgsw_product( n: f64, log_base2k: usize, var_xs: f64,
@@ -1,621 +1,618 @@
-#[cfg(test)] -mod tests_rlwe { - use base2k::{ - Decoding, Encoding, FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, VecZnxToMut, - ZnxViewMut, ZnxZero, - }; - use itertools::izip; - use sampling::source::Source; +use base2k::{ + Decoding, Encoding, FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, VecZnxToMut, + ZnxViewMut, ZnxZero, +}; +use itertools::izip; +use sampling::source::Source; - use crate::{ - elem::{FromProdBy, FromProdByScratchSpace, Infos, ProdBy, ProdByScratchSpace}, - grlwe::GRLWECt, - keys::{PublicKey, SecretKey, SecretKeyDft}, - rgsw::RGSWCt, - rlwe::{RLWECt, RLWECtDft, RLWEPt}, - test_fft64::{grlwe::noise_grlwe_rlwe_product, rgsw::noise_rgsw_rlwe_product}, - }; +use crate::{ + elem::{Infos, ProdInplace, ProdInplaceScratchSpace, ProdScratchSpace, Product}, + grlwe::GRLWECt, + keys::{PublicKey, SecretKey, SecretKeyDft}, + rgsw::RGSWCt, + rlwe::{RLWECt, RLWECtDft, RLWEPt}, + test_fft64::{grlwe::noise_grlwe_rlwe_product, rgsw::noise_rgsw_product}, +}; - #[test] - fn encrypt_sk() { - let module: Module<FFT64> = Module::<FFT64>::new(32); - let log_base2k: usize = 8; - let log_k_ct: usize = 54; - let log_k_pt: usize = 30; +#[test] +fn encrypt_sk() { + let module: Module<FFT64> = Module::<FFT64>::new(32); + let log_base2k: usize = 8; + let log_k_ct: usize = 54; + let log_k_pt: usize = 30; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut ct: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_ct); - let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_pt); + let mut ct: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_ct); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_pt); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - let mut scratch: ScratchOwned = ScratchOwned::new( - RLWECt::encrypt_sk_scratch_space(&module, ct.size()) | RLWECt::decrypt_scratch_space(&module, ct.size()), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + RLWECt::encrypt_sk_scratch_space(&module, ct.size()) | RLWECt::decrypt_scratch_space(&module, ct.size()), + ); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); - let mut data_want: Vec<i64> = vec![0i64; module.n()]; + let mut data_want: Vec<i64> = vec![0i64; module.n()]; - data_want - .iter_mut() - .for_each(|x| *x = source_xa.next_i64() & 0xFF); + data_want + .iter_mut() + .for_each(|x| *x = source_xa.next_i64() & 0xFF); - pt.data - .encode_vec_i64(0, log_base2k, log_k_pt, &data_want, 10); + pt.data + .encode_vec_i64(0, log_base2k, log_k_pt, &data_want, 10); - ct.encrypt_sk( - &module, - Some(&pt), - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct.encrypt_sk( + &module, + Some(&pt), + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - pt.data.zero(); + pt.data.zero(); - ct.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); + ct.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); - let mut data_have: Vec<i64> = vec![0i64; module.n()]; + let mut data_have: Vec<i64> = vec![0i64; module.n()]; - pt.data - .decode_vec_i64(0, log_base2k, pt.size() * log_base2k, &mut data_have); + pt.data + .decode_vec_i64(0, log_base2k, pt.size() * log_base2k, &mut data_have); - // TODO: properly assert the decryption noise through std(dec(ct) - pt) - let scale: f64 = (1 << (pt.size() * log_base2k - log_k_pt)) as f64; - izip!(data_want.iter(), data_have.iter()).for_each(|(a, b)| { - let b_scaled = (*b as f64) / scale; - assert!( - (*a as f64 - b_scaled).abs() < 0.1, - "{} {}", - *a as f64, - b_scaled - ) - }); + // TODO: properly assert the decryption noise through std(dec(ct) - pt) + let scale: f64 = (1 << (pt.size() * log_base2k - log_k_pt)) as f64; + izip!(data_want.iter(), data_have.iter()).for_each(|(a, b)| { + let b_scaled = (*b as f64) / scale; + assert!( + (*a as f64 - b_scaled).abs() < 0.1, + "{} {}", + *a as f64, + b_scaled + ) + }); - module.free(); - } + module.free(); +} - #[test] - fn encrypt_zero_sk() { - let module: Module<FFT64> = Module::<FFT64>::new(1024); - let log_base2k: usize = 8; - let log_k_ct: usize = 55; +#[test] +fn encrypt_zero_sk() { + let module: Module<FFT64> = Module::<FFT64>::new(1024); + let log_base2k: usize = 8; + let log_k_ct: usize = 55; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); + let mut pt: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([1u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([1u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); - let mut ct_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_ct); + let mut ct_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_ct); - let mut scratch: ScratchOwned = ScratchOwned::new( - RLWECtDft::decrypt_scratch_space(&module, ct_dft.size()) - | RLWECtDft::encrypt_zero_sk_scratch_space(&module, ct_dft.size()), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + RLWECtDft::decrypt_scratch_space(&module, ct_dft.size()) + | RLWECtDft::encrypt_zero_sk_scratch_space(&module, ct_dft.size()), + ); - ct_dft.encrypt_zero_sk( - &module, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); - ct_dft.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); + ct_dft.encrypt_zero_sk( + &module, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); + ct_dft.decrypt(&module, &mut pt, &sk_dft, scratch.borrow()); - assert!((sigma - pt.data.std(0, log_base2k) * (log_k_ct as f64).exp2()) <= 0.2); - module.free(); - } + assert!((sigma - pt.data.std(0, log_base2k) * (log_k_ct as f64).exp2()) <= 0.2); + module.free(); +} - #[test] - fn encrypt_pk() { - let module: Module<FFT64> = Module::<FFT64>::new(32); - let log_base2k: usize = 8; - let log_k_ct: usize = 54; - let log_k_pk: usize = 64; +#[test] +fn encrypt_pk() { + let module: Module<FFT64> = Module::<FFT64>::new(32); + let log_base2k: usize = 8; + let log_k_ct: usize = 54; + let log_k_pk: usize = 64; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut ct: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_ct); - let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); + let mut ct: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_ct); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); - let mut source_xu: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xu: Source = Source::new([0u8; 32]); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); - let mut pk: PublicKey<Vec<u8>, FFT64> = PublicKey::new(&module, log_base2k, log_k_pk); - pk.generate( - &module, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - ); + let mut pk: PublicKey<Vec<u8>, FFT64> = PublicKey::new(&module, log_base2k, log_k_pk); + pk.generate( + &module, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + ); - let mut scratch: ScratchOwned = ScratchOwned::new( - RLWECt::encrypt_sk_scratch_space(&module, ct.size()) - | RLWECt::decrypt_scratch_space(&module, ct.size()) - | RLWECt::encrypt_pk_scratch_space(&module, pk.size()), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + RLWECt::encrypt_sk_scratch_space(&module, ct.size()) + | RLWECt::decrypt_scratch_space(&module, ct.size()) + | RLWECt::encrypt_pk_scratch_space(&module, pk.size()), + ); - let mut data_want: Vec<i64> = vec![0i64; module.n()]; + let mut data_want: Vec<i64> = vec![0i64; module.n()]; - data_want - .iter_mut() - .for_each(|x| *x = source_xa.next_i64() & 0); + data_want + .iter_mut() + .for_each(|x| *x = source_xa.next_i64() & 0); - pt_want - .data - .encode_vec_i64(0, log_base2k, log_k_ct, &data_want, 10); + pt_want + .data + .encode_vec_i64(0, log_base2k, log_k_ct, &data_want, 10); - ct.encrypt_pk( - &module, - Some(&pt_want), - &pk, - &mut source_xu, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct.encrypt_pk( + &module, + Some(&pt_want), + &pk, + &mut source_xu, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); + let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_ct); - ct.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); + ct.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); - module.vec_znx_sub_ab_inplace(&mut pt_want, 0, &pt_have, 0); + module.vec_znx_sub_ab_inplace(&mut pt_want, 0, &pt_have, 0); - assert!(((1.0f64 / 12.0).sqrt() - pt_want.data.std(0, log_base2k) * (log_k_ct as f64).exp2()).abs() < 0.2); + assert!(((1.0f64 / 12.0).sqrt() - pt_want.data.std(0, log_base2k) * (log_k_ct as f64).exp2()).abs() < 0.2); - module.free(); - } + module.free(); +} - #[test] - fn from_prod_by_grlwe() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe_in: usize = 45; - let log_k_rlwe_out: usize = 60; - let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; +#[test] +fn prod_by_grlwe() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let log_k_rlwe_in: usize = 45; + let log_k_rlwe_out: usize = 60; + let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); - let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out); - let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); - let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); + let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); + let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); + let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - // Random input plaintext - pt_want - .data - .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); + // Random input plaintext + pt_want + .data + .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); - let mut scratch: ScratchOwned = ScratchOwned::new( - GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) - | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size()) - | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size()) - | RLWECt::from_prod_by_grlwe_scratch_space( - &module, - ct_rlwe_out.size(), - ct_rlwe_in.size(), - ct_grlwe.size(), - ), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) + | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size()) + | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size()) + | RLWECt::prod_by_grlwe_scratch_space( + &module, + ct_rlwe_out.size(), + ct_rlwe_in.size(), + ct_grlwe.size(), + ), + ); - let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk0.fill_ternary_prob(0.5, &mut source_xs); + let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk0.fill_ternary_prob(0.5, &mut source_xs); - let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk0_dft.dft(&module, &sk0); + let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk0_dft.dft(&module, &sk0); - let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk1.fill_ternary_prob(0.5, &mut source_xs); + let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk1.fill_ternary_prob(0.5, &mut source_xs); - let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk1_dft.dft(&module, &sk1); + let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk1_dft.dft(&module, &sk1); - ct_grlwe.encrypt_sk( - &module, - &sk0.data, - &sk1_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_grlwe.encrypt_sk( + &module, + &sk0.data, + &sk1_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe_in.encrypt_sk( - &module, - Some(&pt_want), - &sk0_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rlwe_in.encrypt_sk( + &module, + Some(&pt_want), + &sk0_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe_out.from_prod_by_grlwe(&module, &ct_rlwe_in, &ct_grlwe, scratch.borrow()); + ct_rlwe_out.prod_by_grlwe(&module, &ct_rlwe_in, &ct_grlwe, scratch.borrow()); - ct_rlwe_out.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow()); + ct_rlwe_out.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow()); - module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); + module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); - let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); - let noise_want: f64 = noise_grlwe_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - 0.5, - 0f64, - sigma * sigma, - 0f64, - log_k_rlwe_in, - log_k_grlwe, - ); + let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); + let noise_want: f64 = noise_grlwe_rlwe_product( + module.n() as f64, + log_base2k, + 0.5, + 0.5, + 0f64, + sigma * sigma, + 0f64, + log_k_rlwe_in, + log_k_grlwe, + ); - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want + ); - module.free(); - } + module.free(); +} - #[test] - fn prod_grlwe() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe: usize = 45; - let rows: usize = (log_k_rlwe + log_base2k - 1) / log_base2k; +#[test] +fn prod_by_grlwe_inplace() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let log_k_rlwe: usize = 45; + let rows: usize = (log_k_rlwe + log_base2k - 1) / log_base2k; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe); - let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe); - let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe); + let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe); + let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - // Random input plaintext - pt_want - .data - .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); + // Random input plaintext + pt_want + .data + .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); - let mut scratch: ScratchOwned = ScratchOwned::new( - GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) - | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size()) - | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size()) - | RLWECt::prod_by_grlwe_scratch_space(&module, ct_rlwe.size(), ct_grlwe.size()), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) + | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size()) + | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size()) + | RLWECt::prod_by_grlwe_inplace_scratch_space(&module, ct_rlwe.size(), ct_grlwe.size()), + ); - let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk0.fill_ternary_prob(0.5, &mut source_xs); + let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk0.fill_ternary_prob(0.5, &mut source_xs); - let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk0_dft.dft(&module, &sk0); + let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk0_dft.dft(&module, &sk0); - let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk1.fill_ternary_prob(0.5, &mut source_xs); + let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk1.fill_ternary_prob(0.5, &mut source_xs); - let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk1_dft.dft(&module, &sk1); + let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk1_dft.dft(&module, &sk1); - ct_grlwe.encrypt_sk( - &module, - &sk0.data, - &sk1_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_grlwe.encrypt_sk( + &module, + &sk0.data, + &sk1_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe.encrypt_sk( - &module, - Some(&pt_want), - &sk0_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rlwe.encrypt_sk( + &module, + Some(&pt_want), + &sk0_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe.prod_by_grlwe(&module, &ct_grlwe, scratch.borrow()); + ct_rlwe.prod_by_grlwe_inplace(&module, &ct_grlwe, scratch.borrow()); - ct_rlwe.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow()); + ct_rlwe.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow()); - module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); + module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); - let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); - let noise_want: f64 = noise_grlwe_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - 0.5, - 0f64, - sigma * sigma, - 0f64, - log_k_rlwe, - log_k_grlwe, - ); + let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); + let noise_want: f64 = noise_grlwe_rlwe_product( + module.n() as f64, + log_base2k, + 0.5, + 0.5, + 0f64, + sigma * sigma, + 0f64, + log_k_rlwe, + log_k_grlwe, + ); - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want + ); - module.free(); - } + module.free(); +} - #[test] - fn from_prod_by_rgsw() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe_in: usize = 45; - let log_k_rlwe_out: usize = 60; - let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; +#[test] +fn prod_by_rgsw() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let log_k_rlwe_in: usize = 45; + let log_k_rlwe_out: usize = 60; + let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); - let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out); - let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); - let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); - let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); + let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); + let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out); + let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); + let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - // Random input plaintext - pt_want - .data - .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); + // Random input plaintext + pt_want + .data + .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); - pt_want.to_mut().at_mut(0, 0)[1] = 1; + pt_want.to_mut().at_mut(0, 0)[1] = 1; - let k: usize = 1; + let k: usize = 1; - pt_rgsw.raw_mut()[k] = 1; // X^{k} + pt_rgsw.raw_mut()[k] = 1; // X^{k} - let mut scratch: ScratchOwned = ScratchOwned::new( - RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()) - | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size()) - | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size()) - | RLWECt::from_prod_by_rgsw_scratch_space( - &module, - ct_rlwe_out.size(), - ct_rlwe_in.size(), - ct_rgsw.size(), - ), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()) + | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size()) + | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size()) + | RLWECt::prod_by_grlwe_scratch_space( + &module, + ct_rlwe_out.size(), + ct_rlwe_in.size(), + ct_rgsw.size(), + ), + ); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); - ct_rgsw.encrypt_sk( - &module, - &pt_rgsw, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rgsw.encrypt_sk( + &module, + &pt_rgsw, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe_in.encrypt_sk( - &module, - Some(&pt_want), - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rlwe_in.encrypt_sk( + &module, + Some(&pt_want), + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe_out.from_prod_by_rgsw(&module, &ct_rlwe_in, &ct_rgsw, scratch.borrow()); + ct_rlwe_out.prod_by_rgsw(&module, &ct_rlwe_in, &ct_rgsw, scratch.borrow()); - ct_rlwe_out.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); + ct_rlwe_out.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); - module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0); + module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0); - module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); + module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); - let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); + let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); - let var_gct_err_lhs: f64 = sigma * sigma; - let var_gct_err_rhs: f64 = 0f64; + let var_gct_err_lhs: f64 = sigma * sigma; + let var_gct_err_rhs: f64 = 0f64; - let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} - let var_a0_err: f64 = sigma * sigma; - let var_a1_err: f64 = 1f64 / 12f64; + let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} + let var_a0_err: f64 = sigma * sigma; + let var_a1_err: f64 = 1f64 / 12f64; - let noise_want: f64 = noise_rgsw_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - var_msg, - var_a0_err, - var_a1_err, - var_gct_err_lhs, - var_gct_err_rhs, - log_k_rlwe_in, - log_k_grlwe, - ); + let noise_want: f64 = noise_rgsw_product( + module.n() as f64, + log_base2k, + 0.5, + var_msg, + var_a0_err, + var_a1_err, + var_gct_err_lhs, + var_gct_err_rhs, + log_k_rlwe_in, + log_k_grlwe, + ); - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want + ); - module.free(); - } + module.free(); +} - #[test] - fn prod_by_rgsw() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe_in: usize = 45; - let log_k_rlwe_out: usize = 60; - let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; +#[test] +fn prod_by_rgsw_inplace() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let log_k_rlwe_in: usize = 45; + let log_k_rlwe_out: usize = 60; + let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); - let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); - let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); - let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); + let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); + let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); + let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - // Random input plaintext - pt_want - .data - .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); + // Random input plaintext + pt_want + .data + .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); - pt_want.to_mut().at_mut(0, 0)[1] = 1; + pt_want.to_mut().at_mut(0, 0)[1] = 1; - let k: usize = 1; + let k: usize = 1; - pt_rgsw.raw_mut()[k] = 1; // X^{k} + pt_rgsw.raw_mut()[k] = 1; // X^{k} - let mut scratch: ScratchOwned = ScratchOwned::new( - RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()) - | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size()) - | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size()) - | RLWECt::prod_by_rgsw_scratch_space(&module, ct_rlwe.size(), ct_rgsw.size()), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()) + | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size()) + | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size()) + | RLWECt::prod_by_rgsw_inplace_scratch_space(&module, ct_rlwe.size(), ct_rgsw.size()), + ); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); - ct_rgsw.encrypt_sk( - &module, - &pt_rgsw, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rgsw.encrypt_sk( + &module, + &pt_rgsw, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe.encrypt_sk( - &module, - Some(&pt_want), - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rlwe.encrypt_sk( + &module, + Some(&pt_want), + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe.prod_by_rgsw(&module, &ct_rgsw, scratch.borrow()); + ct_rlwe.prod_by_rgsw_inplace(&module, &ct_rgsw, scratch.borrow()); - ct_rlwe.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); + ct_rlwe.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); - module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0); + module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0); - module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); + module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); - let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); + let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); - let var_gct_err_lhs: f64 = sigma * sigma; - let var_gct_err_rhs: f64 = 0f64; + let var_gct_err_lhs: f64 = sigma * sigma; + let var_gct_err_rhs: f64 = 0f64; - let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} - let var_a0_err: f64 = sigma * sigma; - let var_a1_err: f64 = 1f64 / 12f64; + let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} + let var_a0_err: f64 = sigma * sigma; + let var_a1_err: f64 = 1f64 / 12f64; - let noise_want: f64 = noise_rgsw_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - var_msg, - var_a0_err, - var_a1_err, - var_gct_err_lhs, - var_gct_err_rhs, - log_k_rlwe_in, - log_k_grlwe, - ); + let noise_want: f64 = noise_rgsw_product( + module.n() as f64, + log_base2k, + 0.5, + var_msg, + var_a0_err, + var_a1_err, + var_gct_err_lhs, + var_gct_err_rhs, + log_k_rlwe_in, + log_k_grlwe, + ); - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want + ); - module.free(); - } + module.free(); }
@@ -1,448 +1,443 @@
-#[cfg(test)] -mod tests { - use crate::{ - elem::{FromProdBy, FromProdByScratchSpace, Infos, ProdBy, ProdByScratchSpace}, - grlwe::GRLWECt, - keys::{SecretKey, SecretKeyDft}, - rgsw::RGSWCt, - rlwe::{RLWECt, RLWECtDft, RLWEPt}, - test_fft64::{grlwe::noise_grlwe_rlwe_product, rgsw::noise_rgsw_rlwe_product}, - }; - use base2k::{ - FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, VecZnxToMut, ZnxViewMut, - }; - use sampling::source::Source; +use crate::{ + elem::{Infos, ProdInplace, ProdInplaceScratchSpace, ProdScratchSpace, Product}, + grlwe::GRLWECt, + keys::{SecretKey, SecretKeyDft}, + rgsw::RGSWCt, + rlwe::{RLWECt, RLWECtDft, RLWEPt}, + test_fft64::{grlwe::noise_grlwe_rlwe_product, rgsw::noise_rgsw_product}, +}; +use base2k::{FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, VecZnxToMut, ZnxViewMut}; +use sampling::source::Source; - #[test] - fn from_prod_by_grlwe() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe_in: usize = 45; - let log_k_rlwe_out: usize = 60; - let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; +#[test] +fn by_grlwe_inplace() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let log_k_rlwe_in: usize = 45; + let log_k_rlwe_out: usize = 60; + let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); - let mut ct_rlwe_in_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_in); - let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out); - let mut ct_rlwe_out_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_out); - let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); - let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); + let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); + let mut ct_rlwe_in_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_in); + let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out); + let mut ct_rlwe_out_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_out); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); + let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - // Random input plaintext - pt_want - .data - .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); + // Random input plaintext + pt_want + .data + .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); - let mut scratch: ScratchOwned = ScratchOwned::new( - GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) - | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size()) - | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size()) - | RLWECtDft::from_prod_by_grlwe_scratch_space( - &module, - ct_rlwe_out.size(), - ct_rlwe_in.size(), - ct_grlwe.size(), - ), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) + | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size()) + | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size()) + | RLWECtDft::prod_by_grlwe_scratch_space( + &module, + ct_rlwe_out.size(), + ct_rlwe_in.size(), + ct_grlwe.size(), + ), + ); - let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk0.fill_ternary_prob(0.5, &mut source_xs); + let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk0.fill_ternary_prob(0.5, &mut source_xs); - let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk0_dft.dft(&module, &sk0); + let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk0_dft.dft(&module, &sk0); - let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk1.fill_ternary_prob(0.5, &mut source_xs); + let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk1.fill_ternary_prob(0.5, &mut source_xs); - let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk1_dft.dft(&module, &sk1); + let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk1_dft.dft(&module, &sk1); - ct_grlwe.encrypt_sk( - &module, - &sk0.data, - &sk1_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_grlwe.encrypt_sk( + &module, + &sk0.data, + &sk1_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe_in.encrypt_sk( - &module, - Some(&pt_want), - &sk0_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rlwe_in.encrypt_sk( + &module, + Some(&pt_want), + &sk0_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe_in.dft(&module, &mut ct_rlwe_in_dft); - ct_rlwe_out_dft.from_prod_by_grlwe(&module, &ct_rlwe_in_dft, &ct_grlwe, scratch.borrow()); - ct_rlwe_out_dft.idft(&module, &mut ct_rlwe_out, scratch.borrow()); + ct_rlwe_in.dft(&module, &mut ct_rlwe_in_dft); + ct_rlwe_out_dft.prod_by_grlwe(&module, &ct_rlwe_in_dft, &ct_grlwe, scratch.borrow()); + ct_rlwe_out_dft.idft(&module, &mut ct_rlwe_out, scratch.borrow()); - ct_rlwe_out.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow()); + ct_rlwe_out.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow()); - module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); + module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); - let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); - let noise_want: f64 = noise_grlwe_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - 0.5, - 0f64, - sigma * sigma, - 0f64, - log_k_rlwe_in, - log_k_grlwe, - ); + let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); + let noise_want: f64 = noise_grlwe_rlwe_product( + module.n() as f64, + log_base2k, + 0.5, + 0.5, + 0f64, + sigma * sigma, + 0f64, + log_k_rlwe_in, + log_k_grlwe, + ); - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want + ); - module.free(); - } + module.free(); +} - #[test] - fn prod_by_grlwe() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe: usize = 45; - let rows: usize = (log_k_rlwe + log_base2k - 1) / log_base2k; +#[test] +fn prod_by_grlwe_inplace() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let log_k_rlwe: usize = 45; + let rows: usize = (log_k_rlwe + log_base2k - 1) / log_base2k; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe); - let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe); - let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe); - let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe); + let mut ct_grlwe: GRLWECt<Vec<u8>, FFT64> = GRLWECt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe); + let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe); + let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - // Random input plaintext - pt_want - .data - .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); + // Random input plaintext + pt_want + .data + .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); - let mut scratch: ScratchOwned = ScratchOwned::new( - GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) - | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size()) - | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size()) - | RLWECtDft::prod_by_grlwe_scratch_space(&module, ct_rlwe_dft.size(), ct_grlwe.size()), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + GRLWECt::encrypt_sk_scratch_space(&module, ct_grlwe.size()) + | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size()) + | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size()) + | RLWECtDft::prod_by_grlwe_inplace_scratch_space(&module, ct_rlwe_dft.size(), ct_grlwe.size()), + ); - let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk0.fill_ternary_prob(0.5, &mut source_xs); + let mut sk0: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk0.fill_ternary_prob(0.5, &mut source_xs); - let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk0_dft.dft(&module, &sk0); + let mut sk0_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk0_dft.dft(&module, &sk0); - let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk1.fill_ternary_prob(0.5, &mut source_xs); + let mut sk1: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk1.fill_ternary_prob(0.5, &mut source_xs); - let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk1_dft.dft(&module, &sk1); + let mut sk1_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk1_dft.dft(&module, &sk1); - ct_grlwe.encrypt_sk( - &module, - &sk0.data, - &sk1_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_grlwe.encrypt_sk( + &module, + &sk0.data, + &sk1_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe.encrypt_sk( - &module, - Some(&pt_want), - &sk0_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rlwe.encrypt_sk( + &module, + Some(&pt_want), + &sk0_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe.dft(&module, &mut ct_rlwe_dft); - ct_rlwe_dft.prod_by_grlwe(&module, &ct_grlwe, scratch.borrow()); - ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow()); + ct_rlwe.dft(&module, &mut ct_rlwe_dft); + ct_rlwe_dft.prod_by_grlwe_inplace(&module, &ct_grlwe, scratch.borrow()); + ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow()); - ct_rlwe.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow()); + ct_rlwe.decrypt(&module, &mut pt_have, &sk1_dft, scratch.borrow()); - module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); + module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); - let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); - let noise_want: f64 = noise_grlwe_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - 0.5, - 0f64, - sigma * sigma, - 0f64, - log_k_rlwe, - log_k_grlwe, - ); + let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); + let noise_want: f64 = noise_grlwe_rlwe_product( + module.n() as f64, + log_base2k, + 0.5, + 0.5, + 0f64, + sigma * sigma, + 0f64, + log_k_rlwe, + log_k_grlwe, + ); - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want + ); - module.free(); - } + module.free(); +} - #[test] - fn from_prod_by_rgsw() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe_in: usize = 45; - let log_k_rlwe_out: usize = 60; - let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; +#[test] +fn prod_by_rgsw() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let log_k_rlwe_in: usize = 45; + let log_k_rlwe_out: usize = 60; + let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); - let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out); - let mut ct_rlwe_dft_in: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_in); - let mut ct_rlwe_dft_out: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_out); - let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); - let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); - let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); + let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rlwe_in: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); + let mut ct_rlwe_out: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_out); + let mut ct_rlwe_dft_in: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_in); + let mut ct_rlwe_dft_out: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_out); + let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); + let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - // Random input plaintext - pt_want - .data - .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); + // Random input plaintext + pt_want + .data + .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); - pt_want.to_mut().at_mut(0, 0)[1] = 1; + pt_want.to_mut().at_mut(0, 0)[1] = 1; - let k: usize = 1; + let k: usize = 1; - pt_rgsw.raw_mut()[k] = 1; // X^{k} + pt_rgsw.raw_mut()[k] = 1; // X^{k} - let mut scratch: ScratchOwned = ScratchOwned::new( - RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()) - | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size()) - | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size()) - | RLWECt::from_prod_by_rgsw_scratch_space( - &module, - ct_rlwe_out.size(), - ct_rlwe_in.size(), - ct_rgsw.size(), - ), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()) + | RLWECt::decrypt_scratch_space(&module, ct_rlwe_out.size()) + | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe_in.size()) + | RLWECt::prod_by_rgsw_scratch_space( + &module, + ct_rlwe_out.size(), + ct_rlwe_in.size(), + ct_rgsw.size(), + ), + ); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); - ct_rgsw.encrypt_sk( - &module, - &pt_rgsw, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rgsw.encrypt_sk( + &module, + &pt_rgsw, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe_in.encrypt_sk( - &module, - Some(&pt_want), - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rlwe_in.encrypt_sk( + &module, + Some(&pt_want), + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe_in.dft(&module, &mut ct_rlwe_dft_in); - ct_rlwe_dft_out.from_prod_by_rgsw(&module, &ct_rlwe_dft_in, &ct_rgsw, scratch.borrow()); - ct_rlwe_dft_out.idft(&module, &mut ct_rlwe_out, scratch.borrow()); + ct_rlwe_in.dft(&module, &mut ct_rlwe_dft_in); + ct_rlwe_dft_out.prod_by_rgsw(&module, &ct_rlwe_dft_in, &ct_rgsw, scratch.borrow()); + ct_rlwe_dft_out.idft(&module, &mut ct_rlwe_out, scratch.borrow()); - ct_rlwe_out.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); + ct_rlwe_out.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); - module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0); + module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0); - module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); + module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); - let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); + let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); - let var_gct_err_lhs: f64 = sigma * sigma; - let var_gct_err_rhs: f64 = 0f64; + let var_gct_err_lhs: f64 = sigma * sigma; + let var_gct_err_rhs: f64 = 0f64; - let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} - let var_a0_err: f64 = sigma * sigma; - let var_a1_err: f64 = 1f64 / 12f64; + let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} + let var_a0_err: f64 = sigma * sigma; + let var_a1_err: f64 = 1f64 / 12f64; - let noise_want: f64 = noise_rgsw_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - var_msg, - var_a0_err, - var_a1_err, - var_gct_err_lhs, - var_gct_err_rhs, - log_k_rlwe_in, - log_k_grlwe, - ); + let noise_want: f64 = noise_rgsw_product( + module.n() as f64, + log_base2k, + 0.5, + var_msg, + var_a0_err, + var_a1_err, + var_gct_err_lhs, + var_gct_err_rhs, + log_k_rlwe_in, + log_k_grlwe, + ); - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want + ); - module.free(); - } + module.free(); +} - #[test] - fn prod_by_rgsw() { - let module: Module<FFT64> = Module::<FFT64>::new(2048); - let log_base2k: usize = 12; - let log_k_grlwe: usize = 60; - let log_k_rlwe_in: usize = 45; - let log_k_rlwe_out: usize = 60; - let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; +#[test] +fn prod_by_rgsw_inplace() { + let module: Module<FFT64> = Module::<FFT64>::new(2048); + let log_base2k: usize = 12; + let log_k_grlwe: usize = 60; + let log_k_rlwe_in: usize = 45; + let log_k_rlwe_out: usize = 60; + let rows: usize = (log_k_rlwe_in + log_base2k - 1) / log_base2k; - let sigma: f64 = 3.2; - let bound: f64 = sigma * 6.0; + let sigma: f64 = 3.2; + let bound: f64 = sigma * 6.0; - let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); - let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); - let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_in); - let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); - let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); - let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); + let mut ct_rgsw: RGSWCt<Vec<u8>, FFT64> = RGSWCt::new(&module, log_base2k, log_k_grlwe, rows); + let mut ct_rlwe: RLWECt<Vec<u8>> = RLWECt::new(&module, log_base2k, log_k_rlwe_in); + let mut ct_rlwe_dft: RLWECtDft<Vec<u8>, FFT64> = RLWECtDft::new(&module, log_base2k, log_k_rlwe_in); + let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); + let mut pt_want: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_in); + let mut pt_have: RLWEPt<Vec<u8>> = RLWEPt::new(&module, log_base2k, log_k_rlwe_out); - let mut source_xs: Source = Source::new([0u8; 32]); - let mut source_xe: Source = Source::new([0u8; 32]); - let mut source_xa: Source = Source::new([0u8; 32]); + let mut source_xs: Source = Source::new([0u8; 32]); + let mut source_xe: Source = Source::new([0u8; 32]); + let mut source_xa: Source = Source::new([0u8; 32]); - // Random input plaintext - pt_want - .data - .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); + // Random input plaintext + pt_want + .data + .fill_uniform(log_base2k, 0, pt_want.size(), &mut source_xa); - pt_want.to_mut().at_mut(0, 0)[1] = 1; + pt_want.to_mut().at_mut(0, 0)[1] = 1; - let k: usize = 1; + let k: usize = 1; - pt_rgsw.raw_mut()[k] = 1; // X^{k} + pt_rgsw.raw_mut()[k] = 1; // X^{k} - let mut scratch: ScratchOwned = ScratchOwned::new( - RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()) - | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size()) - | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size()) - | RLWECt::prod_by_rgsw_scratch_space(&module, ct_rlwe.size(), ct_rgsw.size()), - ); + let mut scratch: ScratchOwned = ScratchOwned::new( + RGSWCt::encrypt_sk_scratch_space(&module, ct_rgsw.size()) + | RLWECt::decrypt_scratch_space(&module, ct_rlwe.size()) + | RLWECt::encrypt_sk_scratch_space(&module, ct_rlwe.size()) + | RLWECt::prod_by_rgsw_inplace_scratch_space(&module, ct_rlwe.size(), ct_rgsw.size()), + ); - let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); - sk.fill_ternary_prob(0.5, &mut source_xs); + let mut sk: SecretKey<Vec<u8>> = SecretKey::new(&module); + sk.fill_ternary_prob(0.5, &mut source_xs); - let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); - sk_dft.dft(&module, &sk); + let mut sk_dft: SecretKeyDft<Vec<u8>, FFT64> = SecretKeyDft::new(&module); + sk_dft.dft(&module, &sk); - ct_rgsw.encrypt_sk( - &module, - &pt_rgsw, - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rgsw.encrypt_sk( + &module, + &pt_rgsw, + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe.encrypt_sk( - &module, - Some(&pt_want), - &sk_dft, - &mut source_xa, - &mut source_xe, - sigma, - bound, - scratch.borrow(), - ); + ct_rlwe.encrypt_sk( + &module, + Some(&pt_want), + &sk_dft, + &mut source_xa, + &mut source_xe, + sigma, + bound, + scratch.borrow(), + ); - ct_rlwe.dft(&module, &mut ct_rlwe_dft); - ct_rlwe_dft.prod_by_rgsw(&module, &ct_rgsw, scratch.borrow()); - ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow()); + ct_rlwe.dft(&module, &mut ct_rlwe_dft); + ct_rlwe_dft.prod_by_rgsw_inplace(&module, &ct_rgsw, scratch.borrow()); + ct_rlwe_dft.idft(&module, &mut ct_rlwe, scratch.borrow()); - ct_rlwe.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); + ct_rlwe.decrypt(&module, &mut pt_have, &sk_dft, scratch.borrow()); - module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0); + module.vec_znx_rotate_inplace(k as i64, &mut pt_want, 0); - module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); + module.vec_znx_sub_ab_inplace(&mut pt_have, 0, &pt_want, 0); - let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); + let noise_have: f64 = pt_have.data.std(0, log_base2k).log2(); - let var_gct_err_lhs: f64 = sigma * sigma; - let var_gct_err_rhs: f64 = 0f64; + let var_gct_err_lhs: f64 = sigma * sigma; + let var_gct_err_rhs: f64 = 0f64; - let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} - let var_a0_err: f64 = sigma * sigma; - let var_a1_err: f64 = 1f64 / 12f64; + let var_msg: f64 = 1f64 / module.n() as f64; // X^{k} + let var_a0_err: f64 = sigma * sigma; + let var_a1_err: f64 = 1f64 / 12f64; - let noise_want: f64 = noise_rgsw_rlwe_product( - module.n() as f64, - log_base2k, - 0.5, - var_msg, - var_a0_err, - var_a1_err, - var_gct_err_lhs, - var_gct_err_rhs, - log_k_rlwe_in, - log_k_grlwe, - ); + let noise_want: f64 = noise_rgsw_product( + module.n() as f64, + log_base2k, + 0.5, + var_msg, + var_a0_err, + var_a1_err, + var_gct_err_lhs, + var_gct_err_rhs, + log_k_rlwe_in, + log_k_grlwe, + ); - assert!( - (noise_have - noise_want).abs() <= 0.1, - "{} {}", - noise_have, - noise_want - ); + assert!( + (noise_have - noise_want).abs() <= 0.1, + "{} {}", + noise_have, + noise_want + ); - module.free(); - } + module.free(); }