Merge pull request #102 from phantomzone-org/dev_trait fix #95
jump to
@@ -3,13 +3,8 @@
use poulpy_hal::{ DEFAULTALIGN, alloc_aligned, api::ScratchFromBytes, - layouts::{Backend, MatZnx, ScalarZnx, Scratch, ScratchOwned, SvpPPol, VecZnx, VecZnxBig, VecZnxDft, VmpPMat}, - oep::{ - ScratchAvailableImpl, ScratchFromBytesImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, SvpPPolAllocBytesImpl, - TakeMatZnxImpl, TakeScalarZnxImpl, TakeSliceImpl, TakeSvpPPolImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, - TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, TakeVmpPMatImpl, VecZnxBigAllocBytesImpl, - VecZnxDftAllocBytesImpl, VmpPMatAllocBytesImpl, - }, + layouts::{Backend, Scratch, ScratchOwned}, + oep::{ScratchAvailableImpl, ScratchFromBytesImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeSliceImpl}, }; use crate::cpu_fft64_avx::FFT64Avx;@@ -61,178 +56,6 @@ &mut *(std::ptr::slice_from_raw_parts_mut(take_slice.as_mut_ptr() as *mut T, len)),
Scratch::from_bytes(rem_slice), ) } - } -} - -unsafe impl<B: Backend> TakeScalarZnxImpl<B> for FFT64Avx -where - B: ScratchFromBytesImpl<B>, -{ - fn take_scalar_znx_impl(scratch: &mut Scratch<B>, n: usize, cols: usize) -> (ScalarZnx<&mut [u8]>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned(&mut scratch.data, ScalarZnx::alloc_bytes(n, cols)); - ( - ScalarZnx::from_data(take_slice, n, cols), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeSvpPPolImpl<B> for FFT64Avx -where - B: SvpPPolAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_svp_ppol_impl(scratch: &mut Scratch<B>, n: usize, cols: usize) -> (SvpPPol<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned(&mut scratch.data, B::svp_ppol_alloc_bytes_impl(n, cols)); - ( - SvpPPol::from_data(take_slice, n, cols), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxImpl<B> for FFT64Avx -where - B: ScratchFromBytesImpl<B>, -{ - fn take_vec_znx_impl(scratch: &mut Scratch<B>, n: usize, cols: usize, size: usize) -> (VecZnx<&mut [u8]>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned(&mut scratch.data, VecZnx::alloc_bytes(n, cols, size)); - ( - VecZnx::from_data(take_slice, n, cols, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxBigImpl<B> for FFT64Avx -where - B: VecZnxBigAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_vec_znx_big_impl( - scratch: &mut Scratch<B>, - n: usize, - cols: usize, - size: usize, - ) -> (VecZnxBig<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - B::vec_znx_big_alloc_bytes_impl(n, cols, size), - ); - ( - VecZnxBig::from_data(take_slice, n, cols, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxDftImpl<B> for FFT64Avx -where - B: VecZnxDftAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_vec_znx_dft_impl( - scratch: &mut Scratch<B>, - n: usize, - cols: usize, - size: usize, - ) -> (VecZnxDft<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - B::vec_znx_dft_alloc_bytes_impl(n, cols, size), - ); - - ( - VecZnxDft::from_data(take_slice, n, cols, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxDftSliceImpl<B> for FFT64Avx -where - B: VecZnxDftAllocBytesImpl<B> + ScratchFromBytesImpl<B> + TakeVecZnxDftImpl<B>, -{ - fn take_vec_znx_dft_slice_impl( - scratch: &mut Scratch<B>, - len: usize, - n: usize, - cols: usize, - size: usize, - ) -> (Vec<VecZnxDft<&mut [u8], B>>, &mut Scratch<B>) { - let mut scratch: &mut Scratch<B> = scratch; - let mut slice: Vec<VecZnxDft<&mut [u8], B>> = Vec::with_capacity(len); - for _ in 0..len { - let (znx, new_scratch) = B::take_vec_znx_dft_impl(scratch, n, cols, size); - scratch = new_scratch; - slice.push(znx); - } - (slice, scratch) - } -} - -unsafe impl<B: Backend> TakeVecZnxSliceImpl<B> for FFT64Avx -where - B: ScratchFromBytesImpl<B> + TakeVecZnxImpl<B>, -{ - fn take_vec_znx_slice_impl( - scratch: &mut Scratch<B>, - len: usize, - n: usize, - cols: usize, - size: usize, - ) -> (Vec<VecZnx<&mut [u8]>>, &mut Scratch<B>) { - let mut scratch: &mut Scratch<B> = scratch; - let mut slice: Vec<VecZnx<&mut [u8]>> = Vec::with_capacity(len); - for _ in 0..len { - let (znx, new_scratch) = B::take_vec_znx_impl(scratch, n, cols, size); - scratch = new_scratch; - slice.push(znx); - } - (slice, scratch) - } -} - -unsafe impl<B: Backend> TakeVmpPMatImpl<B> for FFT64Avx -where - B: VmpPMatAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_vmp_pmat_impl( - scratch: &mut Scratch<B>, - n: usize, - rows: usize, - cols_in: usize, - cols_out: usize, - size: usize, - ) -> (VmpPMat<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - B::vmp_pmat_alloc_bytes_impl(n, rows, cols_in, cols_out, size), - ); - ( - VmpPMat::from_data(take_slice, n, rows, cols_in, cols_out, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeMatZnxImpl<B> for FFT64Avx -where - B: ScratchFromBytesImpl<B>, -{ - fn take_mat_znx_impl( - scratch: &mut Scratch<B>, - n: usize, - rows: usize, - cols_in: usize, - cols_out: usize, - size: usize, - ) -> (MatZnx<&mut [u8]>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - MatZnx::alloc_bytes(n, rows, cols_in, cols_out, size), - ); - ( - MatZnx::from_data(take_slice, n, rows, cols_in, cols_out, size), - Scratch::from_bytes(rem_slice), - ) } }
@@ -22,7 +22,7 @@ }
} unsafe impl SvpPPolAllocBytesImpl<Self> for FFT64Avx { - fn svp_ppol_alloc_bytes_impl(n: usize, cols: usize) -> usize { + fn svp_ppol_bytes_of_impl(n: usize, cols: usize) -> usize { Self::layout_prep_word_count() * n * cols * size_of::<f64>() } }
@@ -27,7 +27,7 @@ source::Source,
}; unsafe impl VecZnxBigAllocBytesImpl<Self> for FFT64Avx { - fn vec_znx_big_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize { + fn vec_znx_big_bytes_of_impl(n: usize, cols: usize, size: usize) -> usize { Self::layout_big_word_count() * n * cols * size * size_of::<f64>() } }
@@ -24,7 +24,7 @@ }
} unsafe impl VecZnxDftAllocBytesImpl<Self> for FFT64Avx { - fn vec_znx_dft_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize { + fn vec_znx_dft_bytes_of_impl(n: usize, cols: usize, size: usize) -> usize { Self::layout_prep_word_count() * n * cols * size * size_of::<<FFT64Avx as Backend>::ScalarPrep>() } }
@@ -16,7 +16,7 @@
use crate::cpu_fft64_avx::{FFT64Avx, module::FFT64ModuleHandle}; unsafe impl VmpPMatAllocBytesImpl<Self> for FFT64Avx { - fn vmp_pmat_alloc_bytes_impl(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize { + fn vmp_pmat_bytes_of_impl(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize { Self::layout_prep_word_count() * n * rows * cols_in * cols_out * size * size_of::<f64>() } }
@@ -3,13 +3,8 @@
use poulpy_hal::{ DEFAULTALIGN, alloc_aligned, api::ScratchFromBytes, - layouts::{Backend, MatZnx, ScalarZnx, Scratch, ScratchOwned, SvpPPol, VecZnx, VecZnxBig, VecZnxDft, VmpPMat}, - oep::{ - ScratchAvailableImpl, ScratchFromBytesImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, SvpPPolAllocBytesImpl, - TakeMatZnxImpl, TakeScalarZnxImpl, TakeSliceImpl, TakeSvpPPolImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, - TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, TakeVmpPMatImpl, VecZnxBigAllocBytesImpl, - VecZnxDftAllocBytesImpl, VmpPMatAllocBytesImpl, - }, + layouts::{Backend, Scratch, ScratchOwned}, + oep::{ScratchAvailableImpl, ScratchFromBytesImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeSliceImpl}, }; use crate::cpu_fft64_ref::FFT64Ref;@@ -61,178 +56,6 @@ &mut *(std::ptr::slice_from_raw_parts_mut(take_slice.as_mut_ptr() as *mut T, len)),
Scratch::from_bytes(rem_slice), ) } - } -} - -unsafe impl<B: Backend> TakeScalarZnxImpl<B> for FFT64Ref -where - B: ScratchFromBytesImpl<B>, -{ - fn take_scalar_znx_impl(scratch: &mut Scratch<B>, n: usize, cols: usize) -> (ScalarZnx<&mut [u8]>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned(&mut scratch.data, ScalarZnx::alloc_bytes(n, cols)); - ( - ScalarZnx::from_data(take_slice, n, cols), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeSvpPPolImpl<B> for FFT64Ref -where - B: SvpPPolAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_svp_ppol_impl(scratch: &mut Scratch<B>, n: usize, cols: usize) -> (SvpPPol<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned(&mut scratch.data, B::svp_ppol_alloc_bytes_impl(n, cols)); - ( - SvpPPol::from_data(take_slice, n, cols), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxImpl<B> for FFT64Ref -where - B: ScratchFromBytesImpl<B>, -{ - fn take_vec_znx_impl(scratch: &mut Scratch<B>, n: usize, cols: usize, size: usize) -> (VecZnx<&mut [u8]>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned(&mut scratch.data, VecZnx::alloc_bytes(n, cols, size)); - ( - VecZnx::from_data(take_slice, n, cols, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxBigImpl<B> for FFT64Ref -where - B: VecZnxBigAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_vec_znx_big_impl( - scratch: &mut Scratch<B>, - n: usize, - cols: usize, - size: usize, - ) -> (VecZnxBig<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - B::vec_znx_big_alloc_bytes_impl(n, cols, size), - ); - ( - VecZnxBig::from_data(take_slice, n, cols, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxDftImpl<B> for FFT64Ref -where - B: VecZnxDftAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_vec_znx_dft_impl( - scratch: &mut Scratch<B>, - n: usize, - cols: usize, - size: usize, - ) -> (VecZnxDft<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - B::vec_znx_dft_alloc_bytes_impl(n, cols, size), - ); - - ( - VecZnxDft::from_data(take_slice, n, cols, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxDftSliceImpl<B> for FFT64Ref -where - B: VecZnxDftAllocBytesImpl<B> + ScratchFromBytesImpl<B> + TakeVecZnxDftImpl<B>, -{ - fn take_vec_znx_dft_slice_impl( - scratch: &mut Scratch<B>, - len: usize, - n: usize, - cols: usize, - size: usize, - ) -> (Vec<VecZnxDft<&mut [u8], B>>, &mut Scratch<B>) { - let mut scratch: &mut Scratch<B> = scratch; - let mut slice: Vec<VecZnxDft<&mut [u8], B>> = Vec::with_capacity(len); - for _ in 0..len { - let (znx, new_scratch) = B::take_vec_znx_dft_impl(scratch, n, cols, size); - scratch = new_scratch; - slice.push(znx); - } - (slice, scratch) - } -} - -unsafe impl<B: Backend> TakeVecZnxSliceImpl<B> for FFT64Ref -where - B: ScratchFromBytesImpl<B> + TakeVecZnxImpl<B>, -{ - fn take_vec_znx_slice_impl( - scratch: &mut Scratch<B>, - len: usize, - n: usize, - cols: usize, - size: usize, - ) -> (Vec<VecZnx<&mut [u8]>>, &mut Scratch<B>) { - let mut scratch: &mut Scratch<B> = scratch; - let mut slice: Vec<VecZnx<&mut [u8]>> = Vec::with_capacity(len); - for _ in 0..len { - let (znx, new_scratch) = B::take_vec_znx_impl(scratch, n, cols, size); - scratch = new_scratch; - slice.push(znx); - } - (slice, scratch) - } -} - -unsafe impl<B: Backend> TakeVmpPMatImpl<B> for FFT64Ref -where - B: VmpPMatAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_vmp_pmat_impl( - scratch: &mut Scratch<B>, - n: usize, - rows: usize, - cols_in: usize, - cols_out: usize, - size: usize, - ) -> (VmpPMat<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - B::vmp_pmat_alloc_bytes_impl(n, rows, cols_in, cols_out, size), - ); - ( - VmpPMat::from_data(take_slice, n, rows, cols_in, cols_out, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeMatZnxImpl<B> for FFT64Ref -where - B: ScratchFromBytesImpl<B>, -{ - fn take_mat_znx_impl( - scratch: &mut Scratch<B>, - n: usize, - rows: usize, - cols_in: usize, - cols_out: usize, - size: usize, - ) -> (MatZnx<&mut [u8]>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - MatZnx::alloc_bytes(n, rows, cols_in, cols_out, size), - ); - ( - MatZnx::from_data(take_slice, n, rows, cols_in, cols_out, size), - Scratch::from_bytes(rem_slice), - ) } }
@@ -22,7 +22,7 @@ }
} unsafe impl SvpPPolAllocBytesImpl<Self> for FFT64Ref { - fn svp_ppol_alloc_bytes_impl(n: usize, cols: usize) -> usize { + fn svp_ppol_bytes_of_impl(n: usize, cols: usize) -> usize { Self::layout_prep_word_count() * n * cols * size_of::<f64>() } }
@@ -27,7 +27,7 @@ source::Source,
}; unsafe impl VecZnxBigAllocBytesImpl<Self> for FFT64Ref { - fn vec_znx_big_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize { + fn vec_znx_big_bytes_of_impl(n: usize, cols: usize, size: usize) -> usize { Self::layout_big_word_count() * n * cols * size * size_of::<f64>() } }
@@ -24,7 +24,7 @@ }
} unsafe impl VecZnxDftAllocBytesImpl<Self> for FFT64Ref { - fn vec_znx_dft_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize { + fn vec_znx_dft_bytes_of_impl(n: usize, cols: usize, size: usize) -> usize { Self::layout_prep_word_count() * n * cols * size * size_of::<<FFT64Ref as Backend>::ScalarPrep>() } }
@@ -16,7 +16,7 @@
use crate::cpu_fft64_ref::{FFT64Ref, module::FFT64ModuleHandle}; unsafe impl VmpPMatAllocBytesImpl<Self> for FFT64Ref { - fn vmp_pmat_alloc_bytes_impl(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize { + fn vmp_pmat_bytes_of_impl(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize { Self::layout_prep_word_count() * n * rows * cols_in * cols_out * size * size_of::<f64>() } }
@@ -3,13 +3,8 @@
use poulpy_hal::{ DEFAULTALIGN, alloc_aligned, api::ScratchFromBytes, - layouts::{Backend, MatZnx, ScalarZnx, Scratch, ScratchOwned, SvpPPol, VecZnx, VecZnxBig, VecZnxDft, VmpPMat}, - oep::{ - ScratchAvailableImpl, ScratchFromBytesImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, SvpPPolAllocBytesImpl, - TakeMatZnxImpl, TakeScalarZnxImpl, TakeSliceImpl, TakeSvpPPolImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, - TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, TakeVmpPMatImpl, VecZnxBigAllocBytesImpl, - VecZnxDftAllocBytesImpl, VmpPMatAllocBytesImpl, - }, + layouts::{Backend, Scratch, ScratchOwned}, + oep::{ScratchAvailableImpl, ScratchFromBytesImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeSliceImpl}, }; use crate::cpu_spqlios::FFT64Spqlios;@@ -61,178 +56,6 @@ &mut *(std::ptr::slice_from_raw_parts_mut(take_slice.as_mut_ptr() as *mut T, len)),
Scratch::from_bytes(rem_slice), ) } - } -} - -unsafe impl<B: Backend> TakeScalarZnxImpl<B> for FFT64Spqlios -where - B: ScratchFromBytesImpl<B>, -{ - fn take_scalar_znx_impl(scratch: &mut Scratch<B>, n: usize, cols: usize) -> (ScalarZnx<&mut [u8]>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned(&mut scratch.data, ScalarZnx::alloc_bytes(n, cols)); - ( - ScalarZnx::from_data(take_slice, n, cols), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeSvpPPolImpl<B> for FFT64Spqlios -where - B: SvpPPolAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_svp_ppol_impl(scratch: &mut Scratch<B>, n: usize, cols: usize) -> (SvpPPol<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned(&mut scratch.data, B::svp_ppol_alloc_bytes_impl(n, cols)); - ( - SvpPPol::from_data(take_slice, n, cols), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxImpl<B> for FFT64Spqlios -where - B: ScratchFromBytesImpl<B>, -{ - fn take_vec_znx_impl(scratch: &mut Scratch<B>, n: usize, cols: usize, size: usize) -> (VecZnx<&mut [u8]>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned(&mut scratch.data, VecZnx::alloc_bytes(n, cols, size)); - ( - VecZnx::from_data(take_slice, n, cols, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxBigImpl<B> for FFT64Spqlios -where - B: VecZnxBigAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_vec_znx_big_impl( - scratch: &mut Scratch<B>, - n: usize, - cols: usize, - size: usize, - ) -> (VecZnxBig<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - B::vec_znx_big_alloc_bytes_impl(n, cols, size), - ); - ( - VecZnxBig::from_data(take_slice, n, cols, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxDftImpl<B> for FFT64Spqlios -where - B: VecZnxDftAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_vec_znx_dft_impl( - scratch: &mut Scratch<B>, - n: usize, - cols: usize, - size: usize, - ) -> (VecZnxDft<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - B::vec_znx_dft_alloc_bytes_impl(n, cols, size), - ); - - ( - VecZnxDft::from_data(take_slice, n, cols, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeVecZnxDftSliceImpl<B> for FFT64Spqlios -where - B: VecZnxDftAllocBytesImpl<B> + ScratchFromBytesImpl<B> + TakeVecZnxDftImpl<B>, -{ - fn take_vec_znx_dft_slice_impl( - scratch: &mut Scratch<B>, - len: usize, - n: usize, - cols: usize, - size: usize, - ) -> (Vec<VecZnxDft<&mut [u8], B>>, &mut Scratch<B>) { - let mut scratch: &mut Scratch<B> = scratch; - let mut slice: Vec<VecZnxDft<&mut [u8], B>> = Vec::with_capacity(len); - for _ in 0..len { - let (znx, new_scratch) = B::take_vec_znx_dft_impl(scratch, n, cols, size); - scratch = new_scratch; - slice.push(znx); - } - (slice, scratch) - } -} - -unsafe impl<B: Backend> TakeVecZnxSliceImpl<B> for FFT64Spqlios -where - B: ScratchFromBytesImpl<B> + TakeVecZnxImpl<B>, -{ - fn take_vec_znx_slice_impl( - scratch: &mut Scratch<B>, - len: usize, - n: usize, - cols: usize, - size: usize, - ) -> (Vec<VecZnx<&mut [u8]>>, &mut Scratch<B>) { - let mut scratch: &mut Scratch<B> = scratch; - let mut slice: Vec<VecZnx<&mut [u8]>> = Vec::with_capacity(len); - for _ in 0..len { - let (znx, new_scratch) = B::take_vec_znx_impl(scratch, n, cols, size); - scratch = new_scratch; - slice.push(znx); - } - (slice, scratch) - } -} - -unsafe impl<B: Backend> TakeVmpPMatImpl<B> for FFT64Spqlios -where - B: VmpPMatAllocBytesImpl<B> + ScratchFromBytesImpl<B>, -{ - fn take_vmp_pmat_impl( - scratch: &mut Scratch<B>, - n: usize, - rows: usize, - cols_in: usize, - cols_out: usize, - size: usize, - ) -> (VmpPMat<&mut [u8], B>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - B::vmp_pmat_alloc_bytes_impl(n, rows, cols_in, cols_out, size), - ); - ( - VmpPMat::from_data(take_slice, n, rows, cols_in, cols_out, size), - Scratch::from_bytes(rem_slice), - ) - } -} - -unsafe impl<B: Backend> TakeMatZnxImpl<B> for FFT64Spqlios -where - B: ScratchFromBytesImpl<B>, -{ - fn take_mat_znx_impl( - scratch: &mut Scratch<B>, - n: usize, - rows: usize, - cols_in: usize, - cols_out: usize, - size: usize, - ) -> (MatZnx<&mut [u8]>, &mut Scratch<B>) { - let (take_slice, rem_slice) = take_slice_aligned( - &mut scratch.data, - MatZnx::alloc_bytes(n, rows, cols_in, cols_out, size), - ); - ( - MatZnx::from_data(take_slice, n, rows, cols_in, cols_out, size), - Scratch::from_bytes(rem_slice), - ) } }
@@ -27,7 +27,7 @@ }
} unsafe impl SvpPPolAllocBytesImpl<Self> for FFT64Spqlios { - fn svp_ppol_alloc_bytes_impl(n: usize, cols: usize) -> usize { + fn svp_ppol_bytes_of_impl(n: usize, cols: usize) -> usize { FFT64Spqlios::layout_prep_word_count() * n * cols * size_of::<f64>() } }
@@ -22,7 +22,7 @@ source::Source,
}; unsafe impl VecZnxBigAllocBytesImpl<Self> for FFT64Spqlios { - fn vec_znx_big_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize { + fn vec_znx_big_bytes_of_impl(n: usize, cols: usize, size: usize) -> usize { Self::layout_big_word_count() * n * cols * size * size_of::<f64>() } }
@@ -30,7 +30,7 @@ }
} unsafe impl VecZnxDftAllocBytesImpl<Self> for FFT64Spqlios { - fn vec_znx_dft_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize { + fn vec_znx_dft_bytes_of_impl(n: usize, cols: usize, size: usize) -> usize { Self::layout_prep_word_count() * n * cols * size * size_of::<<FFT64Spqlios as Backend>::ScalarPrep>() } }
@@ -16,7 +16,7 @@ ffi::{vec_znx_dft::vec_znx_dft_t, vmp},
}; unsafe impl VmpPMatAllocBytesImpl<Self> for FFT64Spqlios { - fn vmp_pmat_alloc_bytes_impl(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize { + fn vmp_pmat_bytes_of_impl(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize { Self::layout_prep_word_count() * n * rows * cols_in * cols_out * size * size_of::<f64>() } }
@@ -18,7 +18,7 @@ }
} unsafe impl SvpPPolAllocBytesImpl<Self> for NTT120 { - fn svp_ppol_alloc_bytes_impl(n: usize, cols: usize) -> usize { + fn svp_ppol_bytes_of_impl(n: usize, cols: usize) -> usize { NTT120::layout_prep_word_count() * n * cols * size_of::<i64>() } }
@@ -3,7 +3,7 @@
use crate::cpu_spqlios::NTT120; unsafe impl VecZnxBigAllocBytesImpl<NTT120> for NTT120 { - fn vec_znx_big_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize { + fn vec_znx_big_bytes_of_impl(n: usize, cols: usize, size: usize) -> usize { NTT120::layout_big_word_count() * n * cols * size * size_of::<i128>() } }
@@ -6,7 +6,7 @@
use crate::cpu_spqlios::NTT120; unsafe impl VecZnxDftAllocBytesImpl<NTT120> for NTT120 { - fn vec_znx_dft_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize { + fn vec_znx_dft_bytes_of_impl(n: usize, cols: usize, size: usize) -> usize { NTT120::layout_prep_word_count() * n * cols * size * size_of::<i64>() } }
@@ -52,8 +52,8 @@ let mut source_xa: Source = Source::new([2u8; 32]);
// Scratch space let mut scratch: ScratchOwned<FFT64> = ScratchOwned::alloc( - GLWECiphertext::encrypt_sk_scratch_space(&module, n, base2k, ct.k()) - | GLWECiphertext::decrypt_scratch_space(&module, n, base2k, ct.k()), + GLWECiphertext::encrypt_sk_tmp_bytes(&module, n, base2k, ct.k()) + | GLWECiphertext::decrypt_tmp_bytes(&module, n, base2k, ct.k()), ); // Generate secret-key
@@ -1,7 +1,6 @@
use poulpy_core::layouts::{ - Base2K, Degree, Dnum, Dsize, GGSWCiphertext, GGSWCiphertextLayout, GLWECiphertext, GLWECiphertextLayout, GLWESecret, Rank, - TorusPrecision, - prepared::{GGSWCiphertextPrepared, GLWESecretPrepared, PrepareAlloc}, + Base2K, Degree, Dnum, Dsize, GGSW, GGSWLayout, GLWE, GLWELayout, GLWESecret, Rank, TorusPrecision, + prepared::{GGSWPrepared, GLWESecretPrepared}, }; use std::hint::black_box;@@ -39,7 +38,7 @@ let dsize: Dsize = Dsize(1);
let dnum: Dnum = Dnum(1); //(p.k_ct_in.div_ceil(p.base2k); - let ggsw_layout: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_layout: GGSWLayout = GGSWLayout { n, base2k, k: k_ggsw,@@ -48,38 +47,40 @@ dsize: dsize,
rank, }; - let glwe_out_layout: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_out_layout: GLWELayout = GLWELayout { n, base2k, k: k_ct_out, rank, }; - let glwe_in_layout: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_in_layout: GLWELayout = GLWELayout { n, base2k, k: k_ct_in, rank, }; - let mut ct_ggsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_layout); - let mut ct_glwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_in_layout); - let mut ct_glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_layout); + let mut ct_ggsw: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_layout); + let mut ct_glwe_in: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_in_layout); + let mut ct_glwe_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_layout); let pt_rgsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n.into(), 1); let mut scratch: ScratchOwned<FFT64Spqlios> = ScratchOwned::alloc( - GGSWCiphertext::encrypt_sk_scratch_space(&module, &ggsw_layout) - | GLWECiphertext::encrypt_sk_scratch_space(&module, &glwe_in_layout) - | GLWECiphertext::external_product_scratch_space(&module, &glwe_out_layout, &glwe_in_layout, &ggsw_layout), + GGSW::encrypt_sk_tmp_bytes(&module, &ggsw_layout) + | GLWE::encrypt_sk_tmp_bytes(&module, &glwe_in_layout) + | GLWE::external_product_tmp_bytes(&module, &glwe_out_layout, &glwe_in_layout, &ggsw_layout), ); let mut source_xs = Source::new([0u8; 32]); let mut source_xe = Source::new([0u8; 32]); let mut source_xa = Source::new([0u8; 32]); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_in_layout); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_in_layout); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_dft: GLWESecretPrepared<Vec<u8>, FFT64Spqlios> = sk.prepare_alloc(&module, scratch.borrow()); + + let mut sk_dft: GLWESecretPrepared<Vec<u8>, FFT64Spqlios> = GLWESecretPrepared::alloc(&module, rank); + sk_dft.prepare(&module, &sk); ct_ggsw.encrypt_sk( &module,@@ -98,7 +99,8 @@ &mut source_xe,
scratch.borrow(), ); - let ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, FFT64Spqlios> = ct_ggsw.prepare_alloc(&module, scratch.borrow()); + let mut ggsw_prepared: GGSWPrepared<Vec<u8>, FFT64Spqlios> = GGSWPrepared::alloc_from_infos(&module, &ct_ggsw); + ggsw_prepared.prepare(&module, &ct_ggsw, scratch.borrow()); move || { ct_glwe_out.external_product(&module, &ct_glwe_in, &ggsw_prepared, scratch.borrow());@@ -147,7 +149,7 @@ let dsize: Dsize = Dsize(1);
let dnum: Dnum = p.k_ct.div_ceil(p.base2k).into(); - let ggsw_layout: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_layout: GGSWLayout = GGSWLayout { n, base2k, k: k_ggsw,@@ -156,30 +158,32 @@ dsize: dsize,
rank, }; - let glwe_layout: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_layout: GLWELayout = GLWELayout { n, base2k, k: k_glwe, rank, }; - let mut ct_ggsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_layout); - let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_layout); + let mut ct_ggsw: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_layout); + let mut ct_glwe: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_layout); let pt_rgsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n.into(), 1); let mut scratch: ScratchOwned<FFT64Spqlios> = ScratchOwned::alloc( - GGSWCiphertext::encrypt_sk_scratch_space(&module, &ggsw_layout) - | GLWECiphertext::encrypt_sk_scratch_space(&module, &glwe_layout) - | GLWECiphertext::external_product_inplace_scratch_space(&module, &glwe_layout, &ggsw_layout), + GGSW::encrypt_sk_tmp_bytes(&module, &ggsw_layout) + | GLWE::encrypt_sk_tmp_bytes(&module, &glwe_layout) + | GLWE::external_product_tmp_bytes(&module, &glwe_layout, &glwe_layout, &ggsw_layout), ); 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: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_layout); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_layout); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_dft: GLWESecretPrepared<Vec<u8>, FFT64Spqlios> = sk.prepare_alloc(&module, scratch.borrow()); + + let mut sk_dft: GLWESecretPrepared<Vec<u8>, FFT64Spqlios> = GLWESecretPrepared::alloc(&module, rank); + sk_dft.prepare(&module, &sk); ct_ggsw.encrypt_sk( &module,@@ -198,8 +202,8 @@ &mut source_xe,
scratch.borrow(), ); - let ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, FFT64Spqlios> = ct_ggsw.prepare_alloc(&module, scratch.borrow()); - + let mut ggsw_prepared: GGSWPrepared<Vec<u8>, FFT64Spqlios> = GGSWPrepared::alloc_from_infos(&module, &ct_ggsw); + ggsw_prepared.prepare(&module, &ct_ggsw, scratch.borrow()); move || { let scratch_borrow = scratch.borrow(); ct_glwe.external_product_inplace(&module, &ggsw_prepared, scratch_borrow);
@@ -1,7 +1,7 @@
use poulpy_core::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWESwitchingKey, GGLWESwitchingKeyLayout, - GLWECiphertext, GLWECiphertextLayout, GLWESecret, Rank, TorusPrecision, - prepared::{GGLWEAutomorphismKeyPrepared, GGLWESwitchingKeyPrepared, GLWESecretPrepared, PrepareAlloc}, + Base2K, Degree, Dnum, Dsize, GLWE, GLWEAutomorphismKey, GLWEAutomorphismKeyLayout, GLWELayout, GLWESecret, GLWESwitchingKey, + GLWESwitchingKeyLayout, GLWESwitchingKeyPrepared, Rank, TorusPrecision, + prepared::{GLWEAutomorphismKeyPrepared, GLWESecretPrepared}, }; use std::{hint::black_box, time::Duration};@@ -39,7 +39,7 @@ let dsize: Dsize = p.dsize;
let dnum: Dnum = p.k_ct_in.div_ceil(p.base2k.0 * dsize.0).into(); - let gglwe_atk_layout: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let gglwe_atk_layout: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n, base2k, k: k_gglwe,@@ -48,28 +48,28 @@ rank,
dsize, }; - let glwe_in_layout: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_in_layout: GLWELayout = GLWELayout { n, base2k, k: k_glwe_in, rank, }; - let glwe_out_layout: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_out_layout: GLWELayout = GLWELayout { n, base2k, k: k_glwe_out, rank, }; - let mut ksk: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&gglwe_atk_layout); - let mut ct_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_in_layout); - let mut ct_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_layout); + let mut ksk: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&gglwe_atk_layout); + let mut ct_in: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_in_layout); + let mut ct_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_layout); let mut scratch: ScratchOwned<FFT64Spqlios> = ScratchOwned::alloc( - GGLWESwitchingKey::encrypt_sk_scratch_space(&module, &gglwe_atk_layout) - | GLWECiphertext::encrypt_sk_scratch_space(&module, &glwe_in_layout) - | GLWECiphertext::keyswitch_scratch_space( + GLWESwitchingKey::encrypt_sk_tmp_bytes(&module, &gglwe_atk_layout) + | GLWE::encrypt_sk_tmp_bytes(&module, &glwe_in_layout) + | GLWE::keyswitch_tmp_bytes( &module, &glwe_out_layout, &glwe_in_layout,@@ -81,9 +81,11 @@ 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_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_in_layout); + let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_in_layout); sk_in.fill_ternary_prob(0.5, &mut source_xs); - let sk_in_dft: GLWESecretPrepared<Vec<u8>, FFT64Spqlios> = sk_in.prepare_alloc(&module, scratch.borrow()); + + let mut sk_in_dft: GLWESecretPrepared<Vec<u8>, FFT64Spqlios> = GLWESecretPrepared::alloc(&module, rank); + sk_in_dft.prepare(&module, &sk_in); ksk.encrypt_sk( &module,@@ -102,7 +104,9 @@ &mut source_xe,
scratch.borrow(), ); - let ksk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, _> = ksk.prepare_alloc(&module, scratch.borrow()); + let mut ksk_prepared: GLWEAutomorphismKeyPrepared<Vec<u8>, _> = + GLWEAutomorphismKeyPrepared::alloc_from_infos(&module, &ksk); + ksk_prepared.prepare(&module, &ksk, scratch.borrow()); move || { ct_out.automorphism(&module, &ct_in, &ksk_prepared, scratch.borrow());@@ -157,7 +161,7 @@ let dsize: Dsize = Dsize(1);
let dnum: Dnum = p.k_ct.div_ceil(p.base2k).into(); - let gglwe_layout: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let gglwe_layout: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n, base2k, k: k_ksk,@@ -167,31 +171,33 @@ rank_in: rank,
rank_out: rank, }; - let glwe_layout: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_layout: GLWELayout = GLWELayout { n, base2k, k: k_ct, rank, }; - let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_layout); - let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_layout); + let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_layout); + let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_layout); let mut scratch: ScratchOwned<FFT64Spqlios> = ScratchOwned::alloc( - GGLWESwitchingKey::encrypt_sk_scratch_space(&module, &gglwe_layout) - | GLWECiphertext::encrypt_sk_scratch_space(&module, &glwe_layout) - | GLWECiphertext::keyswitch_inplace_scratch_space(&module, &glwe_layout, &gglwe_layout), + GLWESwitchingKey::encrypt_sk_tmp_bytes(&module, &gglwe_layout) + | GLWE::encrypt_sk_tmp_bytes(&module, &glwe_layout) + | GLWE::keyswitch_tmp_bytes(&module, &glwe_layout, &glwe_layout, &gglwe_layout), ); 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_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_layout); + let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_layout); sk_in.fill_ternary_prob(0.5, &mut source_xs); - let sk_in_dft: GLWESecretPrepared<Vec<u8>, FFT64Spqlios> = sk_in.prepare_alloc(&module, scratch.borrow()); + + let mut sk_in_dft: GLWESecretPrepared<Vec<u8>, FFT64Spqlios> = GLWESecretPrepared::alloc(&module, rank); + sk_in_dft.prepare(&module, &sk_in); - let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_layout); + let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_layout); sk_out.fill_ternary_prob(0.5, &mut source_xs); ksk.encrypt_sk(@@ -211,7 +217,8 @@ &mut source_xe,
scratch.borrow(), ); - let ksk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, FFT64Spqlios> = ksk.prepare_alloc(&module, scratch.borrow()); + let mut ksk_prepared: GLWESwitchingKeyPrepared<Vec<u8>, _> = GLWESwitchingKeyPrepared::alloc_from_infos(&module, &ksk); + ksk_prepared.prepare(&module, &ksk, scratch.borrow()); move || { ct.keyswitch_inplace(&module, &ksk_prepared, scratch.borrow());
@@ -1,10 +1,9 @@
use poulpy_backend::cpu_spqlios::FFT64Spqlios; use poulpy_core::{ - GLWEOperations, SIGMA, + GLWESub, SIGMA, layouts::{ - Base2K, Degree, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWEPlaintextLayout, GLWESecret, LWEInfos, Rank, - TorusPrecision, - prepared::{GLWESecretPrepared, PrepareAlloc}, + Base2K, Degree, GLWE, GLWELayout, GLWEPlaintext, GLWEPlaintextLayout, GLWESecret, LWEInfos, Rank, TorusPrecision, + prepared::GLWESecretPrepared, }, }; use poulpy_hal::{@@ -34,7 +33,7 @@
// Instantiate Module (DFT Tables) let module: Module<FFT64Spqlios> = Module::<FFT64Spqlios>::new(n.0 as u64); - let glwe_ct_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_ct_infos: GLWELayout = GLWELayout { n, base2k, k: k_ct,@@ -44,9 +43,9 @@
let glwe_pt_infos: GLWEPlaintextLayout = GLWEPlaintextLayout { n, base2k, k: k_pt }; // Allocates ciphertext & plaintexts - let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_ct_infos); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_pt_infos); - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_pt_infos); + let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_ct_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_pt_infos); + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_pt_infos); // CPRNG let mut source_xs: Source = Source::new([0u8; 32]);@@ -55,16 +54,16 @@ let mut source_xa: Source = Source::new([2u8; 32]);
// Scratch space let mut scratch: ScratchOwned<FFT64Spqlios> = ScratchOwned::alloc( - GLWECiphertext::encrypt_sk_scratch_space(&module, &glwe_ct_infos) - | GLWECiphertext::decrypt_scratch_space(&module, &glwe_ct_infos), + GLWE::encrypt_sk_tmp_bytes(&module, &glwe_ct_infos) | GLWE::decrypt_tmp_bytes(&module, &glwe_ct_infos), ); // Generate secret-key - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_ct_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_ct_infos); sk.fill_ternary_prob(0.5, &mut source_xs); // Backend-prepared secret - let sk_prepared: GLWESecretPrepared<Vec<u8>, FFT64Spqlios> = sk.prepare_alloc(&module, scratch.borrow()); + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, FFT64Spqlios> = GLWESecretPrepared::alloc(&module, rank); + sk_prepared.prepare(&module, &sk); // Uniform plaintext module.vec_znx_fill_uniform(base2k.into(), &mut pt_want.data, 0, &mut source_xa);@@ -83,7 +82,7 @@ // Decryption
ct.decrypt(&module, &mut pt_have, &sk_prepared, scratch.borrow()); // Diff between pt - Dec(Enc(pt)) - pt_want.sub_inplace_ab(&module, &pt_have); + module.glwe_sub_inplace(&mut pt_want, &pt_have); // Ideal vs. actual noise let noise_have: f64 = pt_want.data.std(base2k.into(), 0) * (ct.k().as_u32() as f64).exp2();
@@ -1,198 +1,165 @@
use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxBigAddSmallInplace, - VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, - VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, + api::VecZnxAutomorphism, + layouts::{Backend, DataMut, GaloisElement, Module, Scratch}, +}; + +use crate::{ + ScratchTakeCore, + automorphism::glwe_ct::GLWEAutomorphism, + layouts::{ + GGLWE, GGLWEInfos, GGLWEPreparedToRef, GGLWEToMut, GGLWEToRef, GLWE, GLWEAutomorphismKey, GetGaloisElement, + SetGaloisElement, }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, }; -use crate::layouts::{GGLWEAutomorphismKey, GGLWEInfos, GLWECiphertext, prepared::GGLWEAutomorphismKeyPrepared}; +impl GLWEAutomorphismKey<Vec<u8>> { + pub fn automorphism_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, key_infos: &K) -> usize + where + R: GGLWEInfos, + A: GGLWEInfos, + K: GGLWEInfos, + M: GLWEAutomorphismKeyAutomorphism<BE>, + { + module.glwe_automorphism_key_automorphism_tmp_bytes(res_infos, a_infos, key_infos) + } +} -impl GGLWEAutomorphismKey<Vec<u8>> { - pub fn automorphism_scratch_space<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - key_infos: &KEY, - ) -> usize +impl<DataSelf: DataMut> GLWEAutomorphismKey<DataSelf> { + pub fn automorphism<A, K, M, BE: Backend>(&mut self, module: &M, a: &A, key: &K, scratch: &mut Scratch<BE>) where - OUT: GGLWEInfos, - IN: GGLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + A: GGLWEToRef + GetGaloisElement + GGLWEInfos, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: GLWEAutomorphismKeyAutomorphism<BE>, { - GLWECiphertext::keyswitch_scratch_space( - module, - &out_infos.glwe_layout(), - &in_infos.glwe_layout(), - key_infos, - ) + module.glwe_automorphism_key_automorphism(self, a, key, scratch); } - pub fn automorphism_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize + pub fn automorphism_inplace<K, M, BE: Backend>(&mut self, module: &M, key: &K, scratch: &mut Scratch<BE>) where - OUT: GGLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: GLWEAutomorphismKeyAutomorphism<BE>, { - GGLWEAutomorphismKey::automorphism_scratch_space(module, out_infos, out_infos, key_infos) + module.glwe_automorphism_key_automorphism_inplace(self, key, scratch); } } -impl<DataSelf: DataMut> GGLWEAutomorphismKey<DataSelf> { - pub fn automorphism<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GGLWEAutomorphismKey<DataLhs>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphism - + VecZnxAutomorphismInplace<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnx, +impl<BE: Backend> GLWEAutomorphismKeyAutomorphism<BE> for Module<BE> where + Self: GaloisElement + GLWEAutomorphism<BE> + VecZnxAutomorphism +{ +} + +pub trait GLWEAutomorphismKeyAutomorphism<BE: Backend> +where + Self: GaloisElement + GLWEAutomorphism<BE> + VecZnxAutomorphism, +{ + fn glwe_automorphism_key_automorphism_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize + where + R: GGLWEInfos, + A: GGLWEInfos, + K: GGLWEInfos, + { + self.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos) + } + + fn glwe_automorphism_key_automorphism<R, A, K>(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + R: GGLWEToMut + SetGaloisElement + GGLWEInfos, + A: GGLWEToRef + GetGaloisElement + GGLWEInfos, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - use crate::layouts::LWEInfos; + assert!( + res.dnum().as_u32() <= a.dnum().as_u32(), + "res dnum: {} > a dnum: {}", + res.dnum(), + a.dnum() + ); - assert_eq!( - self.rank_in(), - lhs.rank_in(), - "ksk_out input rank: {} != ksk_in input rank: {}", - self.rank_in(), - lhs.rank_in() - ); - assert_eq!( - self.rank_out(), - rhs.rank_in(), - "ksk_in output rank: {} != ksk_apply input rank: {}", - self.rank_out(), - rhs.rank_in() - ); - assert_eq!( - self.rank_out(), - rhs.rank_out(), - "ksk_out output rank: {} != ksk_apply output rank: {}", - self.rank_out(), - rhs.rank_out() - ); - assert!( - self.k() <= lhs.k(), - "output k={} cannot be greater than input k={}", - self.k(), - lhs.k() - ) - } + assert_eq!( + res.dsize(), + a.dsize(), + "res dnum: {} != a dnum: {}", + res.dsize(), + a.dsize() + ); - let cols_out: usize = (rhs.rank_out() + 1).into(); + let cols_out: usize = (key.rank_out() + 1).into(); + let cols_in: usize = key.rank_in().into(); - let p: i64 = lhs.p(); - let p_inv: i64 = module.galois_element_inv(p); + let p: i64 = a.p(); + let p_inv: i64 = self.galois_element_inv(p); - (0..self.rank_in().into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_j| { - let mut res_ct: GLWECiphertext<&mut [u8]> = self.at_mut(row_j, col_i); - let lhs_ct: GLWECiphertext<&[u8]> = lhs.at(row_j, col_i); + { + let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GGLWE<&[u8]> = &a.to_ref(); - // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a) - (0..cols_out).for_each(|i| { - module.vec_znx_automorphism(lhs.p(), &mut res_ct.data, i, &lhs_ct.data, i); - }); + for row in 0..res.dnum().as_usize() { + for col in 0..cols_in { + let mut res_tmp: GLWE<&mut [u8]> = res.at_mut(row, col); + let a_ct: GLWE<&[u8]> = a.at(row, col); - // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) - res_ct.keyswitch_inplace(module, &rhs.key, scratch); + // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a) + for i in 0..cols_out { + self.vec_znx_automorphism(p, res_tmp.data_mut(), i, &a_ct.data, i); + } - // Applies back the automorphism X^{-k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) to (-pi^{-1}_{k'+k}(s)a + s, a) - (0..cols_out).for_each(|i| { - module.vec_znx_automorphism_inplace(p_inv, &mut res_ct.data, i, scratch); - }); - }); - }); + // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) + self.glwe_keyswitch_inplace(&mut res_tmp, key, scratch); - (self.dnum().min(lhs.dnum()).into()..self.dnum().into()).for_each(|row_i| { - (0..self.rank_in().into()).for_each(|col_j| { - self.at_mut(row_i, col_j).data.zero(); - }); - }); + // Applies back the automorphism X^{-k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) to (-pi^{-1}_{k'+k}(s)a + s, a) + (0..cols_out).for_each(|i| { + self.vec_znx_automorphism_inplace(p_inv, res_tmp.data_mut(), i, scratch); + }); + } + } + } - self.p = (lhs.p * rhs.p) % (module.cyclotomic_order() as i64); + res.set_p((p * key.p()) % self.cyclotomic_order()); } - pub fn automorphism_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphism - + VecZnxAutomorphismInplace<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnx, + fn glwe_automorphism_key_automorphism_inplace<R, K>(&self, res: &mut R, key: &K, scratch: &mut Scratch<BE>) + where + R: GGLWEToMut + SetGaloisElement + GetGaloisElement + GGLWEInfos, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - assert_eq!( - self.rank_out(), - rhs.rank_in(), - "ksk_in output rank: {} != ksk_apply input rank: {}", - self.rank_out(), - rhs.rank_in() - ); - assert_eq!( - self.rank_out(), - rhs.rank_out(), - "ksk_out output rank: {} != ksk_apply output rank: {}", - self.rank_out(), - rhs.rank_out() - ); - } + assert_eq!( + res.rank(), + key.rank(), + "key rank: {} != key rank: {}", + res.rank(), + key.rank() + ); - let cols_out: usize = (rhs.rank_out() + 1).into(); + let cols_out: usize = (key.rank_out() + 1).into(); + let cols_in: usize = key.rank_in().into(); + let p: i64 = res.p(); + let p_inv: i64 = self.galois_element_inv(p); - let p: i64 = self.p(); - let p_inv = module.galois_element_inv(p); - - (0..self.rank_in().into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_j| { - let mut res_ct: GLWECiphertext<&mut [u8]> = self.at_mut(row_j, col_i); + { + let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); + for row in 0..res.dnum().as_usize() { + for col in 0..cols_in { + let mut res_tmp: GLWE<&mut [u8]> = res.at_mut(row, col); - // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a) - (0..cols_out).for_each(|i| { - module.vec_znx_automorphism_inplace(p_inv, &mut res_ct.data, i, scratch); - }); + // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a) + for i in 0..cols_out { + self.vec_znx_automorphism_inplace(p, res_tmp.data_mut(), i, scratch); + } - // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) - res_ct.keyswitch_inplace(module, &rhs.key, scratch); + // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) + self.glwe_keyswitch_inplace(&mut res_tmp, key, scratch); - // Applies back the automorphism X^{-k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) to (-pi^{-1}_{k'+k}(s)a + s, a) - (0..cols_out).for_each(|i| { - module.vec_znx_automorphism_inplace(p_inv, &mut res_ct.data, i, scratch); - }); - }); - }); + // Applies back the automorphism X^{-k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) to (-pi^{-1}_{k'+k}(s)a + s, a) + for i in 0..cols_out { + self.vec_znx_automorphism_inplace(p_inv, res_tmp.data_mut(), i, scratch); + } + } + } + } - self.p = (self.p * rhs.p) % (module.cyclotomic_order() as i64); + res.set_p((res.p() * key.p()) % self.cyclotomic_order()); } }
@@ -1,171 +1,124 @@
use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxAutomorphismInplace, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAddInplace, VecZnxDftAllocBytes, - VecZnxDftApply, VecZnxDftCopy, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeTmpBytes, - VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch}, + api::ScratchAvailable, + layouts::{Backend, DataMut, Module, Scratch}, }; -use crate::layouts::{ - GGLWEInfos, GGSWCiphertext, GGSWInfos, GLWECiphertext, - prepared::{GGLWEAutomorphismKeyPrepared, GGLWETensorKeyPrepared}, +use crate::{ + GGSWExpandRows, ScratchTakeCore, + automorphism::glwe_ct::GLWEAutomorphism, + layouts::{ + GGLWEInfos, GGLWEPreparedToRef, GGSW, GGSWInfos, GGSWToMut, GGSWToRef, GetGaloisElement, + prepared::{GLWETensorKeyPrepared, GLWETensorKeyPreparedToRef}, + }, }; -impl GGSWCiphertext<Vec<u8>> { - pub fn automorphism_scratch_space<B: Backend, OUT, IN, KEY, TSK>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - key_infos: &KEY, - tsk_infos: &TSK, +impl GGSW<Vec<u8>> { + pub fn automorphism_tmp_bytes<R, A, K, T, M, BE: Backend>( + module: &M, + res_infos: &R, + a_infos: &A, + key_infos: &K, + tsk_infos: &T, ) -> usize where - OUT: GGSWInfos, - IN: GGSWInfos, - KEY: GGLWEInfos, - TSK: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigAllocBytes - + VecZnxNormalizeTmpBytes - + VecZnxBigNormalizeTmpBytes, + R: GGSWInfos, + A: GGSWInfos, + K: GGLWEInfos, + T: GGLWEInfos, + M: GGSWAutomorphism<BE>, { - let out_size: usize = out_infos.size(); - let ci_dft: usize = module.vec_znx_dft_alloc_bytes((key_infos.rank_out() + 1).into(), out_size); - let ks_internal: usize = GLWECiphertext::keyswitch_scratch_space( - module, - &out_infos.glwe_layout(), - &in_infos.glwe_layout(), - key_infos, - ); - let expand: usize = GGSWCiphertext::expand_row_scratch_space(module, out_infos, tsk_infos); - ci_dft + (ks_internal | expand) + module.ggsw_automorphism_tmp_bytes(res_infos, a_infos, key_infos, tsk_infos) } +} - pub fn automorphism_inplace_scratch_space<B: Backend, OUT, KEY, TSK>( - module: &Module<B>, - out_infos: &OUT, - key_infos: &KEY, - tsk_infos: &TSK, - ) -> usize +impl<D: DataMut> GGSW<D> { + pub fn automorphism<A, K, T, M, BE: Backend>(&mut self, module: &M, a: &A, key: &K, tsk: &T, scratch: &mut Scratch<BE>) where - OUT: GGSWInfos, - KEY: GGLWEInfos, - TSK: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigAllocBytes - + VecZnxNormalizeTmpBytes - + VecZnxBigNormalizeTmpBytes, + A: GGSWToRef, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + M: GGSWAutomorphism<BE>, + { + module.ggsw_automorphism(self, a, key, tsk, scratch); + } + + pub fn automorphism_inplace<K, T, M, BE: Backend>(&mut self, module: &M, key: &K, tsk: &T, scratch: &mut Scratch<BE>) + where + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + M: GGSWAutomorphism<BE>, { - GGSWCiphertext::automorphism_scratch_space(module, out_infos, out_infos, key_infos, tsk_infos) + module.ggsw_automorphism_inplace(self, key, tsk, scratch); } } -impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> { - pub fn automorphism<DataLhs: DataRef, DataAk: DataRef, DataTsk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GGSWCiphertext<DataLhs>, - auto_key: &GGLWEAutomorphismKeyPrepared<DataAk, B>, - tensor_key: &GGLWETensorKeyPrepared<DataTsk, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxBigAllocBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftCopy<B> - + VecZnxDftAddInplace<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnxBig<B> + TakeVecZnx, +impl<BE: Backend> GGSWAutomorphism<BE> for Module<BE> where Self: GLWEAutomorphism<BE> + GGSWExpandRows<BE> {} + +pub trait GGSWAutomorphism<BE: Backend> +where + Self: GLWEAutomorphism<BE> + GGSWExpandRows<BE>, +{ + fn ggsw_automorphism_tmp_bytes<R, A, K, T>(&self, res_infos: &R, a_infos: &A, key_infos: &K, tsk_infos: &T) -> usize + where + R: GGSWInfos, + A: GGSWInfos, + K: GGLWEInfos, + T: GGLWEInfos, { - #[cfg(debug_assertions)] - { - use crate::layouts::{GLWEInfos, LWEInfos}; + let out_size: usize = res_infos.size(); + let ci_dft: usize = self.bytes_of_vec_znx_dft((key_infos.rank_out() + 1).into(), out_size); + let ks_internal: usize = self.glwe_automorphism_tmp_bytes(res_infos, a_infos, key_infos); + let expand: usize = self.ggsw_expand_rows_tmp_bytes(res_infos, tsk_infos); + ci_dft + (ks_internal.max(expand)) + } - assert_eq!(self.n(), module.n() as u32); - assert_eq!(lhs.n(), module.n() as u32); - assert_eq!(auto_key.n(), module.n() as u32); - assert_eq!(tensor_key.n(), module.n() as u32); + fn ggsw_automorphism<R, A, K, T>(&self, res: &mut R, a: &A, key: &K, tsk: &T, scratch: &mut Scratch<BE>) + where + R: GGSWToMut, + A: GGSWToRef, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + let a: &GGSW<&[u8]> = &a.to_ref(); + let tsk: &GLWETensorKeyPrepared<&[u8], BE> = &tsk.to_ref(); - assert_eq!( - self.rank(), - lhs.rank(), - "ggsw_out rank: {} != ggsw_in rank: {}", - self.rank(), - lhs.rank() - ); - assert_eq!( - self.rank(), - auto_key.rank_out(), - "ggsw_in rank: {} != auto_key rank: {}", - self.rank(), - auto_key.rank_out() - ); - assert_eq!( - self.rank(), - tensor_key.rank_out(), - "ggsw_in rank: {} != tensor_key rank: {}", - self.rank(), - tensor_key.rank_out() - ); - assert!(scratch.available() >= GGSWCiphertext::automorphism_scratch_space(module, self, lhs, auto_key, tensor_key)) - }; + assert_eq!(res.dsize(), a.dsize()); + assert!(res.dnum() <= a.dnum()); + assert!(scratch.available() >= self.ggsw_automorphism_tmp_bytes(res, a, key, tsk)); // Keyswitch the j-th row of the col 0 - (0..lhs.dnum().into()).for_each(|row_i| { + for row in 0..res.dnum().as_usize() { // Key-switch column 0, i.e. // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0pi^-1(s0) + a1pi^-1(s1) + a2pi^-1(s2)) + M[i], a0, a1, a2) - self.at_mut(row_i, 0) - .automorphism(module, &lhs.at(row_i, 0), auto_key, scratch); - }); - self.expand_row(module, tensor_key, scratch); + self.glwe_automorphism(&mut res.at_mut(row, 0), &a.at(row, 0), key, scratch); + } + + self.ggsw_expand_row(res, tsk, scratch); } - pub fn automorphism_inplace<DataKsk: DataRef, DataTsk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - auto_key: &GGLWEAutomorphismKeyPrepared<DataKsk, B>, - tensor_key: &GGLWETensorKeyPrepared<DataTsk, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxBigAllocBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftCopy<B> - + VecZnxDftAddInplace<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnxBig<B> + TakeVecZnx, + fn ggsw_automorphism_inplace<R, K, T>(&self, res: &mut R, key: &K, tsk: &T, scratch: &mut Scratch<BE>) + where + R: GGSWToMut, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + let tsk: &GLWETensorKeyPrepared<&[u8], BE> = &tsk.to_ref(); + // Keyswitch the j-th row of the col 0 - (0..self.dnum().into()).for_each(|row_i| { + for row in 0..res.dnum().as_usize() { // Key-switch column 0, i.e. // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0pi^-1(s0) + a1pi^-1(s1) + a2pi^-1(s2)) + M[i], a0, a1, a2) - self.at_mut(row_i, 0) - .automorphism_inplace(module, auto_key, scratch); - }); - self.expand_row(module, tensor_key, scratch); + self.glwe_automorphism_inplace(&mut res.at_mut(row, 0), key, scratch); + } + + self.ggsw_expand_row(res, tsk, scratch); } } + +impl<DataSelf: DataMut> GGSW<DataSelf> {}
@@ -1,345 +1,322 @@
use poulpy_hal::{ api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxAutomorphismInplace, VecZnxBigAddSmallInplace, - VecZnxBigAutomorphismInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallInplace, - VecZnxBigSubSmallNegateInplace, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalize, - VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, + ScratchTakeBasic, VecZnxAutomorphismInplace, VecZnxBigAutomorphismInplace, VecZnxBigSubSmallInplace, + VecZnxBigSubSmallNegateInplace, }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnxBig}, + layouts::{Backend, DataMut, Module, Scratch, VecZnxBig}, }; -use crate::layouts::{GGLWEInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GGLWEAutomorphismKeyPrepared}; +use crate::{ + GLWEKeyswitch, ScratchTakeCore, keyswitch_internal, + layouts::{GGLWEInfos, GGLWEPreparedToRef, GLWE, GLWEInfos, GLWEToMut, GLWEToRef, GetGaloisElement, LWEInfos}, +}; -impl GLWECiphertext<Vec<u8>> { - pub fn automorphism_scratch_space<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - key_infos: &KEY, - ) -> usize +impl GLWE<Vec<u8>> { + pub fn automorphism_tmp_bytes<M, R, A, K, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, key_infos: &K) -> usize where - OUT: GLWEInfos, - IN: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + R: GLWEInfos, + A: GLWEInfos, + K: GGLWEInfos, + M: GLWEAutomorphism<BE>, { - Self::keyswitch_scratch_space(module, out_infos, in_infos, key_infos) + module.glwe_automorphism_tmp_bytes(res_infos, a_infos, key_infos) } +} - pub fn automorphism_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize +impl<DataSelf: DataMut> GLWE<DataSelf> { + pub fn automorphism<M, A, K, BE: Backend>(&mut self, module: &M, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + M: GLWEAutomorphism<BE>, + A: GLWEToRef, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_automorphism(self, a, key, scratch); + } + + pub fn automorphism_add<M, A, K, BE: Backend>(&mut self, module: &M, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + M: GLWEAutomorphism<BE>, + A: GLWEToRef, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_automorphism_add(self, a, key, scratch); + } + + pub fn automorphism_sub<M, A, K, BE: Backend>(&mut self, module: &M, a: &A, key: &K, scratch: &mut Scratch<BE>) where - OUT: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + M: GLWEAutomorphism<BE>, + A: GLWEToRef, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - Self::keyswitch_inplace_scratch_space(module, out_infos, key_infos) + module.glwe_automorphism_sub(self, a, key, scratch); + } + + pub fn automorphism_sub_negate<M, A, K, BE: Backend>(&mut self, module: &M, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + M: GLWEAutomorphism<BE>, + A: GLWEToRef, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_automorphism_sub_negate(self, a, key, scratch); + } + + pub fn automorphism_inplace<M, K, BE: Backend>(&mut self, module: &M, key: &K, scratch: &mut Scratch<BE>) + where + M: GLWEAutomorphism<BE>, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_automorphism_inplace(self, key, scratch); + } + + pub fn automorphism_add_inplace<M, K, BE: Backend>(&mut self, module: &M, key: &K, scratch: &mut Scratch<BE>) + where + M: GLWEAutomorphism<BE>, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_automorphism_add_inplace(self, key, scratch); + } + + pub fn automorphism_sub_inplace<M, K, BE: Backend>(&mut self, module: &M, key: &K, scratch: &mut Scratch<BE>) + where + M: GLWEAutomorphism<BE>, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_automorphism_sub_inplace(self, key, scratch); + } + + pub fn automorphism_sub_negate_inplace<M, K, BE: Backend>(&mut self, module: &M, key: &K, scratch: &mut Scratch<BE>) + where + M: GLWEAutomorphism<BE>, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_automorphism_sub_negate_inplace(self, key, scratch); } } -impl<DataSelf: DataMut> GLWECiphertext<DataSelf> { - pub fn automorphism<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, +pub trait GLWEAutomorphism<BE: Backend> +where + Self: GLWEKeyswitch<BE> + + VecZnxAutomorphismInplace<BE> + + VecZnxBigAutomorphismInplace<BE> + + VecZnxBigSubSmallInplace<BE> + + VecZnxBigSubSmallNegateInplace<BE>, +{ + fn glwe_automorphism_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize + where + R: GLWEInfos, + A: GLWEInfos, + K: GGLWEInfos, { - self.keyswitch(module, lhs, &rhs.key, scratch); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_automorphism_inplace(rhs.p(), &mut self.data, i, scratch); - }) + self.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos) } - pub fn automorphism_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + fn glwe_automorphism<R, A, K>(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + A: GLWEToRef, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - self.keyswitch_inplace(module, &rhs.key, scratch); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_automorphism_inplace(rhs.p(), &mut self.data, i, scratch); - }) + self.glwe_keyswitch(res, a, key, scratch); + + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_automorphism_inplace(key.p(), res.data_mut(), i, scratch); + } } - pub fn automorphism_add<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + fn glwe_automorphism_inplace<R, K>(&self, res: &mut R, key: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - self.assert_keyswitch(module, lhs, &rhs.key, scratch); + self.glwe_keyswitch_inplace(res, key, scratch); + + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_automorphism_inplace(key.p(), res.data_mut(), i, scratch); } - let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n().into(), (self.rank() + 1).into(), rhs.size()); // TODO: optimise size - let mut res_big: VecZnxBig<_, B> = lhs.keyswitch_internal(module, res_dft, &rhs.key, scratch_1); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_big_automorphism_inplace(rhs.p(), &mut res_big, i, scratch_1); - module.vec_znx_big_add_small_inplace(&mut res_big, i, &lhs.data, i); - module.vec_znx_big_normalize( - self.base2k().into(), - &mut self.data, + } + + fn glwe_automorphism_add<R, A, K>(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + A: GLWEToRef, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); + + let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self, (res.rank() + 1).into(), key.size()); // TODO: optimise size + let mut res_big: VecZnxBig<_, BE> = keyswitch_internal(self, res_dft, a, key, scratch_1); + + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_big_automorphism_inplace(key.p(), &mut res_big, i, scratch_1); + self.vec_znx_big_add_small_inplace(&mut res_big, i, a.data(), i); + self.vec_znx_big_normalize( + res.base2k().into(), + res.data_mut(), i, - rhs.base2k().into(), + key.base2k().into(), &res_big, i, scratch_1, ); - }) + } } - pub fn automorphism_add_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + fn glwe_automorphism_add_inplace<R, K>(&self, res: &mut R, key: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - self.assert_keyswitch_inplace(module, &rhs.key, scratch); - } - let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n().into(), (self.rank() + 1).into(), rhs.size()); // TODO: optimise size - let mut res_big: VecZnxBig<_, B> = self.keyswitch_internal(module, res_dft, &rhs.key, scratch_1); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_big_automorphism_inplace(rhs.p(), &mut res_big, i, scratch_1); - module.vec_znx_big_add_small_inplace(&mut res_big, i, &self.data, i); - module.vec_znx_big_normalize( - self.base2k().into(), - &mut self.data, + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + + let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self, (res.rank() + 1).into(), key.size()); // TODO: optimise size + let mut res_big: VecZnxBig<_, BE> = keyswitch_internal(self, res_dft, res, key, scratch_1); + + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_big_automorphism_inplace(key.p(), &mut res_big, i, scratch_1); + self.vec_znx_big_add_small_inplace(&mut res_big, i, res.data(), i); + self.vec_znx_big_normalize( + res.base2k().into(), + res.data_mut(), i, - rhs.base2k().into(), + key.base2k().into(), &res_big, i, scratch_1, ); - }) + } } - pub fn automorphism_sub_ab<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxBigSubSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + fn glwe_automorphism_sub<R, A, K>(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + A: GLWEToRef, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - self.assert_keyswitch(module, lhs, &rhs.key, scratch); - } - let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n().into(), (self.rank() + 1).into(), rhs.size()); // TODO: optimise size - let mut res_big: VecZnxBig<_, B> = lhs.keyswitch_internal(module, res_dft, &rhs.key, scratch_1); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_big_automorphism_inplace(rhs.p(), &mut res_big, i, scratch_1); - module.vec_znx_big_sub_small_inplace(&mut res_big, i, &lhs.data, i); - module.vec_znx_big_normalize( - self.base2k().into(), - &mut self.data, + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); + + let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self, (res.rank() + 1).into(), key.size()); // TODO: optimise size + let mut res_big: VecZnxBig<_, BE> = keyswitch_internal(self, res_dft, a, key, scratch_1); + + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_big_automorphism_inplace(key.p(), &mut res_big, i, scratch_1); + self.vec_znx_big_sub_small_inplace(&mut res_big, i, a.data(), i); + self.vec_znx_big_normalize( + res.base2k().into(), + res.data_mut(), i, - rhs.base2k().into(), + key.base2k().into(), &res_big, i, scratch_1, ); - }) + } } - pub fn automorphism_sub_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxBigSubSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + fn glwe_automorphism_sub_negate<R, A, K>(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + A: GLWEToRef, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - self.assert_keyswitch_inplace(module, &rhs.key, scratch); - } - let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n().into(), (self.rank() + 1).into(), rhs.size()); // TODO: optimise size - let mut res_big: VecZnxBig<_, B> = self.keyswitch_internal(module, res_dft, &rhs.key, scratch_1); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_big_automorphism_inplace(rhs.p(), &mut res_big, i, scratch_1); - module.vec_znx_big_sub_small_inplace(&mut res_big, i, &self.data, i); - module.vec_znx_big_normalize( - self.base2k().into(), - &mut self.data, + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); + + let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self, (res.rank() + 1).into(), key.size()); // TODO: optimise size + let mut res_big: VecZnxBig<_, BE> = keyswitch_internal(self, res_dft, a, key, scratch_1); + + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_big_automorphism_inplace(key.p(), &mut res_big, i, scratch_1); + self.vec_znx_big_sub_small_negate_inplace(&mut res_big, i, a.data(), i); + self.vec_znx_big_normalize( + res.base2k().into(), + res.data_mut(), i, - rhs.base2k().into(), + key.base2k().into(), &res_big, i, scratch_1, ); - }) + } } - pub fn automorphism_sub_negate<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + fn glwe_automorphism_sub_inplace<R, K>(&self, res: &mut R, key: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - self.assert_keyswitch(module, lhs, &rhs.key, scratch); - } - let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n().into(), (self.rank() + 1).into(), rhs.size()); // TODO: optimise size - let mut res_big: VecZnxBig<_, B> = lhs.keyswitch_internal(module, res_dft, &rhs.key, scratch_1); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_big_automorphism_inplace(rhs.p(), &mut res_big, i, scratch_1); - module.vec_znx_big_sub_small_negate_inplace(&mut res_big, i, &lhs.data, i); - module.vec_znx_big_normalize( - self.base2k().into(), - &mut self.data, + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + + let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self, (res.rank() + 1).into(), key.size()); // TODO: optimise size + let mut res_big: VecZnxBig<_, BE> = keyswitch_internal(self, res_dft, res, key, scratch_1); + + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_big_automorphism_inplace(key.p(), &mut res_big, i, scratch_1); + self.vec_znx_big_sub_small_inplace(&mut res_big, i, res.data(), i); + self.vec_znx_big_normalize( + res.base2k().into(), + res.data_mut(), i, - rhs.base2k().into(), + key.base2k().into(), &res_big, i, scratch_1, ); - }) + } } - pub fn automorphism_sub_negate_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + fn glwe_automorphism_sub_negate_inplace<R, K>(&self, res: &mut R, key: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + K: GetGaloisElement + GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - self.assert_keyswitch_inplace(module, &rhs.key, scratch); - } - let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n().into(), (self.rank() + 1).into(), rhs.size()); // TODO: optimise size - let mut res_big: VecZnxBig<_, B> = self.keyswitch_internal(module, res_dft, &rhs.key, scratch_1); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_big_automorphism_inplace(rhs.p(), &mut res_big, i, scratch_1); - module.vec_znx_big_sub_small_negate_inplace(&mut res_big, i, &self.data, i); - module.vec_znx_big_normalize( - self.base2k().into(), - &mut self.data, + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + + let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self, (res.rank() + 1).into(), key.size()); // TODO: optimise size + let mut res_big: VecZnxBig<_, BE> = keyswitch_internal(self, res_dft, res, key, scratch_1); + + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_big_automorphism_inplace(key.p(), &mut res_big, i, scratch_1); + self.vec_znx_big_sub_small_negate_inplace(&mut res_big, i, res.data(), i); + self.vec_znx_big_normalize( + res.base2k().into(), + res.data_mut(), i, - rhs.base2k().into(), + key.base2k().into(), &res_big, i, scratch_1, ); - }) + } } } + +impl<BE: Backend> GLWEAutomorphism<BE> for Module<BE> where + Self: GLWEKeyswitch<BE> + + VecZnxAutomorphismInplace<BE> + + VecZnxBigAutomorphismInplace<BE> + + VecZnxBigSubSmallInplace<BE> + + VecZnxBigSubSmallNegateInplace<BE> +{ +}
@@ -1,3 +1,7 @@
mod gglwe_atk; mod ggsw_ct; mod glwe_ct; + +pub use gglwe_atk::*; +pub use ggsw_ct::*; +pub use glwe_ct::*;
@@ -0,0 +1,286 @@
+use poulpy_hal::{ + api::{ + ModuleN, ScratchAvailable, ScratchTakeBasic, VecZnxBigBytesOf, VecZnxBigNormalize, VecZnxDftAddInplace, VecZnxDftApply, + VecZnxDftBytesOf, VecZnxDftCopy, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, + VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, + }, + layouts::{Backend, DataMut, Module, Scratch, VmpPMat, ZnxInfos}, +}; + +use crate::{ + GLWECopy, ScratchTakeCore, + layouts::{ + GGLWE, GGLWEInfos, GGLWEToRef, GGSW, GGSWInfos, GGSWToMut, GLWEInfos, LWEInfos, + prepared::{GLWETensorKeyPrepared, GLWETensorKeyPreparedToRef}, + }, +}; + +impl GGLWE<Vec<u8>> { + pub fn from_gglw_tmp_bytes<R, A, M, BE: Backend>(module: &M, res_infos: &R, tsk_infos: &A) -> usize + where + M: GGSWFromGGLWE<BE>, + R: GGSWInfos, + A: GGLWEInfos, + { + module.ggsw_from_gglwe_tmp_bytes(res_infos, tsk_infos) + } +} + +impl<D: DataMut> GGSW<D> { + pub fn from_gglwe<G, M, T, BE: Backend>(&mut self, module: &M, gglwe: &G, tsk: &T, scratch: &mut Scratch<BE>) + where + M: GGSWFromGGLWE<BE>, + G: GGLWEToRef, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.ggsw_from_gglwe(self, gglwe, tsk, scratch); + } +} + +impl<BE: Backend> GGSWFromGGLWE<BE> for Module<BE> +where + Self: GGSWExpandRows<BE> + GLWECopy, +{ + fn ggsw_from_gglwe_tmp_bytes<R, A>(&self, res_infos: &R, tsk_infos: &A) -> usize + where + R: GGSWInfos, + A: GGLWEInfos, + { + self.ggsw_expand_rows_tmp_bytes(res_infos, tsk_infos) + } + + fn ggsw_from_gglwe<R, A, T>(&self, res: &mut R, a: &A, tsk: &T, scratch: &mut Scratch<BE>) + where + R: GGSWToMut, + A: GGLWEToRef, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + let a: &GGLWE<&[u8]> = &a.to_ref(); + let tsk: &GLWETensorKeyPrepared<&[u8], BE> = &tsk.to_ref(); + + assert_eq!(res.rank(), a.rank_out()); + assert_eq!(res.dnum(), a.dnum()); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.n(), self.n() as u32); + assert_eq!(tsk.n(), self.n() as u32); + + for row in 0..res.dnum().into() { + self.glwe_copy(&mut res.at_mut(row, 0), &a.at(row, 0)); + } + + self.ggsw_expand_row(res, tsk, scratch); + } +} + +pub trait GGSWFromGGLWE<BE: Backend> { + fn ggsw_from_gglwe_tmp_bytes<R, A>(&self, res_infos: &R, tsk_infos: &A) -> usize + where + R: GGSWInfos, + A: GGLWEInfos; + + fn ggsw_from_gglwe<R, A, T>(&self, res: &mut R, a: &A, tsk: &T, scratch: &mut Scratch<BE>) + where + R: GGSWToMut, + A: GGLWEToRef, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>; +} + +impl<BE: Backend> GGSWExpandRows<BE> for Module<BE> where + Self: Sized + + ModuleN + + VecZnxDftBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxBigBytesOf + + VecZnxNormalizeTmpBytes + + VecZnxDftBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxBigBytesOf + + VecZnxNormalizeTmpBytes + + VecZnxDftApply<BE> + + VecZnxDftCopy<BE> + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxDftAddInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxIdftApplyTmpA<BE> + + VecZnxNormalize<BE> +{ +} + +pub trait GGSWExpandRows<BE: Backend> +where + Self: Sized + + ModuleN + + VecZnxDftBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxBigBytesOf + + VecZnxNormalizeTmpBytes + + VecZnxDftApply<BE> + + VecZnxDftCopy<BE> + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxDftAddInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxIdftApplyTmpA<BE> + + VecZnxNormalize<BE>, +{ + fn ggsw_expand_rows_tmp_bytes<R, A>(&self, res_infos: &R, tsk_infos: &A) -> usize + where + R: GGSWInfos, + A: GGLWEInfos, + { + let tsk_size: usize = tsk_infos.k().div_ceil(tsk_infos.base2k()) as usize; + let size_in: usize = res_infos + .k() + .div_ceil(tsk_infos.base2k()) + .div_ceil(tsk_infos.dsize().into()) as usize; + + let tmp_dft_i: usize = self.bytes_of_vec_znx_dft((tsk_infos.rank_out() + 1).into(), tsk_size); + let tmp_a: usize = self.bytes_of_vec_znx_dft(1, size_in); + let vmp: usize = self.vmp_apply_dft_to_dft_tmp_bytes( + tsk_size, + size_in, + size_in, + (tsk_infos.rank_in()).into(), // Verify if rank+1 + (tsk_infos.rank_out()).into(), // Verify if rank+1 + tsk_size, + ); + let tmp_idft: usize = self.bytes_of_vec_znx_big(1, tsk_size); + let norm: usize = self.vec_znx_normalize_tmp_bytes(); + + tmp_dft_i + ((tmp_a + vmp) | (tmp_idft + norm)) + } + + fn ggsw_expand_row<R, T>(&self, res: &mut R, tsk: &T, scratch: &mut Scratch<BE>) + where + R: GGSWToMut, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + let tsk: &GLWETensorKeyPrepared<&[u8], BE> = &tsk.to_ref(); + + let basek_in: usize = res.base2k().into(); + let basek_tsk: usize = tsk.base2k().into(); + + assert!(scratch.available() >= self.ggsw_expand_rows_tmp_bytes(res, tsk)); + + let rank: usize = res.rank().into(); + let cols: usize = rank + 1; + + let a_size: usize = (res.size() * basek_in).div_ceil(basek_tsk); + + // Keyswitch the j-th row of the col 0 + for row_i in 0..res.dnum().into() { + let a = &res.at(row_i, 0).data; + + // Pre-compute DFT of (a0, a1, a2) + let (mut ci_dft, scratch_1) = scratch.take_vec_znx_dft(self, cols, a_size); + + if basek_in == basek_tsk { + for i in 0..cols { + self.vec_znx_dft_apply(1, 0, &mut ci_dft, i, a, i); + } + } else { + let (mut a_conv, scratch_2) = scratch_1.take_vec_znx(self.n(), 1, a_size); + for i in 0..cols { + self.vec_znx_normalize(basek_tsk, &mut a_conv, 0, basek_in, a, i, scratch_2); + self.vec_znx_dft_apply(1, 0, &mut ci_dft, i, &a_conv, 0); + } + } + + for col_j in 1..cols { + // Example for rank 3: + // + // Note: M is a vector (m, Bm, B^2m, B^3m, ...), so each column is + // actually composed of that many dnum and we focus on a specific row here + // implicitely given ci_dft. + // + // # Input + // + // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0 , a1 , a2 ) + // col 1: (0, 0, 0, 0) + // col 2: (0, 0, 0, 0) + // col 3: (0, 0, 0, 0) + // + // # Output + // + // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0 , a1 , a2 ) + // col 1: (-(b0s0 + b1s1 + b2s2) , b0 + M[i], b1 , b2 ) + // col 2: (-(c0s0 + c1s1 + c2s2) , c0 , c1 + M[i], c2 ) + // col 3: (-(d0s0 + d1s1 + d2s2) , d0 , d1 , d2 + M[i]) + + let dsize: usize = tsk.dsize().into(); + + let (mut tmp_dft_i, scratch_2) = scratch_1.take_vec_znx_dft(self, cols, tsk.size()); + let (mut tmp_a, scratch_3) = scratch_2.take_vec_znx_dft(self, 1, ci_dft.size().div_ceil(dsize)); + + { + // Performs a key-switch for each combination of s[i]*s[j], i.e. for a0, a1, a2 + // + // # Example for col=1 + // + // a0 * (-(f0s0 + f1s1 + f1s2) + s0^2, f0, f1, f2) = (-(a0f0s0 + a0f1s1 + a0f1s2) + a0s0^2, a0f0, a0f1, a0f2) + // + + // a1 * (-(g0s0 + g1s1 + g1s2) + s0s1, g0, g1, g2) = (-(a1g0s0 + a1g1s1 + a1g1s2) + a1s0s1, a1g0, a1g1, a1g2) + // + + // a2 * (-(h0s0 + h1s1 + h1s2) + s0s2, h0, h1, h2) = (-(a2h0s0 + a2h1s1 + a2h1s2) + a2s0s2, a2h0, a2h1, a2h2) + // = + // (-(x0s0 + x1s1 + x2s2) + s0(a0s0 + a1s1 + a2s2), x0, x1, x2) + for col_i in 1..cols { + let pmat: &VmpPMat<&[u8], BE> = &tsk.at(col_i - 1, col_j - 1).data; // Selects Enc(s[i]s[j]) + + // Extracts a[i] and multipies with Enc(s[i]s[j]) + for di in 0..dsize { + tmp_a.set_size((ci_dft.size() + di) / dsize); + + // Small optimization for dsize > 2 + // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then + // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. + // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last dsize-1 limbs, but this introduce + // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same + // noise is kept with respect to the ideal functionality. + tmp_dft_i.set_size(tsk.size() - ((dsize - di) as isize - 2).max(0) as usize); + + self.vec_znx_dft_copy(dsize, dsize - 1 - di, &mut tmp_a, 0, &ci_dft, col_i); + if di == 0 && col_i == 1 { + self.vmp_apply_dft_to_dft(&mut tmp_dft_i, &tmp_a, pmat, scratch_3); + } else { + self.vmp_apply_dft_to_dft_add(&mut tmp_dft_i, &tmp_a, pmat, di, scratch_3); + } + } + } + } + + // Adds -(sum a[i] * s[i]) + m) on the i-th column of tmp_idft_i + // + // (-(x0s0 + x1s1 + x2s2) + a0s0s0 + a1s0s1 + a2s0s2, x0, x1, x2) + // + + // (0, -(a0s0 + a1s1 + a2s2) + M[i], 0, 0) + // = + // (-(x0s0 + x1s1 + x2s2) + s0(a0s0 + a1s1 + a2s2), x0 -(a0s0 + a1s1 + a2s2) + M[i], x1, x2) + // = + // (-(x0s0 + x1s1 + x2s2), x0 + M[i], x1, x2) + self.vec_znx_dft_add_inplace(&mut tmp_dft_i, col_j, &ci_dft, 0); + let (mut tmp_idft, scratch_3) = scratch_2.take_vec_znx_big(self, 1, tsk.size()); + for i in 0..cols { + self.vec_znx_idft_apply_tmpa(&mut tmp_idft, 0, &mut tmp_dft_i, i); + self.vec_znx_big_normalize( + basek_in, + &mut res.at_mut(row_i, col_j).data, + i, + basek_tsk, + &tmp_idft, + 0, + scratch_3, + ); + } + } + } + } +}
@@ -1,106 +1,124 @@
use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, - VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxView, ZnxViewMut, ZnxZero}, + api::ModuleN, + layouts::{Backend, DataMut, Module, Scratch, ZnxView, ZnxViewMut, ZnxZero}, }; use crate::{ - TakeGLWECt, - layouts::{ - GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, Rank, - prepared::GLWEToLWESwitchingKeyPrepared, - }, + GLWEKeyswitch, ScratchTakeCore, + layouts::{GGLWEInfos, GGLWEPreparedToRef, GLWE, GLWEInfos, GLWELayout, GLWEToRef, LWE, LWEInfos, LWEToMut, Rank}, }; -impl LWECiphertext<Vec<u8>> { - pub fn from_glwe_scratch_space<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - lwe_infos: &OUT, - glwe_infos: &IN, - key_infos: &KEY, - ) -> usize +pub trait LWESampleExtract +where + Self: ModuleN, +{ + fn lwe_sample_extract<R, A>(&self, res: &mut R, a: &A) where - OUT: LWEInfos, - IN: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + R: LWEToMut, + A: GLWEToRef, { - let glwe_layout: GLWECiphertextLayout = GLWECiphertextLayout { - n: module.n().into(), + let res: &mut LWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); + + assert!(res.n() <= a.n()); + assert_eq!(a.n(), self.n() as u32); + assert!(res.base2k() == a.base2k()); + + let min_size: usize = res.size().min(a.size()); + let n: usize = res.n().into(); + + res.data.zero(); + (0..min_size).for_each(|i| { + let data_lwe: &mut [i64] = res.data.at_mut(0, i); + data_lwe[0] = a.data.at(0, i)[0]; + data_lwe[1..].copy_from_slice(&a.data.at(1, i)[..n]); + }); + } +} + +impl<BE: Backend> LWESampleExtract for Module<BE> where Self: ModuleN {} +impl<BE: Backend> LWEFromGLWE<BE> for Module<BE> where Self: GLWEKeyswitch<BE> + LWESampleExtract {} + +pub trait LWEFromGLWE<BE: Backend> +where + Self: GLWEKeyswitch<BE> + LWESampleExtract, +{ + fn lwe_from_glwe_tmp_bytes<R, A, K>(&self, lwe_infos: &R, glwe_infos: &A, key_infos: &K) -> usize + where + R: LWEInfos, + A: GLWEInfos, + K: GGLWEInfos, + { + let res_infos: GLWELayout = GLWELayout { + n: self.n().into(), base2k: lwe_infos.base2k(), k: lwe_infos.k(), rank: Rank(1), }; - GLWECiphertext::alloc_bytes_with( - module.n().into(), + GLWE::bytes_of( + self.n().into(), lwe_infos.base2k(), lwe_infos.k(), 1u32.into(), - ) + GLWECiphertext::keyswitch_scratch_space(module, &glwe_layout, glwe_infos, key_infos) + ) + self.glwe_keyswitch_tmp_bytes(&res_infos, glwe_infos, key_infos) } -} -impl<DLwe: DataMut> LWECiphertext<DLwe> { - pub fn sample_extract<DGlwe: DataRef>(&mut self, a: &GLWECiphertext<DGlwe>) { - #[cfg(debug_assertions)] - { - assert!(self.n() <= a.n()); - assert!(self.base2k() == a.base2k()); - } + fn lwe_from_glwe<R, A, K>(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + R: LWEToMut, + A: GLWEToRef, + K: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut LWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); - let min_size: usize = self.size().min(a.size()); - let n: usize = self.n().into(); + assert_eq!(a.n(), self.n() as u32); + assert_eq!(key.n(), self.n() as u32); + assert!(res.n() <= self.n() as u32); - self.data.zero(); - (0..min_size).for_each(|i| { - let data_lwe: &mut [i64] = self.data.at_mut(0, i); - data_lwe[0] = a.data.at(0, i)[0]; - data_lwe[1..].copy_from_slice(&a.data.at(1, i)[..n]); - }); + let glwe_layout: GLWELayout = GLWELayout { + n: self.n().into(), + base2k: res.base2k(), + k: res.k(), + rank: Rank(1), + }; + + let (mut tmp_glwe, scratch_1) = scratch.take_glwe(&glwe_layout); + self.glwe_keyswitch(&mut tmp_glwe, a, key, scratch_1); + self.lwe_sample_extract(res, &tmp_glwe); } +} - pub fn from_glwe<DGlwe, DKs, B: Backend>( - &mut self, - module: &Module<B>, - a: &GLWECiphertext<DGlwe>, - ks: &GLWEToLWESwitchingKeyPrepared<DKs, B>, - scratch: &mut Scratch<B>, - ) where - DGlwe: DataRef, - DKs: DataRef, - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeGLWECt + TakeVecZnx, +impl LWE<Vec<u8>> { + pub fn from_glwe_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, lwe_infos: &R, glwe_infos: &A, key_infos: &K) -> usize + where + R: LWEInfos, + A: GLWEInfos, + K: GGLWEInfos, + M: LWEFromGLWE<BE>, { - #[cfg(debug_assertions)] - { - assert_eq!(a.n(), module.n() as u32); - assert_eq!(ks.n(), module.n() as u32); - assert!(self.n() <= module.n() as u32); - } + module.lwe_from_glwe_tmp_bytes(lwe_infos, glwe_infos, key_infos) + } +} - let glwe_layout: GLWECiphertextLayout = GLWECiphertextLayout { - n: module.n().into(), - base2k: self.base2k(), - k: self.k(), - rank: Rank(1), - }; +impl<D: DataMut> LWE<D> { + pub fn sample_extract<A, M>(&mut self, module: &M, a: &A) + where + A: GLWEToRef, + M: LWESampleExtract, + { + module.lwe_sample_extract(self, a); + } - let (mut tmp_glwe, scratch_1) = scratch.take_glwe_ct(&glwe_layout); - tmp_glwe.keyswitch(module, a, &ks.0, scratch_1); - self.sample_extract(&tmp_glwe); + pub fn from_glwe<A, K, M, BE: Backend>(&mut self, module: &M, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + A: GLWEToRef, + K: GGLWEPreparedToRef<BE> + GGLWEInfos, + M: LWEFromGLWE<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.lwe_from_glwe(self, a, key, scratch); } }
@@ -1,80 +1,56 @@
use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, - VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnx, ZnxView, ZnxViewMut, ZnxZero}, + api::ScratchTakeBasic, + layouts::{Backend, DataMut, Module, Scratch, VecZnx, ZnxView, ZnxViewMut, ZnxZero}, }; use crate::{ - TakeGLWECt, - layouts::{ - GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, - prepared::LWEToGLWESwitchingKeyPrepared, - }, + GLWEKeyswitch, ScratchTakeCore, + layouts::{GGLWEInfos, GGLWEPreparedToRef, GLWE, GLWEInfos, GLWELayout, GLWEToMut, LWE, LWEInfos, LWEToRef}, }; -impl GLWECiphertext<Vec<u8>> { - pub fn from_lwe_scratch_space<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - glwe_infos: &OUT, - lwe_infos: &IN, - key_infos: &KEY, - ) -> usize +impl<BE: Backend> GLWEFromLWE<BE> for Module<BE> where Self: GLWEKeyswitch<BE> {} + +pub trait GLWEFromLWE<BE: Backend> +where + Self: GLWEKeyswitch<BE>, +{ + fn glwe_from_lwe_tmp_bytes<R, A, K>(&self, glwe_infos: &R, lwe_infos: &A, key_infos: &K) -> usize where - OUT: GLWEInfos, - IN: LWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + R: GLWEInfos, + A: LWEInfos, + K: GGLWEInfos, { - let ct: usize = GLWECiphertext::alloc_bytes_with( - module.n().into(), + let ct: usize = GLWE::bytes_of( + self.n().into(), key_infos.base2k(), lwe_infos.k().max(glwe_infos.k()), 1u32.into(), ); - let ks: usize = GLWECiphertext::keyswitch_inplace_scratch_space(module, glwe_infos, key_infos); + + let ks: usize = self.glwe_keyswitch_tmp_bytes(glwe_infos, glwe_infos, key_infos); if lwe_infos.base2k() == key_infos.base2k() { ct + ks } else { - let a_conv = VecZnx::alloc_bytes(module.n(), 1, lwe_infos.size()) + module.vec_znx_normalize_tmp_bytes(); + let a_conv = VecZnx::bytes_of(self.n(), 1, lwe_infos.size()) + self.vec_znx_normalize_tmp_bytes(); ct + a_conv + ks } } -} -impl<D: DataMut> GLWECiphertext<D> { - pub fn from_lwe<DLwe, DKsk, B: Backend>( - &mut self, - module: &Module<B>, - lwe: &LWECiphertext<DLwe>, - ksk: &LWEToGLWESwitchingKeyPrepared<DKsk, B>, - scratch: &mut Scratch<B>, - ) where - DLwe: DataRef, - DKsk: DataRef, - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeGLWECt + TakeVecZnx, + fn glwe_from_lwe<R, A, K>(&self, res: &mut R, lwe: &A, ksk: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + A: LWEToRef, + K: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - assert_eq!(self.n(), module.n() as u32); - assert_eq!(ksk.n(), module.n() as u32); - assert!(lwe.n() <= module.n() as u32); - } + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let lwe: &LWE<&[u8]> = &lwe.to_ref(); + + assert_eq!(res.n(), self.n() as u32); + assert_eq!(ksk.n(), self.n() as u32); + assert!(lwe.n() <= self.n() as u32); - let (mut glwe, scratch_1) = scratch.take_glwe_ct(&GLWECiphertextLayout { + let (mut glwe, scratch_1) = scratch.take_glwe(&GLWELayout { n: ksk.n(), base2k: ksk.base2k(), k: lwe.k(),@@ -91,14 +67,14 @@ glwe.data.at_mut(0, i)[0] = data_lwe[0];
glwe.data.at_mut(1, i)[..n_lwe].copy_from_slice(&data_lwe[1..]); } } else { - let (mut a_conv, scratch_2) = scratch_1.take_vec_znx(module.n(), 1, lwe.size()); + let (mut a_conv, scratch_2) = scratch_1.take_vec_znx(self.n(), 1, lwe.size()); a_conv.zero(); for j in 0..lwe.size() { let data_lwe: &[i64] = lwe.data.at(0, j); a_conv.at_mut(0, j)[0] = data_lwe[0] } - module.vec_znx_normalize( + self.vec_znx_normalize( ksk.base2k().into(), &mut glwe.data, 0,@@ -114,7 +90,7 @@ let data_lwe: &[i64] = lwe.data.at(0, j);
a_conv.at_mut(0, j)[..n_lwe].copy_from_slice(&data_lwe[1..]); } - module.vec_znx_normalize( + self.vec_znx_normalize( ksk.base2k().into(), &mut glwe.data, 1,@@ -125,6 +101,30 @@ scratch_2,
); } - self.keyswitch(module, &glwe, &ksk.0, scratch_1); + self.glwe_keyswitch(res, &glwe, ksk, scratch_1); + } +} + +impl GLWE<Vec<u8>> { + pub fn from_lwe_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, glwe_infos: &R, lwe_infos: &A, key_infos: &K) -> usize + where + R: GLWEInfos, + A: LWEInfos, + K: GGLWEInfos, + M: GLWEFromLWE<BE>, + { + module.glwe_from_lwe_tmp_bytes(glwe_infos, lwe_infos, key_infos) + } +} + +impl<D: DataMut> GLWE<D> { + pub fn from_lwe<A, K, M, BE: Backend>(&mut self, module: &M, lwe: &A, ksk: &K, scratch: &mut Scratch<BE>) + where + M: GLWEFromLWE<BE>, + A: LWEToRef, + K: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_from_lwe(self, lwe, ksk, scratch); } }
@@ -1,2 +1,7 @@
+mod gglwe_to_ggsw; mod glwe_to_lwe; mod lwe_to_glwe; + +pub use gglwe_to_ggsw::*; +pub use glwe_to_lwe::*; +pub use lwe_to_glwe::*;
@@ -0,0 +1,125 @@
+use poulpy_hal::{ + api::{ + ModuleN, ScratchTakeBasic, SvpApplyDftToDftInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigBytesOf, + VecZnxBigNormalize, VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalizeTmpBytes, + }, + layouts::{Backend, DataRef, DataViewMut, Module, Scratch}, +}; + +use crate::layouts::{ + GLWE, GLWEInfos, GLWEPlaintext, GLWEPlaintextToMut, GLWEToRef, LWEInfos, + prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, +}; + +impl GLWE<Vec<u8>> { + pub fn decrypt_tmp_bytes<A, M, BE: Backend>(module: &M, a_infos: &A) -> usize + where + A: GLWEInfos, + M: GLWEDecrypt<BE>, + { + module.glwe_decrypt_tmp_bytes(a_infos) + } +} + +impl<DataSelf: DataRef> GLWE<DataSelf> { + pub fn decrypt<P, S, M, BE: Backend>(&self, module: &M, pt: &mut P, sk: &S, scratch: &mut Scratch<BE>) + where + P: GLWEPlaintextToMut, + S: GLWESecretPreparedToRef<BE>, + M: GLWEDecrypt<BE>, + Scratch<BE>: ScratchTakeBasic, + { + module.glwe_decrypt(self, pt, sk, scratch); + } +} + +pub trait GLWEDecrypt<BE: Backend> +where + Self: Sized + + ModuleN + + VecZnxDftBytesOf + + VecZnxNormalizeTmpBytes + + VecZnxBigBytesOf + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddInplace<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE>, +{ + fn glwe_decrypt_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GLWEInfos, + { + let size: usize = infos.size(); + (self.vec_znx_normalize_tmp_bytes() | self.bytes_of_vec_znx_dft(1, size)) + self.bytes_of_vec_znx_dft(1, size) + } + + fn glwe_decrypt<R, P, S>(&self, res: &R, pt: &mut P, sk: &S, scratch: &mut Scratch<BE>) + where + R: GLWEToRef, + P: GLWEPlaintextToMut, + S: GLWESecretPreparedToRef<BE>, + Scratch<BE>: ScratchTakeBasic, + { + let res: &GLWE<&[u8]> = &res.to_ref(); + let pt: &mut GLWEPlaintext<&mut [u8]> = &mut pt.to_ref(); + let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref(); + + #[cfg(debug_assertions)] + { + assert_eq!(res.rank(), sk.rank()); + assert_eq!(res.n(), sk.n()); + assert_eq!(pt.n(), sk.n()); + } + + let cols: usize = (res.rank() + 1).into(); + + let (mut c0_big, scratch_1) = scratch.take_vec_znx_big(self, 1, res.size()); // TODO optimize size when pt << ct + c0_big.data_mut().fill(0); + + { + (1..cols).for_each(|i| { + // ci_dft = DFT(a[i]) * DFT(s[i]) + let (mut ci_dft, _) = scratch_1.take_vec_znx_dft(self, 1, res.size()); // TODO optimize size when pt << ct + self.vec_znx_dft_apply(1, 0, &mut ci_dft, 0, &res.data, i); + self.svp_apply_dft_to_dft_inplace(&mut ci_dft, 0, &sk.data, i - 1); + let ci_big = self.vec_znx_idft_apply_consume(ci_dft); + + // c0_big += a[i] * s[i] + self.vec_znx_big_add_inplace(&mut c0_big, 0, &ci_big, 0); + }); + } + + // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e) + self.vec_znx_big_add_small_inplace(&mut c0_big, 0, &res.data, 0); + + // pt = norm(BIG(m + e)) + self.vec_znx_big_normalize( + res.base2k().into(), + &mut pt.data, + 0, + res.base2k().into(), + &c0_big, + 0, + scratch_1, + ); + + pt.base2k = res.base2k(); + pt.k = pt.k().min(res.k()); + } +} + +impl<BE: Backend> GLWEDecrypt<BE> for Module<BE> where + Self: ModuleN + + VecZnxDftBytesOf + + VecZnxNormalizeTmpBytes + + VecZnxBigBytesOf + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddInplace<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> +{ +}
@@ -1,80 +0,0 @@
-use poulpy_hal::{ - api::{ - SvpApplyDftToDftInplace, TakeVecZnxBig, TakeVecZnxDft, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigNormalize, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalizeTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, DataViewMut, Module, Scratch}, -}; - -use crate::layouts::{GLWECiphertext, GLWEInfos, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}; - -impl GLWECiphertext<Vec<u8>> { - pub fn decrypt_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GLWEInfos, - Module<B>: VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes, - { - let size: usize = infos.size(); - (module.vec_znx_normalize_tmp_bytes() | module.vec_znx_dft_alloc_bytes(1, size)) + module.vec_znx_dft_alloc_bytes(1, size) - } -} - -impl<DataSelf: DataRef> GLWECiphertext<DataSelf> { - pub fn decrypt<DataPt: DataMut, DataSk: DataRef, B: Backend>( - &self, - module: &Module<B>, - pt: &mut GLWEPlaintext<DataPt>, - sk: &GLWESecretPrepared<DataSk, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + TakeVecZnxBig<B>, - { - #[cfg(debug_assertions)] - { - assert_eq!(self.rank(), sk.rank()); - assert_eq!(self.n(), sk.n()); - assert_eq!(pt.n(), sk.n()); - } - - let cols: usize = (self.rank() + 1).into(); - - let (mut c0_big, scratch_1) = scratch.take_vec_znx_big(self.n().into(), 1, self.size()); // TODO optimize size when pt << ct - c0_big.data_mut().fill(0); - - { - (1..cols).for_each(|i| { - // ci_dft = DFT(a[i]) * DFT(s[i]) - let (mut ci_dft, _) = scratch_1.take_vec_znx_dft(self.n().into(), 1, self.size()); // TODO optimize size when pt << ct - module.vec_znx_dft_apply(1, 0, &mut ci_dft, 0, &self.data, i); - module.svp_apply_dft_to_dft_inplace(&mut ci_dft, 0, &sk.data, i - 1); - let ci_big = module.vec_znx_idft_apply_consume(ci_dft); - - // c0_big += a[i] * s[i] - module.vec_znx_big_add_inplace(&mut c0_big, 0, &ci_big, 0); - }); - } - - // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e) - module.vec_znx_big_add_small_inplace(&mut c0_big, 0, &self.data, 0); - - // pt = norm(BIG(m + e)) - module.vec_znx_big_normalize( - self.base2k().into(), - &mut pt.data, - 0, - self.base2k().into(), - &c0_big, - 0, - scratch_1, - ); - - pt.base2k = self.base2k(); - pt.k = pt.k().min(self.k()); - } -}
@@ -0,0 +1,65 @@
+use poulpy_hal::{ + api::{ScratchOwnedAlloc, ScratchOwnedBorrow, ZnNormalizeInplace}, + layouts::{Backend, DataMut, DataRef, Module, ScratchOwned, ZnxView, ZnxViewMut}, +}; + +use crate::layouts::{LWE, LWEInfos, LWEPlaintext, LWEPlaintextToMut, LWESecret, LWESecretToRef, LWEToMut}; + +impl<DataSelf: DataRef + DataMut> LWE<DataSelf> { + pub fn decrypt<P, S, M, B: Backend>(&mut self, module: &M, pt: &mut P, sk: &S) + where + P: LWEPlaintextToMut, + S: LWESecretToRef, + M: LWEDecrypt<B>, + { + module.lwe_decrypt(self, pt, sk); + } +} + +pub trait LWEDecrypt<BE: Backend> { + fn lwe_decrypt<R, P, S>(&self, res: &mut R, pt: &mut P, sk: &S) + where + R: LWEToMut, + P: LWEPlaintextToMut, + S: LWESecretToRef; +} + +impl<BE: Backend> LWEDecrypt<BE> for Module<BE> +where + Self: Sized + ZnNormalizeInplace<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, +{ + fn lwe_decrypt<R, P, S>(&self, res: &mut R, pt: &mut P, sk: &S) + where + R: LWEToMut, + P: LWEPlaintextToMut, + S: LWESecretToRef, + { + let res: &mut LWE<&mut [u8]> = &mut res.to_mut(); + let pt: &mut LWEPlaintext<&mut [u8]> = &mut pt.to_mut(); + let sk: LWESecret<&[u8]> = sk.to_ref(); + + #[cfg(debug_assertions)] + { + assert_eq!(res.n(), sk.n()); + } + + (0..pt.size().min(res.size())).for_each(|i| { + pt.data.at_mut(0, i)[0] = res.data.at(0, i)[0] + + res.data.at(0, i)[1..] + .iter() + .zip(sk.data.at(0, 0)) + .map(|(x, y)| x * y) + .sum::<i64>(); + }); + self.zn_normalize_inplace( + 1, + res.base2k().into(), + &mut pt.data, + 0, + ScratchOwned::alloc(size_of::<i64>()).borrow(), + ); + pt.base2k = res.base2k(); + pt.k = crate::layouts::TorusPrecision(res.k().0.min(pt.size() as u32 * res.base2k().0)); + } +}
@@ -1,43 +0,0 @@
-use poulpy_hal::{ - api::{ScratchOwnedAlloc, ScratchOwnedBorrow, ZnNormalizeInplace}, - layouts::{Backend, DataMut, DataRef, Module, ScratchOwned, ZnxView, ZnxViewMut}, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl}, -}; - -use crate::layouts::{LWECiphertext, LWEInfos, LWEPlaintext, LWESecret}; - -impl<DataSelf> LWECiphertext<DataSelf> -where - DataSelf: DataRef, -{ - pub fn decrypt<DataPt, DataSk, B>(&self, module: &Module<B>, pt: &mut LWEPlaintext<DataPt>, sk: &LWESecret<DataSk>) - where - DataPt: DataMut, - DataSk: DataRef, - Module<B>: ZnNormalizeInplace<B>, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, - { - #[cfg(debug_assertions)] - { - assert_eq!(self.n(), sk.n()); - } - - (0..pt.size().min(self.size())).for_each(|i| { - pt.data.at_mut(0, i)[0] = self.data.at(0, i)[0] - + self.data.at(0, i)[1..] - .iter() - .zip(sk.data.at(0, 0)) - .map(|(x, y)| x * y) - .sum::<i64>(); - }); - module.zn_normalize_inplace( - 1, - self.base2k().into(), - &mut pt.data, - 0, - ScratchOwned::alloc(size_of::<i64>()).borrow(), - ); - pt.base2k = self.base2k(); - pt.k = crate::layouts::TorusPrecision(self.k().0.min(pt.size() as u32 * self.base2k().0)); - } -}
@@ -1,2 +1,5 @@
-mod glwe_ct; -mod lwe_ct; +mod glwe; +mod lwe; + +pub use glwe::*; +pub use lwe::*;
@@ -1,5 +1,13 @@
use std::io::{Read, Result, Write}; +pub trait GetDistribution { + fn dist(&self) -> &Distribution; +} + +pub trait GetDistributionMut { + fn dist_mut(&mut self) -> &mut Distribution; +} + #[derive(Clone, Copy, Debug)] pub enum Distribution { TernaryFixed(usize), // Ternary with fixed Hamming weight
@@ -0,0 +1,175 @@
+use poulpy_hal::{ + api::{ModuleN, ScratchAvailable, VecZnxAddScalarInplace, VecZnxDftBytesOf, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes}, + layouts::{Backend, DataMut, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxInfos, ZnxZero}, + source::Source, +}; + +use crate::{ + ScratchTakeCore, + encryption::{GLWEEncryptSk, GLWEEncryptSkInternal, SIGMA}, + layouts::{ + GGLWECompressedSeedMut, GGLWEInfos, GLWEPlaintext, GLWESecretPrepared, LWEInfos, + compressed::{GGLWECompressed, GGLWECompressedToMut}, + prepared::GLWESecretPreparedToRef, + }, +}; + +impl<D: DataMut> GGLWECompressed<D> { + #[allow(clippy::too_many_arguments)] + pub fn encrypt_sk<M, P, S, BE: Backend>( + &mut self, + module: &M, + pt: &P, + sk: &S, + seed: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>, + M: GGLWECompressedEncryptSk<BE>, + { + module.gglwe_compressed_encrypt_sk(self, pt, sk, seed, source_xe, scratch); + } +} + +impl GGLWECompressed<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, BE: Backend, A>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GGLWECompressedEncryptSk<BE>, + { + module.gglwe_compressed_encrypt_sk_tmp_bytes(infos) + } +} + +pub trait GGLWECompressedEncryptSk<BE: Backend> { + fn gglwe_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn gglwe_compressed_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + seed: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWECompressedToMut + GGLWECompressedSeedMut, + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>; +} + +impl<BE: Backend> GGLWECompressedEncryptSk<BE> for Module<BE> +where + Self: ModuleN + + GLWEEncryptSkInternal<BE> + + GLWEEncryptSk<BE> + + VecZnxDftBytesOf + + VecZnxNormalizeInplace<BE> + + VecZnxAddScalarInplace + + VecZnxNormalizeTmpBytes, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn gglwe_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.glwe_encrypt_sk_tmp_bytes(infos) + .max(self.vec_znx_normalize_tmp_bytes()) + + GLWEPlaintext::bytes_of_from_infos(infos) + } + + fn gglwe_compressed_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + seed: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWECompressedToMut + GGLWECompressedSeedMut, + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>, + { + let mut seeds: Vec<[u8; 32]> = vec![[0u8; 32]; res.seed_mut().len()]; + + { + let res: &mut GGLWECompressed<&mut [u8]> = &mut res.to_mut(); + let pt: &ScalarZnx<&[u8]> = &pt.to_ref(); + let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref(); + + assert_eq!( + res.rank_in(), + pt.cols() as u32, + "res.rank_in(): {} != pt.cols(): {}", + res.rank_in(), + pt.cols() + ); + assert_eq!( + res.rank_out(), + sk.rank(), + "res.rank_out(): {} != sk.rank(): {}", + res.rank_out(), + sk.rank() + ); + assert_eq!(res.n(), sk.n()); + assert_eq!(pt.n() as u32, sk.n()); + assert!( + scratch.available() >= GGLWECompressed::encrypt_sk_tmp_bytes(self, res), + "scratch.available: {} < GGLWECiphertext::encrypt_sk_tmp_bytes: {}", + scratch.available(), + GGLWECompressed::encrypt_sk_tmp_bytes(self, res) + ); + assert!( + res.dnum().0 * res.dsize().0 * res.base2k().0 <= res.k().0, + "res.dnum() : {} * res.dsize() : {} * res.base2k() : {} = {} >= res.k() = {}", + res.dnum(), + res.dsize(), + res.base2k(), + res.dnum().0 * res.dsize().0 * res.base2k().0, + res.k() + ); + + let dnum: usize = res.dnum().into(); + let dsize: usize = res.dsize().into(); + let base2k: usize = res.base2k().into(); + let rank_in: usize = res.rank_in().into(); + let cols: usize = (res.rank_out() + 1).into(); + + let mut source_xa = Source::new(seed); + + let (mut tmp_pt, scrach_1) = scratch.take_glwe_plaintext(res); + for col_i in 0..rank_in { + for d_i in 0..dnum { + // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt + tmp_pt.data.zero(); // zeroes for next iteration + self.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + d_i * dsize, pt, col_i); + self.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scrach_1); + + let (seed, mut source_xa_tmp) = source_xa.branch(); + seeds[col_i * dnum + d_i] = seed; + + self.glwe_encrypt_sk_internal( + res.base2k().into(), + res.k().into(), + &mut res.at_mut(d_i, col_i).data, + cols, + true, + Some((&tmp_pt, 0)), + sk, + &mut source_xa_tmp, + source_xe, + SIGMA, + scrach_1, + ); + } + } + } + + res.seed_mut().copy_from_slice(&seeds); + } +}
@@ -1,95 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxBigNormalize, VecZnxDftAllocBytes, - VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch}, - source::Source, -}; - -use crate::{ - TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{ - GGLWEInfos, GLWEInfos, GLWESecret, LWEInfos, - compressed::{GGLWEAutomorphismKeyCompressed, GGLWESwitchingKeyCompressed}, - }, -}; - -impl GGLWEAutomorphismKeyCompressed<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + SvpPPolAllocBytes, - { - assert_eq!(module.n() as u32, infos.n()); - GGLWESwitchingKeyCompressed::encrypt_sk_scratch_space(module, infos) - + GLWESecret::alloc_bytes_with(infos.n(), infos.rank_out()) - } -} - -impl<DataSelf: DataMut> GGLWEAutomorphismKeyCompressed<DataSelf> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - p: i64, - sk: &GLWESecret<DataSk>, - seed_xa: [u8; 32], - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxAutomorphism - + SvpPrepare<B> - + SvpPPolAllocBytes - + VecZnxSwitchRing - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + VecZnxAddScalarInplace, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeGLWESecretPrepared<B>, - { - #[cfg(debug_assertions)] - { - assert_eq!(self.n(), sk.n()); - assert_eq!(self.rank_out(), self.rank_in()); - assert_eq!(sk.rank(), self.rank_out()); - assert!( - scratch.available() >= GGLWEAutomorphismKeyCompressed::encrypt_sk_scratch_space(module, self), - "scratch.available(): {} < AutomorphismKey::encrypt_sk_scratch_space: {}", - scratch.available(), - GGLWEAutomorphismKeyCompressed::encrypt_sk_scratch_space(module, self) - ) - } - - let (mut sk_out, scratch_1) = scratch.take_glwe_secret(sk.n(), sk.rank()); - - { - (0..self.rank_out().into()).for_each(|i| { - module.vec_znx_automorphism( - module.galois_element_inv(p), - &mut sk_out.data.as_vec_znx_mut(), - i, - &sk.data.as_vec_znx(), - i, - ); - }); - } - - self.key - .encrypt_sk(module, sk, &sk_out, seed_xa, source_xe, scratch_1); - - self.p = p; - } -}
@@ -1,127 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, - VecZnxAddScalarInplace, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, - }, - layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch, ZnxZero}, - source::Source, -}; - -use crate::{ - TakeGLWEPt, - encryption::{SIGMA, glwe_encrypt_sk_internal}, - layouts::{GGLWECiphertext, GGLWEInfos, LWEInfos, compressed::GGLWECiphertextCompressed, prepared::GLWESecretPrepared}, -}; - -impl GGLWECiphertextCompressed<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, - { - GGLWECiphertext::encrypt_sk_scratch_space(module, infos) - } -} - -impl<D: DataMut> GGLWECiphertextCompressed<D> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: &ScalarZnx<DataPt>, - sk: &GLWESecretPrepared<DataSk, B>, - seed: [u8; 32], - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - use poulpy_hal::layouts::ZnxInfos; - - assert_eq!( - self.rank_in(), - pt.cols() as u32, - "self.rank_in(): {} != pt.cols(): {}", - self.rank_in(), - pt.cols() - ); - assert_eq!( - self.rank_out(), - sk.rank(), - "self.rank_out(): {} != sk.rank(): {}", - self.rank_out(), - sk.rank() - ); - assert_eq!(self.n(), sk.n()); - assert_eq!(pt.n() as u32, sk.n()); - assert!( - scratch.available() >= GGLWECiphertextCompressed::encrypt_sk_scratch_space(module, self), - "scratch.available: {} < GGLWECiphertext::encrypt_sk_scratch_space: {}", - scratch.available(), - GGLWECiphertextCompressed::encrypt_sk_scratch_space(module, self) - ); - assert!( - self.dnum().0 * self.dsize().0 * self.base2k().0 <= self.k().0, - "self.dnum() : {} * self.dsize() : {} * self.base2k() : {} = {} >= self.k() = {}", - self.dnum(), - self.dsize(), - self.base2k(), - self.dnum().0 * self.dsize().0 * self.base2k().0, - self.k() - ); - } - - let dnum: usize = self.dnum().into(); - let dsize: usize = self.dsize().into(); - let base2k: usize = self.base2k().into(); - let rank_in: usize = self.rank_in().into(); - let cols: usize = (self.rank_out() + 1).into(); - - let mut source_xa = Source::new(seed); - - let (mut tmp_pt, scrach_1) = scratch.take_glwe_pt(self); - (0..rank_in).for_each(|col_i| { - (0..dnum).for_each(|d_i| { - // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt - tmp_pt.data.zero(); // zeroes for next iteration - module.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + d_i * dsize, pt, col_i); - module.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scrach_1); - - let (seed, mut source_xa_tmp) = source_xa.branch(); - self.seed[col_i * dnum + d_i] = seed; - - glwe_encrypt_sk_internal( - module, - self.base2k().into(), - self.k().into(), - &mut self.at_mut(d_i, col_i).data, - cols, - true, - Some((&tmp_pt, 0)), - sk, - &mut source_xa_tmp, - source_xe, - SIGMA, - scrach_1, - ); - }); - }); - } -}
@@ -1,108 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, - VecZnxSubInplace, VecZnxSwitchRing, - }, - layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch}, - source::Source, -}; - -use crate::{ - TakeGLWESecretPrepared, - layouts::{ - Degree, GGLWECiphertext, GGLWEInfos, GLWEInfos, GLWESecret, LWEInfos, compressed::GGLWESwitchingKeyCompressed, - prepared::GLWESecretPrepared, - }, -}; - -impl GGLWESwitchingKeyCompressed<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + SvpPPolAllocBytes, - { - (GGLWECiphertext::encrypt_sk_scratch_space(module, infos) | ScalarZnx::alloc_bytes(module.n(), 1)) - + ScalarZnx::alloc_bytes(module.n(), infos.rank_in().into()) - + GLWESecretPrepared::alloc_bytes_with(module, infos.rank_out()) - } -} - -impl<DataSelf: DataMut> GGLWESwitchingKeyCompressed<DataSelf> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataSkIn: DataRef, DataSkOut: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - sk_in: &GLWESecret<DataSkIn>, - sk_out: &GLWESecret<DataSkOut>, - seed_xa: [u8; 32], - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: SvpPrepare<B> - + SvpPPolAllocBytes - + VecZnxSwitchRing - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + VecZnxAddScalarInplace, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeGLWESecretPrepared<B>, - { - #[cfg(debug_assertions)] - { - use crate::layouts::GGLWESwitchingKey; - - assert!(sk_in.n().0 <= module.n() as u32); - assert!(sk_out.n().0 <= module.n() as u32); - assert!( - scratch.available() >= GGLWESwitchingKey::encrypt_sk_scratch_space(module, self), - "scratch.available()={} < GLWESwitchingKey::encrypt_sk_scratch_space={}", - scratch.available(), - GGLWESwitchingKey::encrypt_sk_scratch_space(module, self) - ) - } - - let n: usize = sk_in.n().max(sk_out.n()).into(); - - let (mut sk_in_tmp, scratch_1) = scratch.take_scalar_znx(n, sk_in.rank().into()); - (0..sk_in.rank().into()).for_each(|i| { - module.vec_znx_switch_ring( - &mut sk_in_tmp.as_vec_znx_mut(), - i, - &sk_in.data.as_vec_znx(), - i, - ); - }); - - let (mut sk_out_tmp, scratch_2) = scratch_1.take_glwe_secret_prepared(Degree(n as u32), sk_out.rank()); - { - let (mut tmp, _) = scratch_2.take_scalar_znx(n, 1); - (0..sk_out.rank().into()).for_each(|i| { - module.vec_znx_switch_ring(&mut tmp.as_vec_znx_mut(), 0, &sk_out.data.as_vec_znx(), i); - module.svp_prepare(&mut sk_out_tmp.data, i, &tmp, 0); - }); - } - - self.key.encrypt_sk( - module, - &sk_in_tmp, - &sk_out_tmp, - seed_xa, - source_xe, - scratch_2, - ); - self.sk_in_n = sk_in.n().into(); - self.sk_out_n = sk_out.n().into(); - } -}
@@ -1,114 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, - TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAllocBytes, - VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, - VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch}, - source::Source, -}; - -use crate::{ - TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{ - GGLWEInfos, GGLWETensorKey, GLWEInfos, GLWESecret, LWEInfos, Rank, compressed::GGLWETensorKeyCompressed, - prepared::Prepare, - }, -}; - -impl GGLWETensorKeyCompressed<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: - SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + VecZnxBigAllocBytes, - { - GGLWETensorKey::encrypt_sk_scratch_space(module, infos) - } -} - -impl<DataSelf: DataMut> GGLWETensorKeyCompressed<DataSelf> { - pub fn encrypt_sk<DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - sk: &GLWESecret<DataSk>, - seed_xa: [u8; 32], - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: SvpApplyDftToDft<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + VecZnxSwitchRing - + VecZnxAddScalarInplace - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B>, - Scratch<B>: ScratchAvailable - + TakeScalarZnx - + TakeVecZnxDft<B> - + TakeGLWESecretPrepared<B> - + ScratchAvailable - + TakeVecZnx - + TakeVecZnxBig<B>, - { - #[cfg(debug_assertions)] - { - assert_eq!(self.rank_out(), sk.rank()); - assert_eq!(self.n(), sk.n()); - } - - let n: usize = sk.n().into(); - let rank: usize = self.rank_out().into(); - - let (mut sk_dft_prep, scratch_1) = scratch.take_glwe_secret_prepared(sk.n(), self.rank_out()); - sk_dft_prep.prepare(module, sk, scratch_1); - - let (mut sk_dft, scratch_2) = scratch_1.take_vec_znx_dft(n, rank, 1); - - for i in 0..rank { - module.vec_znx_dft_apply(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i); - } - - let (mut sk_ij_big, scratch_3) = scratch_2.take_vec_znx_big(n, 1, 1); - let (mut sk_ij, scratch_4) = scratch_3.take_glwe_secret(sk.n(), Rank(1)); - let (mut sk_ij_dft, scratch_5) = scratch_4.take_vec_znx_dft(n, 1, 1); - - let mut source_xa: Source = Source::new(seed_xa); - - for i in 0..rank { - for j in i..rank { - module.svp_apply_dft_to_dft(&mut sk_ij_dft, 0, &sk_dft_prep.data, j, &sk_dft, i); - - module.vec_znx_idft_apply_tmpa(&mut sk_ij_big, 0, &mut sk_ij_dft, 0); - module.vec_znx_big_normalize( - self.base2k().into(), - &mut sk_ij.data.as_vec_znx_mut(), - 0, - self.base2k().into(), - &sk_ij_big, - 0, - scratch_5, - ); - - let (seed_xa_tmp, _) = source_xa.branch(); - - self.at_mut(i, j) - .encrypt_sk(module, &sk_ij, sk, seed_xa_tmp, source_xe, scratch_5); - } - } - } -}
@@ -0,0 +1,147 @@
+use poulpy_hal::{ + api::{ModuleN, VecZnxAddScalarInplace, VecZnxNormalizeInplace}, + layouts::{Backend, DataMut, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxInfos, ZnxZero}, + source::Source, +}; + +use crate::{ + ScratchTakeCore, + encryption::{GGSWEncryptSk, GLWEEncryptSkInternal, SIGMA}, + layouts::{ + GGSWCompressedSeedMut, GGSWInfos, LWEInfos, + compressed::{GGSWCompressed, GGSWCompressedToMut}, + prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, + }, +}; + +impl GGSWCompressed<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGSWInfos, + M: GGSWCompressedEncryptSk<BE>, + { + module.ggsw_compressed_encrypt_sk_tmp_bytes(infos) + } +} + +impl<DataSelf: DataMut> GGSWCompressed<DataSelf> { + #[allow(clippy::too_many_arguments)] + pub fn encrypt_sk<P, S, M, BE: Backend>( + &mut self, + module: &M, + pt: &P, + sk: &S, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>, + M: GGSWCompressedEncryptSk<BE>, + { + module.ggsw_compressed_encrypt_sk(self, pt, sk, seed_xa, source_xe, scratch); + } +} + +pub trait GGSWCompressedEncryptSk<BE: Backend> { + fn ggsw_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGSWInfos; + + fn ggsw_compressed_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGSWCompressedToMut + GGSWCompressedSeedMut + GGSWInfos, + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>; +} + +impl<BE: Backend> GGSWCompressedEncryptSk<BE> for Module<BE> +where + Self: ModuleN + GLWEEncryptSkInternal<BE> + GGSWEncryptSk<BE> + VecZnxAddScalarInplace + VecZnxNormalizeInplace<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn ggsw_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGSWInfos, + { + self.ggsw_encrypt_sk_tmp_bytes(infos) + } + + fn ggsw_compressed_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGSWCompressedToMut + GGSWCompressedSeedMut + GGSWInfos, + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>, + { + let base2k: usize = res.base2k().into(); + let rank: usize = res.rank().into(); + let cols: usize = rank + 1; + let dsize: usize = res.dsize().into(); + + let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref(); + let pt: &ScalarZnx<&[u8]> = &pt.to_ref(); + + assert_eq!(res.rank(), sk.rank()); + assert_eq!(pt.n(), self.n()); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(sk.n(), self.n() as u32); + + let mut seeds: Vec<[u8; 32]> = vec![[0u8; 32]; res.dnum().as_usize() * (res.rank().as_usize() + 1)]; + + { + let res: &mut GGSWCompressed<&mut [u8]> = &mut res.to_mut(); + + println!("res.seed: {:?}", res.seed); + + let (mut tmp_pt, scratch_1) = scratch.take_glwe_plaintext(res); + + let mut source = Source::new(seed_xa); + + for row_i in 0..res.dnum().into() { + tmp_pt.data.zero(); + + // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt + self.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + row_i * dsize, pt, 0); + self.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scratch_1); + + for col_j in 0..rank + 1 { + // rlwe encrypt of vec_znx_pt into vec_znx_ct + + let (seed, mut source_xa_tmp) = source.branch(); + + seeds[row_i * cols + col_j] = seed; + + self.glwe_encrypt_sk_internal( + res.base2k().into(), + res.k().into(), + &mut res.at_mut(row_i, col_j).data, + cols, + true, + Some((&tmp_pt, col_j)), + sk, + &mut source_xa_tmp, + source_xe, + SIGMA, + scratch_1, + ); + } + } + } + + res.seed_mut().copy_from_slice(&seeds); + } +}
@@ -1,107 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, - VecZnxAddScalarInplace, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, - }, - layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch, ZnxZero}, - source::Source, -}; - -use crate::{ - TakeGLWEPt, - encryption::{SIGMA, glwe_encrypt_sk_internal}, - layouts::{ - GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, compressed::GGSWCiphertextCompressed, prepared::GLWESecretPrepared, - }, -}; - -impl GGSWCiphertextCompressed<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGSWInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes, - { - GGSWCiphertext::encrypt_sk_scratch_space(module, infos) - } -} - -impl<DataSelf: DataMut> GGSWCiphertextCompressed<DataSelf> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: &ScalarZnx<DataPt>, - sk: &GLWESecretPrepared<DataSk, B>, - seed_xa: [u8; 32], - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - use poulpy_hal::layouts::ZnxInfos; - - assert_eq!(self.rank(), sk.rank()); - assert_eq!(self.n(), sk.n()); - assert_eq!(pt.n() as u32, sk.n()); - } - - let base2k: usize = self.base2k().into(); - let rank: usize = self.rank().into(); - let cols: usize = rank + 1; - let dsize: usize = self.dsize().into(); - - let (mut tmp_pt, scratch_1) = scratch.take_glwe_pt(&self.glwe_layout()); - - let mut source = Source::new(seed_xa); - - self.seed = vec![[0u8; 32]; self.dnum().0 as usize * cols]; - - (0..self.dnum().into()).for_each(|row_i| { - tmp_pt.data.zero(); - - // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt - module.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + row_i * dsize, pt, 0); - module.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scratch_1); - - (0..rank + 1).for_each(|col_j| { - // rlwe encrypt of vec_znx_pt into vec_znx_ct - - let (seed, mut source_xa_tmp) = source.branch(); - - self.seed[row_i * cols + col_j] = seed; - - glwe_encrypt_sk_internal( - module, - self.base2k().into(), - self.k().into(), - &mut self.at_mut(row_i, col_j).data, - cols, - true, - Some((&tmp_pt, col_j)), - sk, - &mut source_xa_tmp, - source_xe, - SIGMA, - scratch_1, - ); - }); - }); - } -}
@@ -0,0 +1,126 @@
+use poulpy_hal::{ + api::{ModuleN, ScratchAvailable, VecZnxAutomorphism}, + layouts::{Backend, DataMut, GaloisElement, Module, Scratch}, + source::Source, +}; + +use crate::{ + GGLWECompressedEncryptSk, ScratchTakeCore, + layouts::{ + GGLWECompressedSeedMut, GGLWECompressedToMut, GGLWEInfos, GLWEInfos, GLWESecret, GLWESecretPrepared, + GLWESecretPreparedFactory, GLWESecretToRef, LWEInfos, SetGaloisElement, compressed::GLWEAutomorphismKeyCompressed, + }, +}; + +impl GLWEAutomorphismKeyCompressed<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, BE: Backend, A>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWEAutomorphismKeyCompressedEncryptSk<BE>, + { + module.glwe_automorphism_key_compressed_encrypt_sk_tmp_bytes(infos) + } +} + +impl<DataSelf: DataMut> GLWEAutomorphismKeyCompressed<DataSelf> { + #[allow(clippy::too_many_arguments)] + pub fn encrypt_sk<M, S, BE: Backend>( + &mut self, + module: &M, + p: i64, + sk: &S, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S: GLWESecretToRef + GLWEInfos, + M: GLWEAutomorphismKeyCompressedEncryptSk<BE>, + { + module.glwe_automorphism_key_compressed_encrypt_sk(self, p, sk, seed_xa, source_xe, scratch); + } +} + +pub trait GLWEAutomorphismKeyCompressedEncryptSk<BE: Backend> { + fn glwe_automorphism_key_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn glwe_automorphism_key_compressed_encrypt_sk<R, S>( + &self, + res: &mut R, + p: i64, + sk: &S, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWECompressedToMut + GGLWECompressedSeedMut + SetGaloisElement + GGLWEInfos, + S: GLWESecretToRef + GLWEInfos; +} + +impl<BE: Backend> GLWEAutomorphismKeyCompressedEncryptSk<BE> for Module<BE> +where + Self: ModuleN + GaloisElement + VecZnxAutomorphism + GGLWECompressedEncryptSk<BE> + GLWESecretPreparedFactory<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn glwe_automorphism_key_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!(self.n() as u32, infos.n()); + self.gglwe_compressed_encrypt_sk_tmp_bytes(infos) + .max(GLWESecret::bytes_of_from_infos(infos)) + + GLWESecretPrepared::bytes_of_from_infos(self, infos) + } + + fn glwe_automorphism_key_compressed_encrypt_sk<R, S>( + &self, + res: &mut R, + p: i64, + sk: &S, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWECompressedToMut + GGLWECompressedSeedMut + SetGaloisElement + GGLWEInfos, + S: GLWESecretToRef + GLWEInfos, + { + let sk: &GLWESecret<&[u8]> = &sk.to_ref(); + assert_eq!(res.n(), sk.n()); + assert_eq!(res.rank_out(), res.rank_in()); + assert_eq!(sk.rank(), res.rank_out()); + assert!( + scratch.available() >= GLWEAutomorphismKeyCompressed::encrypt_sk_tmp_bytes(self, res), + "scratch.available(): {} < AutomorphismKey::encrypt_sk_tmp_bytes: {}", + scratch.available(), + GLWEAutomorphismKeyCompressed::encrypt_sk_tmp_bytes(self, res) + ); + + let (mut sk_out_prepared, scratch_1) = scratch.take_glwe_secret_prepared(self, sk.rank()); + { + let (mut sk_out, _) = scratch_1.take_glwe_secret(self.n().into(), sk.rank()); + sk_out.dist = sk.dist; + for i in 0..sk.rank().into() { + self.vec_znx_automorphism( + self.galois_element_inv(p), + &mut sk_out.data.as_vec_znx_mut(), + i, + &sk.data.as_vec_znx(), + i, + ); + } + sk_out_prepared.prepare(self, &sk_out); + } + + self.gglwe_compressed_encrypt_sk( + res, + &sk.data, + &sk_out_prepared, + seed_xa, + source_xe, + scratch_1, + ); + + res.set_p(p); + } +}
@@ -1,100 +1,109 @@
use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, - VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, - VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch}, + layouts::{Backend, DataMut, Module, Scratch}, source::Source, }; use crate::{ - encryption::{SIGMA, glwe_ct::glwe_encrypt_sk_internal}, + encryption::{GLWEEncryptSk, GLWEEncryptSkInternal, SIGMA}, layouts::{ - GLWECiphertext, GLWEInfos, GLWEPlaintext, LWEInfos, compressed::GLWECiphertextCompressed, prepared::GLWESecretPrepared, + GLWECompressedSeedMut, GLWEInfos, GLWEPlaintextToRef, LWEInfos, + compressed::{GLWECompressed, GLWECompressedToMut}, + prepared::GLWESecretPreparedToRef, }, }; -impl GLWECiphertextCompressed<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize +impl GLWECompressed<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize where A: GLWEInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes, + M: GLWECompressedEncryptSk<BE>, { - GLWECiphertext::encrypt_sk_scratch_space(module, infos) + module.glwe_compressed_encrypt_sk_tmp_bytes(infos) } } -impl<D: DataMut> GLWECiphertextCompressed<D> { +impl<D: DataMut> GLWECompressed<D> { #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>( + pub fn encrypt_sk<M, P, S, BE: Backend>( &mut self, - module: &Module<B>, - pt: &GLWEPlaintext<DataPt>, - sk: &GLWESecretPrepared<DataSk, B>, + module: &M, + pt: &P, + sk: &S, seed_xa: [u8; 32], source_xe: &mut Source, - scratch: &mut Scratch<B>, + scratch: &mut Scratch<BE>, ) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + M: GLWECompressedEncryptSk<BE>, + P: GLWEPlaintextToRef, + S: GLWESecretPreparedToRef<BE>, + { + module.glwe_compressed_encrypt_sk(self, pt, sk, seed_xa, source_xe, scratch); + } +} + +pub trait GLWECompressedEncryptSk<BE: Backend> { + fn glwe_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GLWEInfos; + + fn glwe_compressed_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWECompressedToMut + GLWECompressedSeedMut, + P: GLWEPlaintextToRef, + S: GLWESecretPreparedToRef<BE>; +} + +impl<BE: Backend> GLWECompressedEncryptSk<BE> for Module<BE> +where + Self: GLWEEncryptSkInternal<BE> + GLWEEncryptSk<BE>, +{ + fn glwe_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GLWEInfos, { - self.encrypt_sk_internal(module, Some((pt, 0)), sk, seed_xa, source_xe, scratch); + self.glwe_encrypt_sk_tmp_bytes(infos) } - #[allow(clippy::too_many_arguments)] - pub(crate) fn encrypt_sk_internal<DataPt: DataRef, DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: Option<(&GLWEPlaintext<DataPt>, usize)>, - sk: &GLWESecretPrepared<DataSk, B>, + fn glwe_compressed_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, seed_xa: [u8; 32], source_xe: &mut Source, - scratch: &mut Scratch<B>, + scratch: &mut Scratch<BE>, ) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + R: GLWECompressedToMut + GLWECompressedSeedMut, + P: GLWEPlaintextToRef, + S: GLWESecretPreparedToRef<BE>, { - let mut source_xa = Source::new(seed_xa); - let cols: usize = (self.rank() + 1).into(); - glwe_encrypt_sk_internal( - module, - self.base2k().into(), - self.k().into(), - &mut self.data, - cols, - true, - pt, - sk, - &mut source_xa, - source_xe, - SIGMA, - scratch, - ); - self.seed = seed_xa; + { + let res: &mut GLWECompressed<&mut [u8]> = &mut res.to_mut(); + let mut source_xa: Source = Source::new(seed_xa); + let cols: usize = (res.rank() + 1).into(); + + self.glwe_encrypt_sk_internal( + res.base2k().into(), + res.k().into(), + &mut res.data, + cols, + true, + Some((pt, 0)), + sk, + &mut source_xa, + source_xe, + SIGMA, + scratch, + ); + } + + res.seed_mut().copy_from_slice(&seed_xa); } }
@@ -0,0 +1,131 @@
+use poulpy_hal::{ + api::{ModuleN, ScratchAvailable, ScratchTakeBasic, SvpPrepare, VecZnxSwitchRing}, + layouts::{Backend, DataMut, Module, ScalarZnx, Scratch}, + source::Source, +}; + +use crate::{ + GGLWECompressedEncryptSk, ScratchTakeCore, + layouts::{ + GGLWECompressedSeedMut, GGLWECompressedToMut, GGLWEInfos, GLWEInfos, GLWESecret, GLWESecretToRef, + GLWESwitchingKeyDegreesMut, LWEInfos, + compressed::GLWESwitchingKeyCompressed, + prepared::{GLWESecretPrepared, GLWESecretPreparedFactory}, + }, +}; + +impl GLWESwitchingKeyCompressed<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWESwitchingKeyCompressedEncryptSk<BE>, + { + module.glwe_switching_key_compressed_encrypt_sk_tmp_bytes(infos) + } +} + +impl<D: DataMut> GLWESwitchingKeyCompressed<D> { + #[allow(clippy::too_many_arguments)] + pub fn encrypt_sk<M, S1, S2, BE: Backend>( + &mut self, + module: &M, + sk_in: &S1, + sk_out: &S2, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S1: GLWESecretToRef, + S2: GLWESecretToRef, + M: GLWESwitchingKeyCompressedEncryptSk<BE>, + { + module.glwe_switching_key_compressed_encrypt_sk(self, sk_in, sk_out, seed_xa, source_xe, scratch); + } +} + +pub trait GLWESwitchingKeyCompressedEncryptSk<BE: Backend> { + fn glwe_switching_key_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn glwe_switching_key_compressed_encrypt_sk<R, S1, S2>( + &self, + res: &mut R, + sk_in: &S1, + sk_out: &S2, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWECompressedToMut + GGLWECompressedSeedMut + GLWESwitchingKeyDegreesMut + GGLWEInfos, + S1: GLWESecretToRef, + S2: GLWESecretToRef; +} + +impl<BE: Backend> GLWESwitchingKeyCompressedEncryptSk<BE> for Module<BE> +where + Self: ModuleN + GGLWECompressedEncryptSk<BE> + GLWESecretPreparedFactory<BE> + VecZnxSwitchRing, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn glwe_switching_key_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.gglwe_compressed_encrypt_sk_tmp_bytes(infos) + .max(ScalarZnx::bytes_of(self.n(), 1)) + + ScalarZnx::bytes_of(self.n(), infos.rank_in().into()) + + GLWESecretPrepared::bytes_of(self, infos.rank_out()) + } + + fn glwe_switching_key_compressed_encrypt_sk<R, S1, S2>( + &self, + res: &mut R, + sk_in: &S1, + sk_out: &S2, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWECompressedToMut + GGLWECompressedSeedMut + GLWESwitchingKeyDegreesMut + GGLWEInfos, + S1: GLWESecretToRef, + S2: GLWESecretToRef, + { + let sk_in: &GLWESecret<&[u8]> = &sk_in.to_ref(); + let sk_out: &GLWESecret<&[u8]> = &sk_out.to_ref(); + + assert!(sk_in.n().0 <= self.n() as u32); + assert!(sk_out.n().0 <= self.n() as u32); + assert!( + scratch.available() >= self.gglwe_compressed_encrypt_sk_tmp_bytes(res), + "scratch.available()={} < GLWESwitchingKey::encrypt_sk_tmp_bytes={}", + scratch.available(), + self.gglwe_compressed_encrypt_sk_tmp_bytes(res) + ); + + let (mut sk_in_tmp, scratch_1) = scratch.take_scalar_znx(self.n(), sk_in.rank().into()); + for i in 0..sk_in.rank().into() { + self.vec_znx_switch_ring( + &mut sk_in_tmp.as_vec_znx_mut(), + i, + &sk_in.data.as_vec_znx(), + i, + ); + } + + let (mut sk_out_tmp, scratch_2) = scratch_1.take_glwe_secret_prepared(self, sk_out.rank()); + { + let (mut tmp, _) = scratch_2.take_scalar_znx(self.n(), 1); + for i in 0..sk_out.rank().into() { + self.vec_znx_switch_ring(&mut tmp.as_vec_znx_mut(), 0, &sk_out.data.as_vec_znx(), i); + self.svp_prepare(&mut sk_out_tmp.data, i, &tmp, 0); + } + } + + sk_out_tmp.dist = sk_out.dist; + + self.gglwe_compressed_encrypt_sk(res, &sk_in_tmp, &sk_out_tmp, seed_xa, source_xe, scratch_2); + + *res.input_degree() = sk_in.n(); + *res.output_degree() = sk_out.n(); + } +}
@@ -0,0 +1,156 @@
+use poulpy_hal::{ + api::{ + ModuleN, ScratchTakeBasic, SvpApplyDftToDft, SvpPPolBytesOf, SvpPrepare, VecZnxBigBytesOf, VecZnxBigNormalize, + VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyTmpA, + }, + layouts::{Backend, DataMut, Module, Scratch}, + source::Source, +}; + +use crate::{ + GGLWECompressedEncryptSk, GLWETensorKeyEncryptSk, GetDistribution, ScratchTakeCore, + layouts::{ + GGLWEInfos, GLWEInfos, GLWESecret, GLWESecretPrepared, GLWESecretPreparedFactory, GLWESecretToRef, + GLWETensorKeyCompressedAtMut, LWEInfos, Rank, compressed::GLWETensorKeyCompressed, + }, +}; + +impl GLWETensorKeyCompressed<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWETensorKeyCompressedEncryptSk<BE>, + { + module.glwe_tensor_key_compressed_encrypt_sk_tmp_bytes(infos) + } +} + +impl<DataSelf: DataMut> GLWETensorKeyCompressed<DataSelf> { + pub fn encrypt_sk<S, M, BE: Backend>( + &mut self, + module: &M, + sk: &S, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S: GLWESecretToRef + GetDistribution, + M: GLWETensorKeyCompressedEncryptSk<BE>, + { + module.glwe_tensor_key_compressed_encrypt_sk(self, sk, seed_xa, source_xe, scratch); + } +} + +pub trait GLWETensorKeyCompressedEncryptSk<BE: Backend> { + fn glwe_tensor_key_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn glwe_tensor_key_compressed_encrypt_sk<R, S, D>( + &self, + res: &mut R, + sk: &S, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + D: DataMut, + R: GLWETensorKeyCompressedAtMut<D> + GGLWEInfos, + S: GLWESecretToRef + GetDistribution; +} + +impl<BE: Backend> GLWETensorKeyCompressedEncryptSk<BE> for Module<BE> +where + Self: ModuleN + + GGLWECompressedEncryptSk<BE> + + GLWETensorKeyEncryptSk<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDft<BE> + + VecZnxIdftApplyTmpA<BE> + + VecZnxBigNormalize<BE> + + SvpPrepare<BE> + + SvpPPolBytesOf + + VecZnxDftBytesOf + + VecZnxBigBytesOf + + GLWESecretPreparedFactory<BE>, + Scratch<BE>: ScratchTakeBasic + ScratchTakeCore<BE>, +{ + fn glwe_tensor_key_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + GLWESecretPrepared::bytes_of(self, infos.rank_out()) + + self.bytes_of_vec_znx_dft(infos.rank_out().into(), 1) + + self.bytes_of_vec_znx_big(1, 1) + + self.bytes_of_vec_znx_dft(1, 1) + + GLWESecret::bytes_of(self.n().into(), Rank(1)) + + self.gglwe_compressed_encrypt_sk_tmp_bytes(infos) + } + + fn glwe_tensor_key_compressed_encrypt_sk<R, S, D>( + &self, + res: &mut R, + sk: &S, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + D: DataMut, + R: GGLWEInfos + GLWETensorKeyCompressedAtMut<D>, + S: GLWESecretToRef + GetDistribution, + { + let (mut sk_dft_prep, scratch_1) = scratch.take_glwe_secret_prepared(self, res.rank()); + sk_dft_prep.prepare(self, sk); + + let sk: &GLWESecret<&[u8]> = &sk.to_ref(); + + #[cfg(debug_assertions)] + { + assert_eq!(res.rank_out(), sk.rank()); + assert_eq!(res.n(), sk.n()); + } + + // let n: usize = sk.n().into(); + let rank: usize = res.rank_out().into(); + + let (mut sk_dft, scratch_2) = scratch_1.take_vec_znx_dft(self, rank, 1); + + for i in 0..rank { + self.vec_znx_dft_apply(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i); + } + + let (mut sk_ij_big, scratch_3) = scratch_2.take_vec_znx_big(self, 1, 1); + let (mut sk_ij, scratch_4) = scratch_3.take_glwe_secret(self.n().into(), Rank(1)); + let (mut sk_ij_dft, scratch_5) = scratch_4.take_vec_znx_dft(self, 1, 1); + + let mut source_xa: Source = Source::new(seed_xa); + + for i in 0..rank { + for j in i..rank { + self.svp_apply_dft_to_dft(&mut sk_ij_dft, 0, &sk_dft_prep.data, j, &sk_dft, i); + + self.vec_znx_idft_apply_tmpa(&mut sk_ij_big, 0, &mut sk_ij_dft, 0); + self.vec_znx_big_normalize( + res.base2k().into(), + &mut sk_ij.data.as_vec_znx_mut(), + 0, + res.base2k().into(), + &sk_ij_big, + 0, + scratch_5, + ); + + let (seed_xa_tmp, _) = source_xa.branch(); + + self.gglwe_compressed_encrypt_sk( + res.at_mut(i, j), + &sk_ij.data, + &sk_dft_prep, + seed_xa_tmp, + source_xe, + scratch_5, + ); + } + } + } +}
@@ -1,6 +1,13 @@
-mod gglwe_atk; -mod gglwe_ct; -mod gglwe_ksk; -mod gglwe_tsk; -mod ggsw_ct; +mod gglwe; +mod ggsw; +mod glwe_automorphism_key; mod glwe_ct; +mod glwe_switching_key; +mod glwe_tensor_key; + +pub use gglwe::*; +pub use ggsw::*; +pub use glwe_automorphism_key::*; +pub use glwe_ct::*; +pub use glwe_switching_key::*; +pub use glwe_tensor_key::*;
@@ -0,0 +1,174 @@
+use poulpy_hal::{ + api::{ModuleN, ScratchAvailable, VecZnxAddScalarInplace, VecZnxDftBytesOf, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes}, + layouts::{Backend, DataMut, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxInfos, ZnxZero}, + source::Source, +}; + +use crate::{ + GLWEEncryptSk, ScratchTakeCore, + layouts::{ + GGLWE, GGLWEInfos, GGLWEToMut, GLWEPlaintext, LWEInfos, + prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, + }, +}; + +impl GGLWE<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GGLWEEncryptSk<BE>, + { + module.gglwe_encrypt_sk_tmp_bytes(infos) + } + + pub fn encrypt_pk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GGLWEEncryptSk<BE>, + { + module.gglwe_encrypt_sk_tmp_bytes(infos) + } +} + +impl<D: DataMut> GGLWE<D> { + #[allow(clippy::too_many_arguments)] + pub fn encrypt_sk<P, S, M, BE: Backend>( + &mut self, + module: &M, + pt: &P, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>, + M: GGLWEEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.gglwe_encrypt_sk(self, pt, sk, source_xa, source_xe, scratch); + } +} + +pub trait GGLWEEncryptSk<BE: Backend> { + fn gglwe_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn gglwe_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWEToMut, + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>; +} + +impl<BE: Backend> GGLWEEncryptSk<BE> for Module<BE> +where + Self: ModuleN + + GLWEEncryptSk<BE> + + VecZnxNormalizeTmpBytes + + VecZnxDftBytesOf + + VecZnxAddScalarInplace + + VecZnxNormalizeInplace<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn gglwe_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.glwe_encrypt_sk_tmp_bytes(infos) + GLWEPlaintext::bytes_of_from_infos(infos).max(self.vec_znx_normalize_tmp_bytes()) + } + + fn gglwe_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWEToMut, + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>, + { + let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); + let pt: &ScalarZnx<&[u8]> = &pt.to_ref(); + let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref(); + + assert_eq!( + res.rank_in(), + pt.cols() as u32, + "res.rank_in(): {} != pt.cols(): {}", + res.rank_in(), + pt.cols() + ); + assert_eq!( + res.rank_out(), + sk.rank(), + "res.rank_out(): {} != sk.rank(): {}", + res.rank_out(), + sk.rank() + ); + assert_eq!(res.n(), sk.n()); + assert_eq!(pt.n() as u32, sk.n()); + assert!( + scratch.available() >= self.gglwe_encrypt_sk_tmp_bytes(res), + "scratch.available: {} < GGLWE::encrypt_sk_tmp_bytes(self, res.rank()={}, res.size()={}): {}", + scratch.available(), + res.rank_out(), + res.size(), + self.gglwe_encrypt_sk_tmp_bytes(res) + ); + assert!( + res.dnum().0 * res.dsize().0 * res.base2k().0 <= res.k().0, + "res.dnum() : {} * res.dsize() : {} * res.base2k() : {} = {} >= res.k() = {}", + res.dnum(), + res.dsize(), + res.base2k(), + res.dnum().0 * res.dsize().0 * res.base2k().0, + res.k() + ); + + let dnum: usize = res.dnum().into(); + let dsize: usize = res.dsize().into(); + let base2k: usize = res.base2k().into(); + let rank_in: usize = res.rank_in().into(); + + let (mut tmp_pt, scrach_1) = scratch.take_glwe_plaintext(res); + // For each input column (i.e. rank) produces a GGLWE of rank_out+1 columns + // + // Example for ksk rank 2 to rank 3: + // + // (-(a0*s0 + a1*s1 + a2*s2) + s0', a0, a1, a2) + // (-(b0*s0 + b1*s1 + b2*s2) + s0', b0, b1, b2) + // + // Example ksk rank 2 to rank 1 + // + // (-(a*s) + s0, a) + // (-(b*s) + s1, b) + for col_i in 0..rank_in { + for row_i in 0..dnum { + // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt + tmp_pt.data.zero(); // zeroes for next iteration + self.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + row_i * dsize, pt, col_i); + self.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scrach_1); + self.glwe_encrypt_sk( + &mut res.at_mut(row_i, col_i), + &tmp_pt, + sk, + source_xa, + source_xe, + scrach_1, + ); + } + } + } +}
@@ -1,109 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxBigNormalize, VecZnxDftAllocBytes, - VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch}, - source::Source, -}; - -use crate::{ - TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{GGLWEAutomorphismKey, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, GLWESecret, LWEInfos}, -}; - -impl GGLWEAutomorphismKey<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWEAutomorphismKey" - ); - GGLWESwitchingKey::encrypt_sk_scratch_space(module, infos) + GLWESecret::alloc_bytes(&infos.glwe_layout()) - } - - pub fn encrypt_pk_scratch_space<B: Backend, A>(module: &Module<B>, _infos: &A) -> usize - where - A: GGLWEInfos, - { - assert_eq!( - _infos.rank_in(), - _infos.rank_out(), - "rank_in != rank_out is not supported for GGLWEAutomorphismKey" - ); - GGLWESwitchingKey::encrypt_pk_scratch_space(module, _infos) - } -} - -impl<DataSelf: DataMut> GGLWEAutomorphismKey<DataSelf> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - p: i64, - sk: &GLWESecret<DataSk>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + VecZnxSwitchRing - + SvpPPolAllocBytes - + VecZnxAutomorphism, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeGLWESecretPrepared<B>, - { - #[cfg(debug_assertions)] - { - use crate::layouts::{GLWEInfos, LWEInfos}; - - assert_eq!(self.n(), sk.n()); - assert_eq!(self.rank_out(), self.rank_in()); - assert_eq!(sk.rank(), self.rank_out()); - assert!( - scratch.available() >= GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, self), - "scratch.available(): {} < AutomorphismKey::encrypt_sk_scratch_space: {:?}", - scratch.available(), - GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, self) - ) - } - - let (mut sk_out, scratch_1) = scratch.take_glwe_secret(sk.n(), sk.rank()); - - { - (0..self.rank_out().into()).for_each(|i| { - module.vec_znx_automorphism( - module.galois_element_inv(p), - &mut sk_out.data.as_vec_znx_mut(), - i, - &sk.data.as_vec_znx(), - i, - ); - }); - } - - self.key - .encrypt_sk(module, sk, &sk_out, source_xa, source_xe, scratch_1); - - self.p = p; - } -}
@@ -1,130 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, - VecZnxAddScalarInplace, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, - }, - layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch, ZnxZero}, - source::Source, -}; - -use crate::{ - TakeGLWEPt, - layouts::{GGLWECiphertext, GGLWEInfos, GLWECiphertext, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}, -}; - -impl GGLWECiphertext<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, - { - GLWECiphertext::encrypt_sk_scratch_space(module, &infos.glwe_layout()) - + (GLWEPlaintext::alloc_bytes(&infos.glwe_layout()) | module.vec_znx_normalize_tmp_bytes()) - } - - pub fn encrypt_pk_scratch_space<B: Backend, A>(_module: &Module<B>, _infos: &A) -> usize - where - A: GGLWEInfos, - { - unimplemented!() - } -} - -impl<DataSelf: DataMut> GGLWECiphertext<DataSelf> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: &ScalarZnx<DataPt>, - sk: &GLWESecretPrepared<DataSk, B>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - use poulpy_hal::layouts::ZnxInfos; - - assert_eq!( - self.rank_in(), - pt.cols() as u32, - "self.rank_in(): {} != pt.cols(): {}", - self.rank_in(), - pt.cols() - ); - assert_eq!( - self.rank_out(), - sk.rank(), - "self.rank_out(): {} != sk.rank(): {}", - self.rank_out(), - sk.rank() - ); - assert_eq!(self.n(), sk.n()); - assert_eq!(pt.n() as u32, sk.n()); - assert!( - scratch.available() >= GGLWECiphertext::encrypt_sk_scratch_space(module, self), - "scratch.available: {} < GGLWECiphertext::encrypt_sk_scratch_space(module, self.rank()={}, self.size()={}): {}", - scratch.available(), - self.rank_out(), - self.size(), - GGLWECiphertext::encrypt_sk_scratch_space(module, self) - ); - assert!( - self.dnum().0 * self.dsize().0 * self.base2k().0 <= self.k().0, - "self.dnum() : {} * self.dsize() : {} * self.base2k() : {} = {} >= self.k() = {}", - self.dnum(), - self.dsize(), - self.base2k(), - self.dnum().0 * self.dsize().0 * self.base2k().0, - self.k() - ); - } - - let dnum: usize = self.dnum().into(); - let dsize: usize = self.dsize().into(); - let base2k: usize = self.base2k().into(); - let rank_in: usize = self.rank_in().into(); - - let (mut tmp_pt, scrach_1) = scratch.take_glwe_pt(self); - // For each input column (i.e. rank) produces a GGLWE ciphertext of rank_out+1 columns - // - // Example for ksk rank 2 to rank 3: - // - // (-(a0*s0 + a1*s1 + a2*s2) + s0', a0, a1, a2) - // (-(b0*s0 + b1*s1 + b2*s2) + s0', b0, b1, b2) - // - // Example ksk rank 2 to rank 1 - // - // (-(a*s) + s0, a) - // (-(b*s) + s1, b) - (0..rank_in).for_each(|col_i| { - (0..dnum).for_each(|row_i| { - // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt - tmp_pt.data.zero(); // zeroes for next iteration - module.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + row_i * dsize, pt, col_i); - module.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scrach_1); - - // rlwe encrypt of vec_znx_pt into vec_znx_ct - self.at_mut(row_i, col_i) - .encrypt_sk(module, &tmp_pt, sk, source_xa, source_xe, scrach_1); - }); - }); - } -}
@@ -1,112 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, - VecZnxSubInplace, VecZnxSwitchRing, - }, - layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch}, - source::Source, -}; - -use crate::{ - TakeGLWESecretPrepared, - layouts::{ - Degree, GGLWECiphertext, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, GLWESecret, LWEInfos, prepared::GLWESecretPrepared, - }, -}; - -impl GGLWESwitchingKey<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, - { - (GGLWECiphertext::encrypt_sk_scratch_space(module, infos) | ScalarZnx::alloc_bytes(module.n(), 1)) - + ScalarZnx::alloc_bytes(module.n(), infos.rank_in().into()) - + GLWESecretPrepared::alloc_bytes(module, &infos.glwe_layout()) - } - - pub fn encrypt_pk_scratch_space<B: Backend, A>(module: &Module<B>, _infos: &A) -> usize - where - A: GGLWEInfos, - { - GGLWECiphertext::encrypt_pk_scratch_space(module, _infos) - } -} - -impl<DataSelf: DataMut> GGLWESwitchingKey<DataSelf> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataSkIn: DataRef, DataSkOut: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - sk_in: &GLWESecret<DataSkIn>, - sk_out: &GLWESecret<DataSkOut>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + VecZnxSwitchRing - + SvpPPolAllocBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeGLWESecretPrepared<B>, - { - #[cfg(debug_assertions)] - { - assert!(sk_in.n().0 <= module.n() as u32); - assert!(sk_out.n().0 <= module.n() as u32); - assert!( - scratch.available() >= GGLWESwitchingKey::encrypt_sk_scratch_space(module, self), - "scratch.available()={} < GLWESwitchingKey::encrypt_sk_scratch_space={}", - scratch.available(), - GGLWESwitchingKey::encrypt_sk_scratch_space(module, self) - ) - } - - let n: usize = sk_in.n().max(sk_out.n()).into(); - - let (mut sk_in_tmp, scratch_1) = scratch.take_scalar_znx(n, sk_in.rank().into()); - (0..sk_in.rank().into()).for_each(|i| { - module.vec_znx_switch_ring( - &mut sk_in_tmp.as_vec_znx_mut(), - i, - &sk_in.data.as_vec_znx(), - i, - ); - }); - - let (mut sk_out_tmp, scratch_2) = scratch_1.take_glwe_secret_prepared(Degree(n as u32), sk_out.rank()); - { - let (mut tmp, _) = scratch_2.take_scalar_znx(n, 1); - (0..sk_out.rank().into()).for_each(|i| { - module.vec_znx_switch_ring(&mut tmp.as_vec_znx_mut(), 0, &sk_out.data.as_vec_znx(), i); - module.svp_prepare(&mut sk_out_tmp.data, i, &tmp, 0); - }); - } - - self.key.encrypt_sk( - module, - &sk_in_tmp, - &sk_out_tmp, - source_xa, - source_xe, - scratch_2, - ); - self.sk_in_n = sk_in.n().into(); - self.sk_out_n = sk_out.n().into(); - } -}
@@ -1,109 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeVecZnx, - TakeVecZnxBig, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAllocBytes, - VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, - VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch}, - source::Source, -}; - -use crate::{ - TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{ - Degree, GGLWEInfos, GGLWESwitchingKey, GGLWETensorKey, GLWEInfos, GLWESecret, LWEInfos, Rank, - prepared::{GLWESecretPrepared, Prepare}, - }, -}; - -impl GGLWETensorKey<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: - SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes + VecZnxBigAllocBytes, - { - GLWESecretPrepared::alloc_bytes_with(module, infos.rank_out()) - + module.vec_znx_dft_alloc_bytes(infos.rank_out().into(), 1) - + module.vec_znx_big_alloc_bytes(1, 1) - + module.vec_znx_dft_alloc_bytes(1, 1) - + GLWESecret::alloc_bytes_with(Degree(module.n() as u32), Rank(1)) - + GGLWESwitchingKey::encrypt_sk_scratch_space(module, infos) - } -} - -impl<DataSelf: DataMut> GGLWETensorKey<DataSelf> { - pub fn encrypt_sk<DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - sk: &GLWESecret<DataSk>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: SvpApplyDftToDft<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + VecZnxSwitchRing - + SvpPPolAllocBytes, - Scratch<B>: - TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeGLWESecretPrepared<B> + TakeVecZnxBig<B>, - { - #[cfg(debug_assertions)] - { - assert_eq!(self.rank_out(), sk.rank()); - assert_eq!(self.n(), sk.n()); - } - - let n: Degree = sk.n(); - let rank: Rank = self.rank_out(); - - let (mut sk_dft_prep, scratch_1) = scratch.take_glwe_secret_prepared(n, rank); - sk_dft_prep.prepare(module, sk, scratch_1); - - let (mut sk_dft, scratch_2) = scratch_1.take_vec_znx_dft(n.into(), rank.into(), 1); - - (0..rank.into()).for_each(|i| { - module.vec_znx_dft_apply(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i); - }); - - let (mut sk_ij_big, scratch_3) = scratch_2.take_vec_znx_big(n.into(), 1, 1); - let (mut sk_ij, scratch_4) = scratch_3.take_glwe_secret(n, Rank(1)); - let (mut sk_ij_dft, scratch_5) = scratch_4.take_vec_znx_dft(n.into(), 1, 1); - - (0..rank.into()).for_each(|i| { - (i..rank.into()).for_each(|j| { - module.svp_apply_dft_to_dft(&mut sk_ij_dft, 0, &sk_dft_prep.data, j, &sk_dft, i); - - module.vec_znx_idft_apply_tmpa(&mut sk_ij_big, 0, &mut sk_ij_dft, 0); - module.vec_znx_big_normalize( - self.base2k().into(), - &mut sk_ij.data.as_vec_znx_mut(), - 0, - self.base2k().into(), - &sk_ij_big, - 0, - scratch_5, - ); - - self.at_mut(i, j) - .encrypt_sk(module, &sk_ij, sk, source_xa, source_xe, scratch_5); - }); - }) - } -}
@@ -0,0 +1,136 @@
+use poulpy_hal::{ + api::{ModuleN, VecZnxAddScalarInplace, VecZnxDftBytesOf, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes}, + layouts::{Backend, DataMut, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxInfos, ZnxZero}, + source::Source, +}; + +use crate::{ + GLWEEncryptSk, GLWEEncryptSkInternal, SIGMA, ScratchTakeCore, + layouts::{ + GGSW, GGSWInfos, GGSWToMut, GLWEInfos, GLWEPlaintext, LWEInfos, + prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, + }, +}; + +impl GGSW<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGSWInfos, + M: GGSWEncryptSk<BE>, + { + module.ggsw_encrypt_sk_tmp_bytes(infos) + } +} + +impl<D: DataMut> GGSW<D> { + #[allow(clippy::too_many_arguments)] + pub fn encrypt_sk<P, S, M, BE: Backend>( + &mut self, + module: &M, + pt: &P, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>, + M: GGSWEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.ggsw_encrypt_sk(self, pt, sk, source_xa, source_xe, scratch); + } +} + +pub trait GGSWEncryptSk<BE: Backend> { + fn ggsw_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGSWInfos; + + fn ggsw_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGSWToMut, + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>; +} + +impl<BE: Backend> GGSWEncryptSk<BE> for Module<BE> +where + Self: ModuleN + + GLWEEncryptSkInternal<BE> + + GLWEEncryptSk<BE> + + VecZnxDftBytesOf + + VecZnxNormalizeInplace<BE> + + VecZnxAddScalarInplace + + VecZnxNormalizeTmpBytes, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn ggsw_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGSWInfos, + { + self.glwe_encrypt_sk_tmp_bytes(infos) + .max(self.vec_znx_normalize_tmp_bytes()) + + GLWEPlaintext::bytes_of_from_infos(infos) + } + + fn ggsw_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGSWToMut, + P: ScalarZnxToRef, + S: GLWESecretPreparedToRef<BE>, + { + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + let pt: &ScalarZnx<&[u8]> = &pt.to_ref(); + let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref(); + + assert_eq!(res.rank(), sk.rank()); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(pt.n(), self.n()); + assert_eq!(sk.n(), self.n() as u32); + + let k: usize = res.k().into(); + let base2k: usize = res.base2k().into(); + let rank: usize = res.rank().into(); + let dsize: usize = res.dsize().into(); + let cols: usize = rank + 1; + + let (mut tmp_pt, scratch_1) = scratch.take_glwe_plaintext(res); + + for row_i in 0..res.dnum().into() { + tmp_pt.data.zero(); + // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt + self.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + row_i * dsize, pt, 0); + self.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scratch_1); + for col_j in 0..rank + 1 { + self.glwe_encrypt_sk_internal( + base2k, + k, + res.at_mut(row_i, col_j).data_mut(), + cols, + false, + Some((&tmp_pt, col_j)), + sk, + source_xa, + source_xe, + SIGMA, + scratch_1, + ); + } + } + } +}
@@ -1,93 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, - VecZnxAddScalarInplace, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, - }, - layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch, VecZnx, ZnxZero}, - source::Source, -}; - -use crate::{ - TakeGLWEPt, - layouts::{GGSWCiphertext, GGSWInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GLWESecretPrepared}, -}; - -impl GGSWCiphertext<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGSWInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes, - { - let size = infos.size(); - GLWECiphertext::encrypt_sk_scratch_space(module, &infos.glwe_layout()) - + VecZnx::alloc_bytes(module.n(), (infos.rank() + 1).into(), size) - + VecZnx::alloc_bytes(module.n(), 1, size) - + module.vec_znx_dft_alloc_bytes((infos.rank() + 1).into(), size) - } -} - -impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: &ScalarZnx<DataPt>, - sk: &GLWESecretPrepared<DataSk, B>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - use poulpy_hal::layouts::ZnxInfos; - - assert_eq!(self.rank(), sk.rank()); - assert_eq!(self.n(), sk.n()); - assert_eq!(pt.n() as u32, sk.n()); - } - - let base2k: usize = self.base2k().into(); - let rank: usize = self.rank().into(); - let dsize: usize = self.dsize().into(); - - let (mut tmp_pt, scratch_1) = scratch.take_glwe_pt(&self.glwe_layout()); - - (0..self.dnum().into()).for_each(|row_i| { - tmp_pt.data.zero(); - - // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt - module.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, (dsize - 1) + row_i * dsize, pt, 0); - module.vec_znx_normalize_inplace(base2k, &mut tmp_pt.data, 0, scratch_1); - - (0..rank + 1).for_each(|col_j| { - // rlwe encrypt of vec_znx_pt into vec_znx_ct - - self.at_mut(row_i, col_j).encrypt_sk_internal( - module, - Some((&tmp_pt, col_j)), - sk, - source_xa, - source_xe, - scratch_1, - ); - }); - }); - } -}
@@ -0,0 +1,562 @@
+use poulpy_hal::{ + api::{ + ModuleN, ScratchAvailable, ScratchTakeBasic, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolBytesOf, SvpPrepare, + VecZnxAddInplace, VecZnxAddNormal, VecZnxBigAddNormal, VecZnxBigAddSmallInplace, VecZnxBigBytesOf, VecZnxBigNormalize, + VecZnxDftApply, VecZnxDftBytesOf, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, + VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, + }, + layouts::{Backend, DataMut, Module, ScalarZnx, Scratch, VecZnx, VecZnxBig, VecZnxToMut, ZnxInfos, ZnxZero}, + source::Source, +}; + +use crate::{ + GetDistribution, ScratchTakeCore, + dist::Distribution, + encryption::{SIGMA, SIGMA_BOUND}, + layouts::{ + GLWE, GLWEInfos, GLWEPlaintext, GLWEPlaintextToRef, GLWEPrepared, GLWEPreparedToRef, GLWEToMut, LWEInfos, + prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, + }, +}; + +impl GLWE<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GLWEInfos, + M: GLWEEncryptSk<BE>, + { + module.glwe_encrypt_sk_tmp_bytes(infos) + } + + pub fn encrypt_pk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GLWEInfos, + M: GLWEEncryptPk<BE>, + { + module.glwe_encrypt_pk_tmp_bytes(infos) + } +} + +impl<D: DataMut> GLWE<D> { + pub fn encrypt_sk<P, S, M, BE: Backend>( + &mut self, + module: &M, + pt: &P, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + P: GLWEPlaintextToRef, + S: GLWESecretPreparedToRef<BE>, + M: GLWEEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_encrypt_sk(self, pt, sk, source_xa, source_xe, scratch); + } + + pub fn encrypt_zero_sk<S, M, BE: Backend>( + &mut self, + module: &M, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S: GLWESecretPreparedToRef<BE>, + M: GLWEEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_encrypt_zero_sk(self, sk, source_xa, source_xe, scratch); + } + + pub fn encrypt_pk<P, K, M, BE: Backend>( + &mut self, + module: &M, + pt: &P, + pk: &K, + source_xu: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + P: GLWEPlaintextToRef + GLWEInfos, + K: GLWEPreparedToRef<BE> + GetDistribution + GLWEInfos, + M: GLWEEncryptPk<BE>, + { + module.glwe_encrypt_pk(self, pt, pk, source_xu, source_xe, scratch); + } + + pub fn encrypt_zero_pk<K, M, BE: Backend>( + &mut self, + module: &M, + pk: &K, + source_xu: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + K: GLWEPreparedToRef<BE> + GetDistribution + GLWEInfos, + M: GLWEEncryptPk<BE>, + { + module.glwe_encrypt_zero_pk(self, pk, source_xu, source_xe, scratch); + } +} + +pub trait GLWEEncryptSk<BE: Backend> { + fn glwe_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GLWEInfos; + + fn glwe_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut, + P: GLWEPlaintextToRef, + S: GLWESecretPreparedToRef<BE>; + + fn glwe_encrypt_zero_sk<R, S>( + &self, + res: &mut R, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut, + S: GLWESecretPreparedToRef<BE>; +} + +impl<BE: Backend> GLWEEncryptSk<BE> for Module<BE> +where + Self: Sized + ModuleN + VecZnxNormalizeTmpBytes + VecZnxDftBytesOf + GLWEEncryptSkInternal<BE>, + Scratch<BE>: ScratchAvailable, +{ + fn glwe_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GLWEInfos, + { + let size: usize = infos.size(); + assert_eq!(self.n() as u32, infos.n()); + self.vec_znx_normalize_tmp_bytes() + 2 * VecZnx::bytes_of(self.n(), 1, size) + self.bytes_of_vec_znx_dft(1, size) + } + + fn glwe_encrypt_sk<R, P, S>( + &self, + res: &mut R, + pt: &P, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut, + P: GLWEPlaintextToRef, + S: GLWESecretPreparedToRef<BE>, + { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let pt: &GLWEPlaintext<&[u8]> = &pt.to_ref(); + let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref(); + + assert_eq!(res.rank(), sk.rank()); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(sk.n(), self.n() as u32); + assert_eq!(pt.n(), self.n() as u32); + assert!( + scratch.available() >= self.glwe_encrypt_sk_tmp_bytes(res), + "scratch.available(): {} < GLWE::encrypt_sk_tmp_bytes: {}", + scratch.available(), + self.glwe_encrypt_sk_tmp_bytes(res) + ); + + let cols: usize = (res.rank() + 1).into(); + self.glwe_encrypt_sk_internal( + res.base2k().into(), + res.k().into(), + res.data_mut(), + cols, + false, + Some((pt, 0)), + sk, + source_xa, + source_xe, + SIGMA, + scratch, + ); + } + + fn glwe_encrypt_zero_sk<R, S>( + &self, + res: &mut R, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut, + S: GLWESecretPreparedToRef<BE>, + { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref(); + + assert_eq!(res.rank(), sk.rank()); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(sk.n(), self.n() as u32); + assert!( + scratch.available() >= self.glwe_encrypt_sk_tmp_bytes(res), + "scratch.available(): {} < GLWE::encrypt_sk_tmp_bytes: {}", + scratch.available(), + self.glwe_encrypt_sk_tmp_bytes(res) + ); + + let cols: usize = (res.rank() + 1).into(); + self.glwe_encrypt_sk_internal( + res.base2k().into(), + res.k().into(), + res.data_mut(), + cols, + false, + None::<(&GLWEPlaintext<Vec<u8>>, usize)>, + sk, + source_xa, + source_xe, + SIGMA, + scratch, + ); + } +} + +pub trait GLWEEncryptPk<BE: Backend> { + fn glwe_encrypt_pk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GLWEInfos; + + fn glwe_encrypt_pk<R, P, K>( + &self, + res: &mut R, + pt: &P, + pk: &K, + source_xu: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut, + P: GLWEPlaintextToRef + GLWEInfos, + K: GLWEPreparedToRef<BE> + GetDistribution + GLWEInfos; + + fn glwe_encrypt_zero_pk<R, K>( + &self, + res: &mut R, + pk: &K, + source_xu: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut, + K: GLWEPreparedToRef<BE> + GetDistribution + GLWEInfos; +} + +impl<BE: Backend> GLWEEncryptPk<BE> for Module<BE> +where + Self: GLWEEncryptPkInternal<BE> + VecZnxDftBytesOf + SvpPPolBytesOf + VecZnxBigBytesOf + VecZnxNormalizeTmpBytes, +{ + fn glwe_encrypt_pk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GLWEInfos, + { + let size: usize = infos.size(); + assert_eq!(self.n() as u32, infos.n()); + ((self.bytes_of_vec_znx_dft(1, size) + self.bytes_of_vec_znx_big(1, size)).max(ScalarZnx::bytes_of(self.n(), 1))) + + self.bytes_of_svp_ppol(1) + + self.vec_znx_normalize_tmp_bytes() + } + + fn glwe_encrypt_pk<R, P, K>( + &self, + res: &mut R, + pt: &P, + pk: &K, + source_xu: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut, + P: GLWEPlaintextToRef + GLWEInfos, + K: GLWEPreparedToRef<BE> + GetDistribution + GLWEInfos, + { + self.glwe_encrypt_pk_internal(res, Some((pt, 0)), pk, source_xu, source_xe, scratch); + } + + fn glwe_encrypt_zero_pk<R, K>( + &self, + res: &mut R, + pk: &K, + source_xu: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut, + K: GLWEPreparedToRef<BE> + GetDistribution + GLWEInfos, + { + self.glwe_encrypt_pk_internal( + res, + None::<(&GLWEPlaintext<Vec<u8>>, usize)>, + pk, + source_xu, + source_xe, + scratch, + ); + } +} + +pub(crate) trait GLWEEncryptPkInternal<BE: Backend> { + fn glwe_encrypt_pk_internal<R, P, K>( + &self, + res: &mut R, + pt: Option<(&P, usize)>, + pk: &K, + source_xu: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut, + P: GLWEPlaintextToRef + GLWEInfos, + K: GLWEPreparedToRef<BE> + GetDistribution + GLWEInfos; +} + +impl<BE: Backend> GLWEEncryptPkInternal<BE> for Module<BE> +where + Self: SvpPrepare<BE> + + SvpApplyDftToDft<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddNormal<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + SvpPPolBytesOf + + ModuleN + + VecZnxDftBytesOf, + Scratch<BE>: ScratchTakeBasic, +{ + fn glwe_encrypt_pk_internal<R, P, K>( + &self, + res: &mut R, + pt: Option<(&P, usize)>, + pk: &K, + source_xu: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut, + P: GLWEPlaintextToRef + GLWEInfos, + K: GLWEPreparedToRef<BE> + GetDistribution + GLWEInfos, + { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + + assert_eq!(res.base2k(), pk.base2k()); + assert_eq!(res.n(), pk.n()); + assert_eq!(res.rank(), pk.rank()); + if let Some((pt, _)) = pt { + assert_eq!(pt.base2k(), pk.base2k()); + assert_eq!(pt.n(), pk.n()); + } + + let base2k: usize = pk.base2k().into(); + let size_pk: usize = pk.size(); + let cols: usize = (res.rank() + 1).into(); + + // Generates u according to the underlying secret distribution. + let (mut u_dft, scratch_1) = scratch.take_svp_ppol(self, 1); + + { + let (mut u, _) = scratch_1.take_scalar_znx(self.n(), 1); + match pk.dist() { + Distribution::NONE => panic!( + "invalid public key: SecretDistribution::NONE, ensure it has been correctly intialized through \ + Self::generate" + ), + Distribution::TernaryFixed(hw) => u.fill_ternary_hw(0, *hw, source_xu), + Distribution::TernaryProb(prob) => u.fill_ternary_prob(0, *prob, source_xu), + Distribution::BinaryFixed(hw) => u.fill_binary_hw(0, *hw, source_xu), + Distribution::BinaryProb(prob) => u.fill_binary_prob(0, *prob, source_xu), + Distribution::BinaryBlock(block_size) => u.fill_binary_block(0, *block_size, source_xu), + Distribution::ZERO => {} + } + + self.svp_prepare(&mut u_dft, 0, &u, 0); + } + + { + let pk: &GLWEPrepared<&[u8], BE> = &pk.to_ref(); + + // ct[i] = pk[i] * u + ei (+ m if col = i) + for i in 0..cols { + let (mut ci_dft, scratch_2) = scratch_1.take_vec_znx_dft(self, 1, size_pk); + // ci_dft = DFT(u) * DFT(pk[i]) + self.svp_apply_dft_to_dft(&mut ci_dft, 0, &u_dft, 0, &pk.data, i); + + // ci_big = u * p[i] + let mut ci_big = self.vec_znx_idft_apply_consume(ci_dft); + + // ci_big = u * pk[i] + e + self.vec_znx_big_add_normal( + base2k, + &mut ci_big, + 0, + pk.k().into(), + source_xe, + SIGMA, + SIGMA_BOUND, + ); + + // ci_big = u * pk[i] + e + m (if col = i) + if let Some((pt, col)) = pt + && col == i + { + self.vec_znx_big_add_small_inplace(&mut ci_big, 0, &pt.to_ref().data, 0); + } + + // ct[i] = norm(ci_big) + self.vec_znx_big_normalize(base2k, &mut res.data, i, base2k, &ci_big, 0, scratch_2); + } + } + } +} + +pub(crate) trait GLWEEncryptSkInternal<BE: Backend> { + #[allow(clippy::too_many_arguments)] + fn glwe_encrypt_sk_internal<R, P, S>( + &self, + base2k: usize, + k: usize, + res: &mut R, + cols: usize, + compressed: bool, + pt: Option<(&P, usize)>, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch<BE>, + ) where + R: VecZnxToMut, + P: GLWEPlaintextToRef, + S: GLWESecretPreparedToRef<BE>; +} + +impl<BE: Backend> GLWEEncryptSkInternal<BE> for Module<BE> +where + Self: ModuleN + + VecZnxDftBytesOf + + VecZnxBigNormalize<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDftInplace<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxNormalizeTmpBytes + + VecZnxFillUniform + + VecZnxSubInplace + + VecZnxAddInplace + + VecZnxNormalizeInplace<BE> + + VecZnxAddNormal + + VecZnxNormalize<BE> + + VecZnxSub, + Scratch<BE>: ScratchTakeBasic, +{ + fn glwe_encrypt_sk_internal<R, P, S>( + &self, + base2k: usize, + k: usize, + res: &mut R, + cols: usize, + compressed: bool, + pt: Option<(&P, usize)>, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch<BE>, + ) where + R: VecZnxToMut, + P: GLWEPlaintextToRef, + S: GLWESecretPreparedToRef<BE>, + { + let ct: &mut VecZnx<&mut [u8]> = &mut res.to_mut(); + let sk: GLWESecretPrepared<&[u8], BE> = sk.to_ref(); + + if compressed { + assert_eq!( + ct.cols(), + 1, + "invalid glwe: compressed tag=true but #cols={} != 1", + ct.cols() + ) + } + + assert!( + sk.dist != Distribution::NONE, + "glwe secret distribution is NONE (have you prepared the key?)" + ); + + let size: usize = ct.size(); + + let (mut c0, scratch_1) = scratch.take_vec_znx(self.n(), 1, size); + c0.zero(); + + { + let (mut ci, scratch_2) = scratch_1.take_vec_znx(self.n(), 1, size); + + // ct[i] = uniform + // ct[0] -= c[i] * s[i], + (1..cols).for_each(|i| { + let col_ct: usize = if compressed { 0 } else { i }; + + // ct[i] = uniform (+ pt) + self.vec_znx_fill_uniform(base2k, ct, col_ct, source_xa); + + // println!("vec_znx_fill_uniform: {}", ct); + + let (mut ci_dft, scratch_3) = scratch_2.take_vec_znx_dft(self, 1, size); + + // ci = ct[i] - pt + // i.e. we act as we sample ct[i] already as uniform + pt + // and if there is a pt, then we subtract it before applying DFT + if let Some((pt, col)) = pt { + if i == col { + self.vec_znx_sub(&mut ci, 0, ct, col_ct, &pt.to_ref().data, 0); + self.vec_znx_normalize_inplace(base2k, &mut ci, 0, scratch_3); + self.vec_znx_dft_apply(1, 0, &mut ci_dft, 0, &ci, 0); + } else { + self.vec_znx_dft_apply(1, 0, &mut ci_dft, 0, ct, col_ct); + } + } else { + self.vec_znx_dft_apply(1, 0, &mut ci_dft, 0, ct, col_ct); + } + + self.svp_apply_dft_to_dft_inplace(&mut ci_dft, 0, &sk.data, i - 1); + let ci_big: VecZnxBig<&mut [u8], BE> = self.vec_znx_idft_apply_consume(ci_dft); + + // use c[0] as buffer, which is overwritten later by the normalization step + self.vec_znx_big_normalize(base2k, &mut ci, 0, base2k, &ci_big, 0, scratch_3); + + // c0_tmp = -c[i] * s[i] (use c[0] as buffer) + self.vec_znx_sub_inplace(&mut c0, 0, &ci, 0); + }); + } + + // c[0] += e + self.vec_znx_add_normal(base2k, &mut c0, 0, k, source_xe, sigma, SIGMA_BOUND); + + // c[0] += m if col = 0 + if let Some((pt, col)) = pt + && col == 0 + { + self.vec_znx_add_inplace(&mut c0, 0, &pt.to_ref().data, 0); + } + + // c[0] = norm(c[0]) + self.vec_znx_normalize(base2k, ct, 0, base2k, &c0, 0, scratch_1); + } +}
@@ -0,0 +1,163 @@
+use poulpy_hal::{ + api::{ScratchAvailable, SvpPPolBytesOf, VecZnxAutomorphism}, + layouts::{Backend, DataMut, GaloisElement, Module, Scratch}, + source::Source, +}; + +use crate::{ + GGLWEEncryptSk, ScratchTakeCore, + layouts::{ + GGLWEInfos, GGLWEToMut, GGLWEToRef, GLWEAutomorphismKey, GLWEInfos, GLWESecret, GLWESecretPrepared, + GLWESecretPreparedFactory, GLWESecretToRef, LWEInfos, SetGaloisElement, + }, +}; + +impl GLWEAutomorphismKey<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWEAutomorphismKeyEncryptSk<BE>, + { + module.glwe_automorphism_key_encrypt_sk_tmp_bytes(infos) + } + + pub fn encrypt_pk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWEAutomorphismKeyEncryptPk<BE>, + { + module.glwe_automorphism_key_encrypt_pk_tmp_bytes(infos) + } +} + +impl<DM: DataMut> GLWEAutomorphismKey<DM> +where + Self: GGLWEToRef, +{ + pub fn encrypt_sk<S, M, BE: Backend>( + &mut self, + module: &M, + p: i64, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S: GLWESecretToRef, + M: GLWEAutomorphismKeyEncryptSk<BE>, + { + module.glwe_automorphism_key_encrypt_sk(self, p, sk, source_xa, source_xe, scratch); + } +} + +pub trait GLWEAutomorphismKeyEncryptSk<BE: Backend> { + fn glwe_automorphism_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn glwe_automorphism_key_encrypt_sk<R, S>( + &self, + res: &mut R, + p: i64, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWEToMut + SetGaloisElement + GGLWEInfos, + S: GLWESecretToRef; +} + +impl<BE: Backend> GLWEAutomorphismKeyEncryptSk<BE> for Module<BE> +where + Self: GGLWEEncryptSk<BE> + VecZnxAutomorphism + GaloisElement + SvpPPolBytesOf + GLWESecretPreparedFactory<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn glwe_automorphism_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_in(), + infos.rank_out(), + "rank_in != rank_out is not supported for GGLWEAutomorphismKey" + ); + GLWESecretPrepared::bytes_of_from_infos(self, infos) + + self + .gglwe_encrypt_sk_tmp_bytes(infos) + .max(GLWESecret::bytes_of_from_infos(infos)) + } + + fn glwe_automorphism_key_encrypt_sk<R, S>( + &self, + res: &mut R, + p: i64, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWEToMut + SetGaloisElement + GGLWEInfos, + S: GLWESecretToRef, + { + let sk: &GLWESecret<&[u8]> = &sk.to_ref(); + + assert_eq!(res.n(), sk.n()); + assert_eq!(res.rank_out(), res.rank_in()); + assert_eq!(sk.rank(), res.rank_out()); + assert!( + scratch.available() >= self.glwe_automorphism_key_encrypt_sk_tmp_bytes(res), + "scratch.available(): {} < AutomorphismKey::encrypt_sk_tmp_bytes: {:?}", + scratch.available(), + self.glwe_automorphism_key_encrypt_sk_tmp_bytes(res) + ); + + let (mut sk_out_prepared, scratch_1) = scratch.take_glwe_secret_prepared(self, sk.rank()); + + { + let (mut sk_out, _) = scratch_1.take_glwe_secret(sk.n(), sk.rank()); + sk_out.dist = sk.dist; + + for i in 0..sk.rank().into() { + self.vec_znx_automorphism( + self.galois_element_inv(p), + &mut sk_out.data.as_vec_znx_mut(), + i, + &sk.data.as_vec_znx(), + i, + ); + } + sk_out_prepared.prepare(self, &sk_out); + } + + self.gglwe_encrypt_sk( + res, + &sk.data, + &sk_out_prepared, + source_xa, + source_xe, + scratch_1, + ); + + res.set_p(p); + } +} + +pub trait GLWEAutomorphismKeyEncryptPk<BE: Backend> { + fn glwe_automorphism_key_encrypt_pk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; +} + +impl<BE: Backend> GLWEAutomorphismKeyEncryptPk<BE> for Module<BE> +where + Self:, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn glwe_automorphism_key_encrypt_pk_tmp_bytes<A>(&self, _infos: &A) -> usize + where + A: GGLWEInfos, + { + unimplemented!() + } +}
@@ -1,407 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeSvpPPol, - TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxBigAddNormal, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, - VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, - }, - layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch, VecZnx, VecZnxBig, ZnxInfos, ZnxZero}, - source::Source, -}; - -use crate::{ - dist::Distribution, - encryption::{SIGMA, SIGMA_BOUND}, - layouts::{ - GLWECiphertext, GLWEInfos, GLWEPlaintext, LWEInfos, - prepared::{GLWEPublicKeyPrepared, GLWESecretPrepared}, - }, -}; - -impl GLWECiphertext<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GLWEInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes, - { - let size: usize = infos.size(); - assert_eq!(module.n() as u32, infos.n()); - module.vec_znx_normalize_tmp_bytes() - + 2 * VecZnx::alloc_bytes(module.n(), 1, size) - + module.vec_znx_dft_alloc_bytes(1, size) - } - pub fn encrypt_pk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GLWEInfos, - Module<B>: VecZnxDftAllocBytes + SvpPPolAllocBytes + VecZnxBigAllocBytes + VecZnxNormalizeTmpBytes, - { - let size: usize = infos.size(); - assert_eq!(module.n() as u32, infos.n()); - ((module.vec_znx_dft_alloc_bytes(1, size) + module.vec_znx_big_alloc_bytes(1, size)) - | ScalarZnx::alloc_bytes(module.n(), 1)) - + module.svp_ppol_alloc_bytes(1) - + module.vec_znx_normalize_tmp_bytes() - } -} - -impl<DataSelf: DataMut> GLWECiphertext<DataSelf> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: &GLWEPlaintext<DataPt>, - sk: &GLWESecretPrepared<DataSk, B>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - assert_eq!(self.rank(), sk.rank()); - assert_eq!(sk.n(), self.n()); - assert_eq!(pt.n(), self.n()); - assert!( - scratch.available() >= GLWECiphertext::encrypt_sk_scratch_space(module, self), - "scratch.available(): {} < GLWECiphertext::encrypt_sk_scratch_space: {}", - scratch.available(), - GLWECiphertext::encrypt_sk_scratch_space(module, self) - ) - } - - self.encrypt_sk_internal(module, Some((pt, 0)), sk, source_xa, source_xe, scratch); - } - - pub fn encrypt_zero_sk<DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - sk: &GLWESecretPrepared<DataSk, B>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - assert_eq!(self.rank(), sk.rank()); - assert_eq!(sk.n(), self.n()); - assert!( - scratch.available() >= GLWECiphertext::encrypt_sk_scratch_space(module, self), - "scratch.available(): {} < GLWECiphertext::encrypt_sk_scratch_space: {}", - scratch.available(), - GLWECiphertext::encrypt_sk_scratch_space(module, self) - ) - } - self.encrypt_sk_internal( - module, - None::<(&GLWEPlaintext<Vec<u8>>, usize)>, - sk, - source_xa, - source_xe, - scratch, - ); - } - - #[allow(clippy::too_many_arguments)] - pub(crate) fn encrypt_sk_internal<DataPt: DataRef, DataSk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: Option<(&GLWEPlaintext<DataPt>, usize)>, - sk: &GLWESecretPrepared<DataSk, B>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - let cols: usize = (self.rank() + 1).into(); - glwe_encrypt_sk_internal( - module, - self.base2k().into(), - self.k().into(), - &mut self.data, - cols, - false, - pt, - sk, - source_xa, - source_xe, - SIGMA, - scratch, - ); - } - - #[allow(clippy::too_many_arguments)] - pub fn encrypt_pk<DataPt: DataRef, DataPk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: &GLWEPlaintext<DataPt>, - pk: &GLWEPublicKeyPrepared<DataPk, B>, - source_xu: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: SvpPrepare<B> - + SvpApplyDftToDft<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddNormal<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B>, - Scratch<B>: TakeSvpPPol<B> + TakeScalarZnx + TakeVecZnxDft<B>, - { - self.encrypt_pk_internal::<DataPt, DataPk, B>(module, Some((pt, 0)), pk, source_xu, source_xe, scratch); - } - - pub fn encrypt_zero_pk<DataPk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pk: &GLWEPublicKeyPrepared<DataPk, B>, - source_xu: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: SvpPrepare<B> - + SvpApplyDftToDft<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddNormal<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B>, - Scratch<B>: TakeSvpPPol<B> + TakeScalarZnx + TakeVecZnxDft<B>, - { - self.encrypt_pk_internal::<Vec<u8>, DataPk, B>( - module, - None::<(&GLWEPlaintext<Vec<u8>>, usize)>, - pk, - source_xu, - source_xe, - scratch, - ); - } - - #[allow(clippy::too_many_arguments)] - pub(crate) fn encrypt_pk_internal<DataPt: DataRef, DataPk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - pt: Option<(&GLWEPlaintext<DataPt>, usize)>, - pk: &GLWEPublicKeyPrepared<DataPk, B>, - source_xu: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - Module<B>: SvpPrepare<B> - + SvpApplyDftToDft<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddNormal<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B>, - Scratch<B>: TakeSvpPPol<B> + TakeScalarZnx + TakeVecZnxDft<B>, - { - #[cfg(debug_assertions)] - { - assert_eq!(self.base2k(), pk.base2k()); - assert_eq!(self.n(), pk.n()); - assert_eq!(self.rank(), pk.rank()); - if let Some((pt, _)) = pt { - assert_eq!(pt.base2k(), pk.base2k()); - assert_eq!(pt.n(), pk.n()); - } - } - - let base2k: usize = pk.base2k().into(); - let size_pk: usize = pk.size(); - let cols: usize = (self.rank() + 1).into(); - - // Generates u according to the underlying secret distribution. - let (mut u_dft, scratch_1) = scratch.take_svp_ppol(self.n().into(), 1); - - { - let (mut u, _) = scratch_1.take_scalar_znx(self.n().into(), 1); - match pk.dist { - Distribution::NONE => panic!( - "invalid public key: SecretDistribution::NONE, ensure it has been correctly intialized through \ - Self::generate" - ), - Distribution::TernaryFixed(hw) => u.fill_ternary_hw(0, hw, source_xu), - Distribution::TernaryProb(prob) => u.fill_ternary_prob(0, prob, source_xu), - Distribution::BinaryFixed(hw) => u.fill_binary_hw(0, hw, source_xu), - Distribution::BinaryProb(prob) => u.fill_binary_prob(0, prob, source_xu), - Distribution::BinaryBlock(block_size) => u.fill_binary_block(0, block_size, source_xu), - Distribution::ZERO => {} - } - - module.svp_prepare(&mut u_dft, 0, &u, 0); - } - - // ct[i] = pk[i] * u + ei (+ m if col = i) - (0..cols).for_each(|i| { - let (mut ci_dft, scratch_2) = scratch_1.take_vec_znx_dft(self.n().into(), 1, size_pk); - // ci_dft = DFT(u) * DFT(pk[i]) - module.svp_apply_dft_to_dft(&mut ci_dft, 0, &u_dft, 0, &pk.data, i); - - // ci_big = u * p[i] - let mut ci_big = module.vec_znx_idft_apply_consume(ci_dft); - - // ci_big = u * pk[i] + e - module.vec_znx_big_add_normal( - base2k, - &mut ci_big, - 0, - pk.k().into(), - source_xe, - SIGMA, - SIGMA_BOUND, - ); - - // ci_big = u * pk[i] + e + m (if col = i) - if let Some((pt, col)) = pt - && col == i - { - module.vec_znx_big_add_small_inplace(&mut ci_big, 0, &pt.data, 0); - } - - // ct[i] = norm(ci_big) - module.vec_znx_big_normalize(base2k, &mut self.data, i, base2k, &ci_big, 0, scratch_2); - }); - } -} - -#[allow(clippy::too_many_arguments)] -pub(crate) fn glwe_encrypt_sk_internal<DataCt: DataMut, DataPt: DataRef, DataSk: DataRef, B: Backend>( - module: &Module<B>, - base2k: usize, - k: usize, - ct: &mut VecZnx<DataCt>, - cols: usize, - compressed: bool, - pt: Option<(&GLWEPlaintext<DataPt>, usize)>, - sk: &GLWESecretPrepared<DataSk, B>, - source_xa: &mut Source, - source_xe: &mut Source, - sigma: f64, - scratch: &mut Scratch<B>, -) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, -{ - #[cfg(debug_assertions)] - { - if compressed { - assert_eq!( - ct.cols(), - 1, - "invalid ciphertext: compressed tag=true but #cols={} != 1", - ct.cols() - ) - } - } - - let size: usize = ct.size(); - - let (mut c0, scratch_1) = scratch.take_vec_znx(ct.n(), 1, size); - c0.zero(); - - { - let (mut ci, scratch_2) = scratch_1.take_vec_znx(ct.n(), 1, size); - - // ct[i] = uniform - // ct[0] -= c[i] * s[i], - (1..cols).for_each(|i| { - let col_ct: usize = if compressed { 0 } else { i }; - - // ct[i] = uniform (+ pt) - module.vec_znx_fill_uniform(base2k, ct, col_ct, source_xa); - - let (mut ci_dft, scratch_3) = scratch_2.take_vec_znx_dft(ct.n(), 1, size); - - // ci = ct[i] - pt - // i.e. we act as we sample ct[i] already as uniform + pt - // and if there is a pt, then we subtract it before applying DFT - if let Some((pt, col)) = pt { - if i == col { - module.vec_znx_sub(&mut ci, 0, ct, col_ct, &pt.data, 0); - module.vec_znx_normalize_inplace(base2k, &mut ci, 0, scratch_3); - module.vec_znx_dft_apply(1, 0, &mut ci_dft, 0, &ci, 0); - } else { - module.vec_znx_dft_apply(1, 0, &mut ci_dft, 0, ct, col_ct); - } - } else { - module.vec_znx_dft_apply(1, 0, &mut ci_dft, 0, ct, col_ct); - } - - module.svp_apply_dft_to_dft_inplace(&mut ci_dft, 0, &sk.data, i - 1); - let ci_big: VecZnxBig<&mut [u8], B> = module.vec_znx_idft_apply_consume(ci_dft); - - // use c[0] as buffer, which is overwritten later by the normalization step - module.vec_znx_big_normalize(base2k, &mut ci, 0, base2k, &ci_big, 0, scratch_3); - - // c0_tmp = -c[i] * s[i] (use c[0] as buffer) - module.vec_znx_sub_inplace(&mut c0, 0, &ci, 0); - }); - } - - // c[0] += e - module.vec_znx_add_normal(base2k, &mut c0, 0, k, source_xe, sigma, SIGMA_BOUND); - - // c[0] += m if col = 0 - if let Some((pt, col)) = pt - && col == 0 - { - module.vec_znx_add_inplace(&mut c0, 0, &pt.data, 0); - } - - // c[0] = norm(c[0]) - module.vec_znx_normalize(base2k, ct, 0, base2k, &c0, 0, scratch_1); -}
@@ -1,61 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, VecZnxAddInplace, VecZnxAddNormal, VecZnxBigNormalize, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, - }, - layouts::{Backend, DataMut, DataRef, Module, ScratchOwned}, - oep::{ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxDftImpl, TakeVecZnxImpl}, - source::Source, -}; - -use crate::layouts::{GLWECiphertext, GLWEPublicKey, prepared::GLWESecretPrepared}; - -impl<D: DataMut> GLWEPublicKey<D> { - pub fn generate_from_sk<S: DataRef, B>( - &mut self, - module: &Module<B>, - sk: &GLWESecretPrepared<S, B>, - source_xa: &mut Source, - source_xe: &mut Source, - ) where - Module<B>:, - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - B: Backend - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + TakeVecZnxDftImpl<B> - + ScratchAvailableImpl<B> - + TakeVecZnxImpl<B>, - { - #[cfg(debug_assertions)] - { - use crate::{Distribution, layouts::LWEInfos}; - - assert_eq!(self.n(), sk.n()); - - if sk.dist == Distribution::NONE { - panic!("invalid sk: SecretDistribution::NONE") - } - } - - // Its ok to allocate scratch space here since pk is usually generated only once. - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWECiphertext::encrypt_sk_scratch_space(module, self)); - - let mut tmp: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(self); - tmp.encrypt_zero_sk(module, sk, source_xa, source_xe, scratch.borrow()); - self.dist = sk.dist; - } -}
@@ -0,0 +1,62 @@
+use poulpy_hal::{ + api::{ScratchOwnedAlloc, ScratchOwnedBorrow}, + layouts::{Backend, DataMut, Module, Scratch, ScratchOwned}, + source::Source, +}; + +use crate::{ + Distribution, GLWEEncryptSk, GetDistribution, GetDistributionMut, ScratchTakeCore, + layouts::{ + GLWE, GLWEInfos, GLWEPublicKey, GLWEToMut, + prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, + }, +}; + +impl<D: DataMut> GLWEPublicKey<D> { + pub fn generate<S, M, BE: Backend>(&mut self, module: &M, sk: &S, source_xa: &mut Source, source_xe: &mut Source) + where + S: GLWESecretPreparedToRef<BE> + GetDistribution, + M: GLWEPublicKeyGenerate<BE>, + { + module.glwe_public_key_generate(self, sk, source_xa, source_xe); + } +} + +pub trait GLWEPublicKeyGenerate<BE: Backend> { + fn glwe_public_key_generate<R, S>(&self, res: &mut R, sk: &S, source_xa: &mut Source, source_xe: &mut Source) + where + R: GLWEToMut + GetDistributionMut + GLWEInfos, + S: GLWESecretPreparedToRef<BE> + GetDistribution; +} + +impl<BE: Backend> GLWEPublicKeyGenerate<BE> for Module<BE> +where + Self: GLWEEncryptSk<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn glwe_public_key_generate<R, S>(&self, res: &mut R, sk: &S, source_xa: &mut Source, source_xe: &mut Source) + where + R: GLWEToMut + GetDistributionMut + GLWEInfos, + S: GLWESecretPreparedToRef<BE> + GetDistribution, + { + { + let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref(); + + assert_eq!(res.n(), self.n() as u32); + assert_eq!(sk.n(), self.n() as u32); + + if sk.dist == Distribution::NONE { + panic!("invalid sk: SecretDistribution::NONE") + } + + // Its ok to allocate scratch space here since pk is usually generated only once. + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(self.glwe_encrypt_sk_tmp_bytes(res)); + + let mut tmp: GLWE<Vec<u8>> = GLWE::alloc_from_infos(res); + + tmp.encrypt_zero_sk(self, sk, source_xa, source_xe, scratch.borrow()); + } + *res.dist_mut() = *sk.dist(); + } +}
@@ -0,0 +1,160 @@
+use poulpy_hal::{ + api::{ModuleN, ScratchAvailable, ScratchTakeBasic, SvpPrepare, VecZnxSwitchRing}, + layouts::{Backend, DataMut, Module, ScalarZnx, Scratch}, + source::Source, +}; + +use crate::{ + ScratchTakeCore, + encryption::gglwe::GGLWEEncryptSk, + layouts::{ + GGLWEInfos, GGLWEToMut, GLWEInfos, GLWESecret, GLWESecretToRef, GLWESwitchingKey, GLWESwitchingKeyDegreesMut, LWEInfos, + prepared::GLWESecretPreparedFactory, + }, +}; + +impl GLWESwitchingKey<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWESwitchingKeyEncryptSk<BE>, + { + module.glwe_switching_key_encrypt_sk_tmp_bytes(infos) + } + + pub fn encrypt_pk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWESwitchingKeyEncryptPk<BE>, + { + module.glwe_switching_key_encrypt_pk_tmp_bytes(infos) + } +} + +impl<DataSelf: DataMut> GLWESwitchingKey<DataSelf> { + pub fn encrypt_sk<M, S1, S2, BE: Backend>( + &mut self, + module: &M, + sk_in: &S1, + sk_out: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S1: GLWESecretToRef, + S2: GLWESecretToRef, + M: GLWESwitchingKeyEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_switching_key_encrypt_sk(self, sk_in, sk_out, source_xa, source_xe, scratch); + } +} + +pub trait GLWESwitchingKeyEncryptSk<BE: Backend> { + fn glwe_switching_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn glwe_switching_key_encrypt_sk<R, S1, S2>( + &self, + res: &mut R, + sk_in: &S1, + sk_out: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWEToMut + GLWESwitchingKeyDegreesMut + GGLWEInfos, + S1: GLWESecretToRef, + S2: GLWESecretToRef; +} + +impl<BE: Backend> GLWESwitchingKeyEncryptSk<BE> for Module<BE> +where + Self: ModuleN + GGLWEEncryptSk<BE> + GLWESecretPreparedFactory<BE> + VecZnxSwitchRing + SvpPrepare<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn glwe_switching_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.gglwe_encrypt_sk_tmp_bytes(infos) + .max(ScalarZnx::bytes_of(self.n(), 1)) + + ScalarZnx::bytes_of(self.n(), infos.rank_in().into()) + + self.bytes_of_glwe_secret_prepared_from_infos(infos) + } + + fn glwe_switching_key_encrypt_sk<R, S1, S2>( + &self, + res: &mut R, + sk_in: &S1, + sk_out: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWEToMut + GLWESwitchingKeyDegreesMut + GGLWEInfos, + S1: GLWESecretToRef, + S2: GLWESecretToRef, + { + let sk_in: &GLWESecret<&[u8]> = &sk_in.to_ref(); + let sk_out: &GLWESecret<&[u8]> = &sk_out.to_ref(); + + assert!(sk_in.n().0 <= self.n() as u32); + assert!(sk_out.n().0 <= self.n() as u32); + assert!( + scratch.available() >= self.glwe_switching_key_encrypt_sk_tmp_bytes(res), + "scratch.available()={} < GLWESwitchingKey::encrypt_sk_tmp_bytes={}", + scratch.available(), + self.glwe_switching_key_encrypt_sk_tmp_bytes(res) + ); + + let (mut sk_in_tmp, scratch_1) = scratch.take_scalar_znx(self.n(), sk_in.rank().into()); + for i in 0..sk_in.rank().into() { + self.vec_znx_switch_ring( + &mut sk_in_tmp.as_vec_znx_mut(), + i, + &sk_in.data.as_vec_znx(), + i, + ); + } + + let (mut sk_out_tmp, scratch_2) = scratch_1.take_glwe_secret_prepared(self, sk_out.rank()); + { + let (mut tmp, _) = scratch_2.take_scalar_znx(self.n(), 1); + for i in 0..sk_out.rank().into() { + self.vec_znx_switch_ring(&mut tmp.as_vec_znx_mut(), 0, &sk_out.data.as_vec_znx(), i); + self.svp_prepare(&mut sk_out_tmp.data, i, &tmp, 0); + } + } + + sk_out_tmp.dist = sk_out.dist; + + self.gglwe_encrypt_sk( + res, + &sk_in_tmp, + &sk_out_tmp, + source_xa, + source_xe, + scratch_2, + ); + + *res.input_degree() = sk_in.n(); + *res.output_degree() = sk_out.n(); + } +} + +pub trait GLWESwitchingKeyEncryptPk<BE: Backend> { + fn glwe_switching_key_encrypt_pk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; +} + +impl<BE: Backend> GLWESwitchingKeyEncryptPk<BE> for Module<BE> { + fn glwe_switching_key_encrypt_pk_tmp_bytes<A>(&self, _infos: &A) -> usize + where + A: GGLWEInfos, + { + unimplemented!() + } +}
@@ -0,0 +1,147 @@
+use poulpy_hal::{ + api::{ + ModuleN, ScratchTakeBasic, SvpApplyDftToDft, VecZnxBigBytesOf, VecZnxBigNormalize, VecZnxDftApply, VecZnxDftBytesOf, + VecZnxIdftApplyTmpA, + }, + layouts::{Backend, DataMut, Module, Scratch}, + source::Source, +}; + +use crate::{ + GGLWEEncryptSk, GetDistribution, ScratchTakeCore, + layouts::{ + GGLWE, GGLWEInfos, GLWEInfos, GLWESecret, GLWESecretToRef, GLWETensorKey, GLWETensorKeyToMut, LWEInfos, Rank, + prepared::{GLWESecretPrepared, GLWESecretPreparedFactory}, + }, +}; + +impl GLWETensorKey<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWETensorKeyEncryptSk<BE>, + { + module.glwe_tensor_key_encrypt_sk_tmp_bytes(infos) + } +} + +impl<DataSelf: DataMut> GLWETensorKey<DataSelf> { + pub fn encrypt_sk<M, S, BE: Backend>( + &mut self, + module: &M, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + M: GLWETensorKeyEncryptSk<BE>, + S: GLWESecretToRef + GetDistribution + GLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_tensor_key_encrypt_sk(self, sk, source_xa, source_xe, scratch); + } +} + +pub trait GLWETensorKeyEncryptSk<BE: Backend> { + fn glwe_tensor_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn glwe_tensor_key_encrypt_sk<R, S>( + &self, + res: &mut R, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWETensorKeyToMut, + S: GLWESecretToRef + GetDistribution + GLWEInfos; +} + +impl<BE: Backend> GLWETensorKeyEncryptSk<BE> for Module<BE> +where + Self: ModuleN + + GGLWEEncryptSk<BE> + + VecZnxDftBytesOf + + VecZnxBigBytesOf + + GLWESecretPreparedFactory<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDft<BE> + + VecZnxIdftApplyTmpA<BE> + + VecZnxBigNormalize<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn glwe_tensor_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + GLWESecretPrepared::bytes_of(self, infos.rank_out()) + + self.bytes_of_vec_znx_dft(infos.rank_out().into(), 1) + + self.bytes_of_vec_znx_big(1, 1) + + self.bytes_of_vec_znx_dft(1, 1) + + GLWESecret::bytes_of(self.n().into(), Rank(1)) + + GGLWE::encrypt_sk_tmp_bytes(self, infos) + } + + fn glwe_tensor_key_encrypt_sk<R, S>( + &self, + res: &mut R, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GLWETensorKeyToMut, + S: GLWESecretToRef + GetDistribution + GLWEInfos, + { + let res: &mut GLWETensorKey<&mut [u8]> = &mut res.to_mut(); + + // let n: RingDegree = sk.n(); + let rank: Rank = res.rank_out(); + + let (mut sk_prepared, scratch_1) = scratch.take_glwe_secret_prepared(self, sk.rank()); + sk_prepared.prepare(self, sk); + + let sk: &GLWESecret<&[u8]> = &sk.to_ref(); + + assert_eq!(res.rank_out(), sk.rank()); + assert_eq!(res.n(), sk.n()); + + let (mut sk_dft, scratch_2) = scratch_1.take_vec_znx_dft(self, rank.into(), 1); + + (0..rank.into()).for_each(|i| { + self.vec_znx_dft_apply(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i); + }); + + let (mut sk_ij_big, scratch_3) = scratch_2.take_vec_znx_big(self, 1, 1); + let (mut sk_ij, scratch_4) = scratch_3.take_glwe_secret(self.n().into(), Rank(1)); + let (mut sk_ij_dft, scratch_5) = scratch_4.take_vec_znx_dft(self, 1, 1); + + (0..rank.into()).for_each(|i| { + (i..rank.into()).for_each(|j| { + self.svp_apply_dft_to_dft(&mut sk_ij_dft, 0, &sk_prepared.data, j, &sk_dft, i); + + self.vec_znx_idft_apply_tmpa(&mut sk_ij_big, 0, &mut sk_ij_dft, 0); + self.vec_znx_big_normalize( + res.base2k().into(), + &mut sk_ij.data.as_vec_znx_mut(), + 0, + res.base2k().into(), + &sk_ij_big, + 0, + scratch_5, + ); + + res.at_mut(i, j).encrypt_sk( + self, + &sk_ij.data, + &sk_prepared, + source_xa, + source_xe, + scratch_5, + ); + }); + }) + } +}
@@ -1,81 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphismInplace, VecZnxBigNormalize, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxView, ZnxViewMut, ZnxZero}, - source::Source, -}; - -use crate::{ - TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{GGLWEInfos, GGLWESwitchingKey, GLWESecret, GLWEToLWEKey, LWEInfos, LWESecret, Rank, prepared::GLWESecretPrepared}, -}; - -impl GLWEToLWEKey<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, - { - GLWESecretPrepared::alloc_bytes_with(module, infos.rank_in()) - + (GGLWESwitchingKey::encrypt_sk_scratch_space(module, infos) - | GLWESecret::alloc_bytes_with(infos.n(), infos.rank_in())) - } -} - -impl<D: DataMut> GLWEToLWEKey<D> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DLwe, DGlwe, B: Backend>( - &mut self, - module: &Module<B>, - sk_lwe: &LWESecret<DLwe>, - sk_glwe: &GLWESecret<DGlwe>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - DLwe: DataRef, - DGlwe: DataRef, - Module<B>: VecZnxAutomorphismInplace<B> - + VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + VecZnxSwitchRing - + SvpPPolAllocBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeGLWESecretPrepared<B>, - { - #[cfg(debug_assertions)] - { - assert!(sk_lwe.n().0 <= module.n() as u32); - } - - let (mut sk_lwe_as_glwe, scratch_1) = scratch.take_glwe_secret(sk_glwe.n(), Rank(1)); - sk_lwe_as_glwe.data.zero(); - sk_lwe_as_glwe.data.at_mut(0, 0)[..sk_lwe.n().into()].copy_from_slice(sk_lwe.data.at(0, 0)); - module.vec_znx_automorphism_inplace(-1, &mut sk_lwe_as_glwe.data.as_vec_znx_mut(), 0, scratch_1); - - self.0.encrypt_sk( - module, - sk_glwe, - &sk_lwe_as_glwe, - source_xa, - source_xe, - scratch_1, - ); - } -}
@@ -0,0 +1,120 @@
+use poulpy_hal::{ + api::{ModuleN, VecZnxAutomorphismInplace, VecZnxAutomorphismInplaceTmpBytes}, + layouts::{Backend, DataMut, Module, Scratch, ZnxView, ZnxViewMut, ZnxZero}, + source::Source, +}; + +use crate::{ + GGLWEEncryptSk, ScratchTakeCore, + layouts::{ + GGLWE, GGLWEInfos, GGLWEToMut, GLWESecret, GLWESecretToRef, GLWEToLWESwitchingKey, LWEInfos, LWESecret, LWESecretToRef, + Rank, + prepared::{GLWESecretPrepared, GLWESecretPreparedFactory}, + }, +}; + +impl GLWEToLWESwitchingKey<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWEToLWESwitchingKeyEncryptSk<BE>, + { + module.glwe_to_lwe_switching_key_encrypt_sk_tmp_bytes(infos) + } +} + +impl<D: DataMut> GLWEToLWESwitchingKey<D> { + pub fn encrypt_sk<M, S1, S2, BE: Backend>( + &mut self, + module: &M, + sk_lwe: &S1, + sk_glwe: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + M: GLWEToLWESwitchingKeyEncryptSk<BE>, + S1: LWESecretToRef, + S2: GLWESecretToRef, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_to_lwe_switching_key_encrypt_sk(self, sk_lwe, sk_glwe, source_xa, source_xe, scratch); + } +} + +pub trait GLWEToLWESwitchingKeyEncryptSk<BE: Backend> { + fn glwe_to_lwe_switching_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn glwe_to_lwe_switching_key_encrypt_sk<R, S1, S2>( + &self, + res: &mut R, + sk_lwe: &S1, + sk_glwe: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S1: LWESecretToRef, + S2: GLWESecretToRef, + R: GGLWEToMut; +} + +impl<BE: Backend> GLWEToLWESwitchingKeyEncryptSk<BE> for Module<BE> +where + Self: ModuleN + + GGLWEEncryptSk<BE> + + GLWESecretPreparedFactory<BE> + + VecZnxAutomorphismInplace<BE> + + VecZnxAutomorphismInplaceTmpBytes, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn glwe_to_lwe_switching_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + GLWESecretPrepared::bytes_of(self, infos.rank_in()) + + GGLWE::encrypt_sk_tmp_bytes(self, infos) + .max(GLWESecret::bytes_of(self.n().into(), infos.rank_in()) + self.vec_znx_automorphism_inplace_tmp_bytes()) + } + + fn glwe_to_lwe_switching_key_encrypt_sk<R, S1, S2>( + &self, + res: &mut R, + sk_lwe: &S1, + sk_glwe: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S1: LWESecretToRef, + S2: GLWESecretToRef, + R: GGLWEToMut, + { + let sk_lwe: &LWESecret<&[u8]> = &sk_lwe.to_ref(); + let sk_glwe: &GLWESecret<&[u8]> = &sk_glwe.to_ref(); + + assert!(sk_lwe.n().0 <= self.n() as u32); + + let (mut sk_lwe_as_glwe_prep, scratch_1) = scratch.take_glwe_secret_prepared(self, Rank(1)); + + { + let (mut sk_lwe_as_glwe, scratch_2) = scratch_1.take_glwe_secret(self.n().into(), sk_lwe_as_glwe_prep.rank()); + sk_lwe_as_glwe.dist = sk_lwe.dist; + sk_lwe_as_glwe.data.zero(); + sk_lwe_as_glwe.data.at_mut(0, 0)[..sk_lwe.n().into()].copy_from_slice(sk_lwe.data.at(0, 0)); + self.vec_znx_automorphism_inplace(-1, &mut sk_lwe_as_glwe.data.as_vec_znx_mut(), 0, scratch_2); + sk_lwe_as_glwe_prep.prepare(self, &sk_lwe_as_glwe); + } + + self.gglwe_encrypt_sk( + res, + &sk_glwe.data, + &sk_lwe_as_glwe_prep, + source_xa, + source_xe, + scratch_1, + ); + } +}
@@ -0,0 +1,100 @@
+use poulpy_hal::{ + api::{ScratchOwnedAlloc, ScratchOwnedBorrow, ZnAddNormal, ZnFillUniform, ZnNormalizeInplace}, + layouts::{Backend, DataMut, Module, ScratchOwned, Zn, ZnxView, ZnxViewMut}, + source::Source, +}; + +use crate::{ + encryption::{SIGMA, SIGMA_BOUND}, + layouts::{LWE, LWEInfos, LWEPlaintext, LWEPlaintextToRef, LWESecret, LWESecretToRef, LWEToMut}, +}; + +impl<DataSelf: DataMut> LWE<DataSelf> { + pub fn encrypt_sk<P, S, M, BE: Backend>(&mut self, module: &M, pt: &P, sk: &S, source_xa: &mut Source, source_xe: &mut Source) + where + P: LWEPlaintextToRef, + S: LWESecretToRef, + M: LWEEncryptSk<BE>, + { + module.lwe_encrypt_sk(self, pt, sk, source_xa, source_xe); + } +} + +pub trait LWEEncryptSk<BE: Backend> { + fn lwe_encrypt_sk<R, P, S>(&self, res: &mut R, pt: &P, sk: &S, source_xa: &mut Source, source_xe: &mut Source) + where + R: LWEToMut, + P: LWEPlaintextToRef, + S: LWESecretToRef; +} + +impl<BE: Backend> LWEEncryptSk<BE> for Module<BE> +where + Self: Sized + ZnFillUniform + ZnAddNormal + ZnNormalizeInplace<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, +{ + fn lwe_encrypt_sk<R, P, S>(&self, res: &mut R, pt: &P, sk: &S, source_xa: &mut Source, source_xe: &mut Source) + where + R: LWEToMut, + P: LWEPlaintextToRef, + S: LWESecretToRef, + { + let res: &mut LWE<&mut [u8]> = &mut res.to_mut(); + let pt: &LWEPlaintext<&[u8]> = &pt.to_ref(); + let sk: &LWESecret<&[u8]> = &sk.to_ref(); + + #[cfg(debug_assertions)] + { + assert_eq!(res.n(), sk.n()) + } + + let base2k: usize = res.base2k().into(); + let k: usize = res.k().into(); + + self.zn_fill_uniform((res.n() + 1).into(), base2k, &mut res.data, 0, source_xa); + + let mut tmp_znx: Zn<Vec<u8>> = Zn::alloc(1, 1, res.size()); + + let min_size = res.size().min(pt.size()); + + (0..min_size).for_each(|i| { + tmp_znx.at_mut(0, i)[0] = pt.data.at(0, i)[0] + - res.data.at(0, i)[1..] + .iter() + .zip(sk.data.at(0, 0)) + .map(|(x, y)| x * y) + .sum::<i64>(); + }); + + (min_size..res.size()).for_each(|i| { + tmp_znx.at_mut(0, i)[0] -= res.data.at(0, i)[1..] + .iter() + .zip(sk.data.at(0, 0)) + .map(|(x, y)| x * y) + .sum::<i64>(); + }); + + self.zn_add_normal( + 1, + base2k, + &mut res.data, + 0, + k, + source_xe, + SIGMA, + SIGMA_BOUND, + ); + + self.zn_normalize_inplace( + 1, + base2k, + &mut tmp_znx, + 0, + ScratchOwned::alloc(size_of::<i64>()).borrow(), + ); + + (0..res.size()).for_each(|i| { + res.data.at_mut(0, i)[0] = tmp_znx.at(0, i)[0]; + }); + } +}
@@ -1,81 +0,0 @@
-use poulpy_hal::{ - api::{ScratchOwnedAlloc, ScratchOwnedBorrow, ZnAddNormal, ZnFillUniform, ZnNormalizeInplace}, - layouts::{Backend, DataMut, DataRef, Module, ScratchOwned, Zn, ZnxView, ZnxViewMut}, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl}, - source::Source, -}; - -use crate::{ - encryption::{SIGMA, SIGMA_BOUND}, - layouts::{LWECiphertext, LWEInfos, LWEPlaintext, LWESecret}, -}; - -impl<DataSelf: DataMut> LWECiphertext<DataSelf> { - pub fn encrypt_sk<DataPt, DataSk, B>( - &mut self, - module: &Module<B>, - pt: &LWEPlaintext<DataPt>, - sk: &LWESecret<DataSk>, - source_xa: &mut Source, - source_xe: &mut Source, - ) where - DataPt: DataRef, - DataSk: DataRef, - Module<B>: ZnFillUniform + ZnAddNormal + ZnNormalizeInplace<B>, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, - { - #[cfg(debug_assertions)] - { - assert_eq!(self.n(), sk.n()) - } - - let base2k: usize = self.base2k().into(); - let k: usize = self.k().into(); - - module.zn_fill_uniform((self.n() + 1).into(), base2k, &mut self.data, 0, source_xa); - - let mut tmp_znx: Zn<Vec<u8>> = Zn::alloc(1, 1, self.size()); - - let min_size = self.size().min(pt.size()); - - (0..min_size).for_each(|i| { - tmp_znx.at_mut(0, i)[0] = pt.data.at(0, i)[0] - - self.data.at(0, i)[1..] - .iter() - .zip(sk.data.at(0, 0)) - .map(|(x, y)| x * y) - .sum::<i64>(); - }); - - (min_size..self.size()).for_each(|i| { - tmp_znx.at_mut(0, i)[0] -= self.data.at(0, i)[1..] - .iter() - .zip(sk.data.at(0, 0)) - .map(|(x, y)| x * y) - .sum::<i64>(); - }); - - module.zn_add_normal( - 1, - base2k, - &mut self.data, - 0, - k, - source_xe, - SIGMA, - SIGMA_BOUND, - ); - - module.zn_normalize_inplace( - 1, - base2k, - &mut tmp_znx, - 0, - ScratchOwned::alloc(size_of::<i64>()).borrow(), - ); - - (0..self.size()).for_each(|i| { - self.data.at_mut(0, i)[0] = tmp_znx.at(0, i)[0]; - }); - } -}
@@ -1,107 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphismInplace, VecZnxBigNormalize, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxView, ZnxViewMut}, - source::Source, -}; - -use crate::{ - TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{ - Degree, GGLWEInfos, GGLWESwitchingKey, GLWESecret, LWEInfos, LWESecret, LWESwitchingKey, Rank, - prepared::GLWESecretPrepared, - }, -}; - -impl LWESwitchingKey<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, - { - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for LWESwitchingKey" - ); - debug_assert_eq!( - infos.rank_in().0, - 1, - "rank_in > 1 is not supported for LWESwitchingKey" - ); - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is not supported for LWESwitchingKey" - ); - GLWESecret::alloc_bytes_with(Degree(module.n() as u32), Rank(1)) - + GLWESecretPrepared::alloc_bytes_with(module, Rank(1)) - + GGLWESwitchingKey::encrypt_sk_scratch_space(module, infos) - } -} - -impl<D: DataMut> LWESwitchingKey<D> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DIn, DOut, B: Backend>( - &mut self, - module: &Module<B>, - sk_lwe_in: &LWESecret<DIn>, - sk_lwe_out: &LWESecret<DOut>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - DIn: DataRef, - DOut: DataRef, - Module<B>: VecZnxAutomorphismInplace<B> - + VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + VecZnxSwitchRing - + SvpPPolAllocBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeGLWESecretPrepared<B>, - { - #[cfg(debug_assertions)] - { - assert!(sk_lwe_in.n().0 <= self.n().0); - assert!(sk_lwe_out.n().0 <= self.n().0); - assert!(self.n().0 <= module.n() as u32); - } - - let (mut sk_in_glwe, scratch_1) = scratch.take_glwe_secret(self.n(), Rank(1)); - let (mut sk_out_glwe, scratch_2) = scratch_1.take_glwe_secret(self.n(), Rank(1)); - - sk_out_glwe.data.at_mut(0, 0)[..sk_lwe_out.n().into()].copy_from_slice(sk_lwe_out.data.at(0, 0)); - sk_out_glwe.data.at_mut(0, 0)[sk_lwe_out.n().into()..].fill(0); - module.vec_znx_automorphism_inplace(-1, &mut sk_out_glwe.data.as_vec_znx_mut(), 0, scratch_2); - - sk_in_glwe.data.at_mut(0, 0)[..sk_lwe_in.n().into()].copy_from_slice(sk_lwe_in.data.at(0, 0)); - sk_in_glwe.data.at_mut(0, 0)[sk_lwe_in.n().into()..].fill(0); - module.vec_znx_automorphism_inplace(-1, &mut sk_in_glwe.data.as_vec_znx_mut(), 0, scratch_2); - - self.0.encrypt_sk( - module, - &sk_in_glwe, - &sk_out_glwe, - source_xa, - source_xe, - scratch_2, - ); - } -}
@@ -0,0 +1,137 @@
+use poulpy_hal::{ + api::{ModuleN, VecZnxAutomorphismInplace}, + layouts::{Backend, DataMut, Module, Scratch, ZnxView, ZnxViewMut}, + source::Source, +}; + +use crate::{ + ScratchTakeCore, + encryption::glwe_switching_key::GLWESwitchingKeyEncryptSk, + layouts::{ + GGLWEInfos, GGLWEToMut, GLWESecret, GLWESwitchingKey, GLWESwitchingKeyDegreesMut, LWEInfos, LWESecret, LWESecretToRef, + LWESwitchingKey, Rank, + prepared::{GLWESecretPrepared, GLWESecretPreparedFactory}, + }, +}; + +impl LWESwitchingKey<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: LWESwitchingKeyEncrypt<BE>, + { + module.lwe_switching_key_encrypt_sk_tmp_bytes(infos) + } +} + +impl<D: DataMut> LWESwitchingKey<D> { + pub fn encrypt_sk<S1, S2, M, BE: Backend>( + &mut self, + module: &M, + sk_lwe_in: &S1, + sk_lwe_out: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S1: LWESecretToRef, + S2: LWESecretToRef, + M: LWESwitchingKeyEncrypt<BE>, + { + module.lwe_switching_key_encrypt_sk(self, sk_lwe_in, sk_lwe_out, source_xa, source_xe, scratch); + } +} + +pub trait LWESwitchingKeyEncrypt<BE: Backend> { + fn lwe_switching_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn lwe_switching_key_encrypt_sk<R, S1, S2>( + &self, + res: &mut R, + sk_lwe_in: &S1, + sk_lwe_out: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWEToMut + GLWESwitchingKeyDegreesMut + GGLWEInfos, + S1: LWESecretToRef, + S2: LWESecretToRef; +} + +impl<BE: Backend> LWESwitchingKeyEncrypt<BE> for Module<BE> +where + Self: ModuleN + GLWESwitchingKeyEncryptSk<BE> + GLWESecretPreparedFactory<BE> + VecZnxAutomorphismInplace<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn lwe_switching_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for LWESwitchingKey" + ); + assert_eq!( + infos.rank_in().0, + 1, + "rank_in > 1 is not supported for LWESwitchingKey" + ); + assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is not supported for LWESwitchingKey" + ); + GLWESecret::bytes_of(self.n().into(), Rank(1)) + + GLWESecretPrepared::bytes_of(self, Rank(1)) + + GLWESwitchingKey::encrypt_sk_tmp_bytes(self, infos) + } + + #[allow(clippy::too_many_arguments)] + fn lwe_switching_key_encrypt_sk<R, S1, S2>( + &self, + res: &mut R, + sk_lwe_in: &S1, + sk_lwe_out: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + R: GGLWEToMut + GLWESwitchingKeyDegreesMut + GGLWEInfos, + S1: LWESecretToRef, + S2: LWESecretToRef, + { + let sk_lwe_in: &LWESecret<&[u8]> = &sk_lwe_in.to_ref(); + let sk_lwe_out: &LWESecret<&[u8]> = &sk_lwe_out.to_ref(); + + assert!(sk_lwe_in.n().0 <= res.n().0); + assert!(sk_lwe_out.n().0 <= res.n().0); + assert!(res.n() <= self.n() as u32); + + let (mut sk_glwe_in, scratch_1) = scratch.take_glwe_secret(self.n().into(), Rank(1)); + let (mut sk_glwe_out, scratch_2) = scratch_1.take_glwe_secret(self.n().into(), Rank(1)); + + sk_glwe_in.dist = sk_lwe_in.dist; + sk_glwe_out.dist = sk_lwe_out.dist; + + sk_glwe_out.data.at_mut(0, 0)[..sk_lwe_out.n().into()].copy_from_slice(sk_lwe_out.data.at(0, 0)); + sk_glwe_out.data.at_mut(0, 0)[sk_lwe_out.n().into()..].fill(0); + self.vec_znx_automorphism_inplace(-1, &mut sk_glwe_out.data.as_vec_znx_mut(), 0, scratch_2); + + sk_glwe_in.data.at_mut(0, 0)[..sk_lwe_in.n().into()].copy_from_slice(sk_lwe_in.data.at(0, 0)); + sk_glwe_in.data.at_mut(0, 0)[sk_lwe_in.n().into()..].fill(0); + self.vec_znx_automorphism_inplace(-1, &mut sk_glwe_in.data.as_vec_znx_mut(), 0, scratch_2); + + self.glwe_switching_key_encrypt_sk( + res, + &sk_glwe_in, + &sk_glwe_out, + source_xa, + source_xe, + scratch_2, + ); + } +}
@@ -1,87 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphismInplace, VecZnxBigNormalize, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxView, ZnxViewMut}, - source::Source, -}; - -use crate::{ - TakeGLWESecret, TakeGLWESecretPrepared, - layouts::{Degree, GGLWEInfos, GGLWESwitchingKey, GLWESecret, LWEInfos, LWESecret, LWEToGLWESwitchingKey, Rank}, -}; - -impl LWEToGLWESwitchingKey<Vec<u8>> { - pub fn encrypt_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: SvpPPolAllocBytes + VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes + VecZnxNormalizeTmpBytes, - { - debug_assert_eq!( - infos.rank_in(), - Rank(1), - "rank_in != 1 is not supported for LWEToGLWESwitchingKey" - ); - GGLWESwitchingKey::encrypt_sk_scratch_space(module, infos) - + GLWESecret::alloc_bytes_with(Degree(module.n() as u32), infos.rank_in()) - } -} - -impl<D: DataMut> LWEToGLWESwitchingKey<D> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DLwe, DGlwe, B: Backend>( - &mut self, - module: &Module<B>, - sk_lwe: &LWESecret<DLwe>, - sk_glwe: &GLWESecret<DGlwe>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - DLwe: DataRef, - DGlwe: DataRef, - Module<B>: VecZnxAutomorphismInplace<B> - + VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + VecZnxSwitchRing - + SvpPPolAllocBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeGLWESecretPrepared<B>, - { - #[cfg(debug_assertions)] - { - use crate::layouts::LWEInfos; - - assert!(sk_lwe.n().0 <= module.n() as u32); - } - - let (mut sk_lwe_as_glwe, scratch_1) = scratch.take_glwe_secret(sk_glwe.n(), Rank(1)); - sk_lwe_as_glwe.data.at_mut(0, 0)[..sk_lwe.n().into()].copy_from_slice(sk_lwe.data.at(0, 0)); - sk_lwe_as_glwe.data.at_mut(0, 0)[sk_lwe.n().into()..].fill(0); - module.vec_znx_automorphism_inplace(-1, &mut sk_lwe_as_glwe.data.as_vec_znx_mut(), 0, scratch_1); - - self.0.encrypt_sk( - module, - &sk_lwe_as_glwe, - sk_glwe, - source_xa, - source_xe, - scratch_1, - ); - } -}
@@ -0,0 +1,118 @@
+use poulpy_hal::{ + api::{ModuleN, VecZnxAutomorphismInplace, VecZnxAutomorphismInplaceTmpBytes}, + layouts::{Backend, DataMut, Module, Scratch, ZnxView, ZnxViewMut}, + source::Source, +}; + +use crate::{ + GGLWEEncryptSk, ScratchTakeCore, + layouts::{ + GGLWE, GGLWEInfos, GGLWEToMut, GLWESecret, GLWESecretPreparedFactory, GLWESecretPreparedToRef, LWEInfos, LWESecret, + LWESecretToRef, LWEToGLWESwitchingKey, Rank, + }, +}; + +impl LWEToGLWESwitchingKey<Vec<u8>> { + pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: LWEToGLWESwitchingKeyEncryptSk<BE>, + { + module.lwe_to_glwe_switching_key_encrypt_sk_tmp_bytes(infos) + } +} + +impl<D: DataMut> LWEToGLWESwitchingKey<D> { + pub fn encrypt_sk<S1, S2, M, BE: Backend>( + &mut self, + module: &M, + sk_lwe: &S1, + sk_glwe: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S1: LWESecretToRef, + S2: GLWESecretPreparedToRef<BE>, + M: LWEToGLWESwitchingKeyEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.lwe_to_glwe_switching_key_encrypt_sk(self, sk_lwe, sk_glwe, source_xa, source_xe, scratch); + } +} + +pub trait LWEToGLWESwitchingKeyEncryptSk<BE: Backend> { + fn lwe_to_glwe_switching_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos; + + fn lwe_to_glwe_switching_key_encrypt_sk<R, S1, S2>( + &self, + res: &mut R, + sk_lwe: &S1, + sk_glwe: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S1: LWESecretToRef, + S2: GLWESecretPreparedToRef<BE>, + R: GGLWEToMut; +} + +impl<BE: Backend> LWEToGLWESwitchingKeyEncryptSk<BE> for Module<BE> +where + Self: ModuleN + + GGLWEEncryptSk<BE> + + VecZnxAutomorphismInplace<BE> + + GLWESecretPreparedFactory<BE> + + VecZnxAutomorphismInplaceTmpBytes, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn lwe_to_glwe_switching_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + debug_assert_eq!( + infos.rank_in(), + Rank(1), + "rank_in != 1 is not supported for LWEToGLWESwitchingKey" + ); + GLWESecret::bytes_of(self.n().into(), infos.rank_in()) + + GGLWE::encrypt_sk_tmp_bytes(self, infos).max(self.vec_znx_automorphism_inplace_tmp_bytes()) + } + + fn lwe_to_glwe_switching_key_encrypt_sk<R, S1, S2>( + &self, + res: &mut R, + sk_lwe: &S1, + sk_glwe: &S2, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S1: LWESecretToRef, + S2: GLWESecretPreparedToRef<BE>, + R: GGLWEToMut, + { + let sk_lwe: &LWESecret<&[u8]> = &sk_lwe.to_ref(); + + assert!(sk_lwe.n().0 <= self.n() as u32); + + let (mut sk_lwe_as_glwe, scratch_1) = scratch.take_glwe_secret(self.n().into(), Rank(1)); + sk_lwe_as_glwe.dist = sk_lwe.dist; + + sk_lwe_as_glwe.data.at_mut(0, 0)[..sk_lwe.n().into()].copy_from_slice(sk_lwe.data.at(0, 0)); + sk_lwe_as_glwe.data.at_mut(0, 0)[sk_lwe.n().into()..].fill(0); + self.vec_znx_automorphism_inplace(-1, &mut sk_lwe_as_glwe.data.as_vec_znx_mut(), 0, scratch_1); + + self.gglwe_encrypt_sk( + res, + &sk_lwe_as_glwe.data, + sk_glwe, + source_xa, + source_xe, + scratch_1, + ); + } +}
@@ -1,17 +1,28 @@
mod compressed; -mod gglwe_atk; -mod gglwe_ct; -mod gglwe_ksk; -mod gglwe_tsk; -mod ggsw_ct; -mod glwe_ct; -mod glwe_pk; -mod glwe_to_lwe_ksk; -mod lwe_ct; -mod lwe_ksk; -mod lwe_to_glwe_ksk; +mod gglwe; +mod ggsw; +mod glwe; +mod glwe_automorphism_key; +mod glwe_public_key; +mod glwe_switching_key; +mod glwe_tensor_key; +mod glwe_to_lwe_switching_key; +mod lwe; +mod lwe_switching_key; +mod lwe_to_glwe_switching_key; -pub(crate) use glwe_ct::glwe_encrypt_sk_internal; +pub use compressed::*; +pub use gglwe::*; +pub use ggsw::*; +pub use glwe::*; +pub use glwe_automorphism_key::*; +pub use glwe_public_key::*; +pub use glwe_switching_key::*; +pub use glwe_tensor_key::*; +pub use glwe_to_lwe_switching_key::*; +pub use lwe::*; +pub use lwe_switching_key::*; +pub use lwe_to_glwe_switching_key::*; pub const SIGMA: f64 = 3.2; pub(crate) const SIGMA_BOUND: f64 = 6.0 * SIGMA;
@@ -0,0 +1,167 @@
+use poulpy_hal::layouts::{Backend, DataMut, Module, Scratch, ZnxZero}; + +use crate::{ + GLWEExternalProduct, ScratchTakeCore, + layouts::{ + GGLWE, GGLWEInfos, GGLWEToMut, GGLWEToRef, GGSWInfos, GGSWPrepared, GLWEAutomorphismKey, GLWEInfos, GLWESwitchingKey, + prepared::GGSWPreparedToRef, + }, +}; + +impl GLWEAutomorphismKey<Vec<u8>> { + pub fn external_product_tmp_bytes<R, A, B, M, BE: Backend>( + &self, + module: &M, + res_infos: &R, + a_infos: &A, + b_infos: &B, + ) -> usize + where + R: GGLWEInfos, + A: GGLWEInfos, + B: GGSWInfos, + M: GGLWEExternalProduct<BE>, + { + module.gglwe_external_product_tmp_bytes(res_infos, a_infos, b_infos) + } +} + +impl<DataSelf: DataMut> GLWEAutomorphismKey<DataSelf> { + pub fn external_product<A, B, M, BE: Backend>(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + M: GGLWEExternalProduct<BE>, + A: GGLWEToRef, + B: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.gglwe_external_product(self, a, b, scratch); + } + + pub fn external_product_inplace<A, M, BE: Backend>(&mut self, module: &M, a: &A, scratch: &mut Scratch<BE>) + where + M: GGLWEExternalProduct<BE>, + A: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.gglwe_external_product_inplace(self, a, scratch); + } +} + +pub trait GGLWEExternalProduct<BE: Backend> +where + Self: GLWEExternalProduct<BE>, +{ + fn gglwe_external_product_tmp_bytes<R, A, B>(&self, res_infos: &R, a_infos: &A, b_infos: &B) -> usize + where + R: GGLWEInfos, + A: GGLWEInfos, + B: GGSWInfos, + { + self.glwe_external_product_tmp_bytes(res_infos, a_infos, b_infos) + } + + fn gglwe_external_product<R, A, B>(&self, res: &mut R, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + R: GGLWEToMut, + A: GGLWEToRef, + B: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GGLWE<&[u8]> = &a.to_ref(); + let b: &GGSWPrepared<&[u8], BE> = &b.to_ref(); + + assert_eq!( + res.rank_in(), + a.rank_in(), + "res input rank_in: {} != a input rank_in: {}", + res.rank_in(), + a.rank_in() + ); + assert_eq!( + a.rank_out(), + b.rank(), + "a output rank_out: {} != b rank: {}", + a.rank_out(), + b.rank() + ); + assert_eq!( + res.rank_out(), + b.rank(), + "res output rank_out: {} != b rank: {}", + res.rank_out(), + b.rank() + ); + + for row in 0..res.dnum().into() { + for col in 0..res.rank_in().into() { + self.glwe_external_product(&mut res.at_mut(row, col), &a.at(row, col), b, scratch); + } + } + + for row in res.dnum().min(a.dnum()).into()..res.dnum().into() { + for col in 0..res.rank_in().into() { + res.at_mut(row, col).data_mut().zero(); + } + } + } + + fn gglwe_external_product_inplace<R, A>(&self, res: &mut R, a: &A, scratch: &mut Scratch<BE>) + where + R: GGLWEToMut, + A: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GGSWPrepared<&[u8], BE> = &a.to_ref(); + + assert_eq!( + res.rank_out(), + a.rank(), + "res output rank: {} != a rank: {}", + res.rank_out(), + a.rank() + ); + + for row in 0..res.dnum().into() { + for col in 0..res.rank_in().into() { + self.glwe_external_product_inplace(&mut res.at_mut(row, col), a, scratch); + } + } + } +} + +impl<BE: Backend> GGLWEExternalProduct<BE> for Module<BE> where Self: GLWEExternalProduct<BE> {} + +impl GLWESwitchingKey<Vec<u8>> { + pub fn external_product_tmp_bytes<R, A, B, M, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, b_infos: &B) -> usize + where + R: GGLWEInfos, + A: GGLWEInfos, + B: GGSWInfos, + M: GGLWEExternalProduct<BE>, + { + module.gglwe_external_product_tmp_bytes(res_infos, a_infos, b_infos) + } +} + +impl<DataSelf: DataMut> GLWESwitchingKey<DataSelf> { + pub fn external_product<A, B, M, BE: Backend>(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + M: GGLWEExternalProduct<BE>, + A: GGLWEToRef, + B: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.gglwe_external_product(self, a, b, scratch); + } + + pub fn external_product_inplace<A, M, BE: Backend>(&mut self, module: &M, a: &A, scratch: &mut Scratch<BE>) + where + M: GGLWEExternalProduct<BE>, + A: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.gglwe_external_product_inplace(self, a, scratch); + } +}
@@ -1,83 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch}, -}; - -use crate::layouts::{GGLWEAutomorphismKey, GGLWEInfos, GGLWESwitchingKey, GGSWInfos, prepared::GGSWCiphertextPrepared}; - -impl GGLWEAutomorphismKey<Vec<u8>> { - pub fn external_product_scratch_space<B: Backend, OUT, IN, GGSW>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - ggsw_infos: &GGSW, - ) -> usize - where - OUT: GGLWEInfos, - IN: GGLWEInfos, - GGSW: GGSWInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, - { - GGLWESwitchingKey::external_product_scratch_space(module, out_infos, in_infos, ggsw_infos) - } - - pub fn external_product_inplace_scratch_space<B: Backend, OUT, GGSW>( - module: &Module<B>, - out_infos: &OUT, - ggsw_infos: &GGSW, - ) -> usize - where - OUT: GGLWEInfos, - GGSW: GGSWInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, - { - GGLWESwitchingKey::external_product_inplace_scratch_space(module, out_infos, ggsw_infos) - } -} - -impl<DataSelf: DataMut> GGLWEAutomorphismKey<DataSelf> { - pub fn external_product<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GGLWEAutomorphismKey<DataLhs>, - rhs: &GGSWCiphertextPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - self.key.external_product(module, &lhs.key, rhs, scratch); - } - - pub fn external_product_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGSWCiphertextPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - self.key.external_product_inplace(module, rhs, scratch); - } -}
@@ -1,144 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, -}; - -use crate::layouts::{GGLWEInfos, GGLWESwitchingKey, GGSWInfos, GLWECiphertext, prepared::GGSWCiphertextPrepared}; - -impl GGLWESwitchingKey<Vec<u8>> { - pub fn external_product_scratch_space<B: Backend, OUT, IN, GGSW>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - ggsw_infos: &GGSW, - ) -> usize - where - OUT: GGLWEInfos, - IN: GGLWEInfos, - GGSW: GGSWInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, - { - GLWECiphertext::external_product_scratch_space( - module, - &out_infos.glwe_layout(), - &in_infos.glwe_layout(), - ggsw_infos, - ) - } - - pub fn external_product_inplace_scratch_space<B: Backend, OUT, GGSW>( - module: &Module<B>, - out_infos: &OUT, - ggsw_infos: &GGSW, - ) -> usize - where - OUT: GGLWEInfos, - GGSW: GGSWInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, - { - GLWECiphertext::external_product_inplace_scratch_space(module, &out_infos.glwe_layout(), ggsw_infos) - } -} - -impl<DataSelf: DataMut> GGLWESwitchingKey<DataSelf> { - pub fn external_product<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GGLWESwitchingKey<DataLhs>, - rhs: &GGSWCiphertextPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - use crate::layouts::GLWEInfos; - - assert_eq!( - self.rank_in(), - lhs.rank_in(), - "ksk_out input rank: {} != ksk_in input rank: {}", - self.rank_in(), - lhs.rank_in() - ); - assert_eq!( - lhs.rank_out(), - rhs.rank(), - "ksk_in output rank: {} != ggsw rank: {}", - self.rank_out(), - rhs.rank() - ); - assert_eq!( - self.rank_out(), - rhs.rank(), - "ksk_out output rank: {} != ggsw rank: {}", - self.rank_out(), - rhs.rank() - ); - } - - (0..self.rank_in().into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_j| { - self.at_mut(row_j, col_i) - .external_product(module, &lhs.at(row_j, col_i), rhs, scratch); - }); - }); - - (self.dnum().min(lhs.dnum()).into()..self.dnum().into()).for_each(|row_i| { - (0..self.rank_in().into()).for_each(|col_j| { - self.at_mut(row_i, col_j).data.zero(); - }); - }); - } - - pub fn external_product_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGSWCiphertextPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - use crate::layouts::GLWEInfos; - - assert_eq!( - self.rank_out(), - rhs.rank(), - "ksk_out output rank: {} != ggsw rank: {}", - self.rank_out(), - rhs.rank() - ); - } - - (0..self.rank_in().into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_j| { - self.at_mut(row_j, col_i) - .external_product_inplace(module, rhs, scratch); - }); - }); - } -}
@@ -0,0 +1,130 @@
+use poulpy_hal::{ + api::ScratchAvailable, + layouts::{Backend, DataMut, Module, Scratch, ZnxZero}, +}; + +use crate::{ + GLWEExternalProduct, ScratchTakeCore, + layouts::{ + GGSW, GGSWInfos, GGSWToMut, GGSWToRef, GLWEInfos, LWEInfos, + prepared::{GGSWPrepared, GGSWPreparedToRef}, + }, +}; + +pub trait GGSWExternalProduct<BE: Backend> +where + Self: GLWEExternalProduct<BE>, +{ + fn ggsw_external_product_tmp_bytes<R, A, B>(&self, res_infos: &R, a_infos: &A, b_infos: &B) -> usize + where + R: GGSWInfos, + A: GGSWInfos, + B: GGSWInfos, + { + self.glwe_external_product_tmp_bytes(res_infos, a_infos, b_infos) + } + + fn ggsw_external_product<R, A, B>(&self, res: &mut R, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + R: GGSWToMut, + A: GGSWToRef, + B: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + let a: &GGSW<&[u8]> = &a.to_ref(); + let b: &GGSWPrepared<&[u8], BE> = &b.to_ref(); + + assert_eq!( + res.rank(), + a.rank(), + "res rank: {} != a rank: {}", + res.rank(), + a.rank() + ); + assert_eq!( + res.rank(), + b.rank(), + "res rank: {} != b rank: {}", + res.rank(), + b.rank() + ); + + assert!(scratch.available() >= self.ggsw_external_product_tmp_bytes(res, a, b)); + + let min_dnum: usize = res.dnum().min(a.dnum()).into(); + + for row in 0..min_dnum { + for col in 0..(res.rank() + 1).into() { + self.glwe_external_product(&mut res.at_mut(row, col), &a.at(row, col), b, scratch); + } + } + + for row in min_dnum..res.dnum().into() { + for col in 0..(res.rank() + 1).into() { + res.at_mut(row, col).data.zero(); + } + } + } + + fn ggsw_external_product_inplace<R, A>(&self, res: &mut R, a: &A, scratch: &mut Scratch<BE>) + where + R: GGSWToMut, + A: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + let a: &GGSWPrepared<&[u8], BE> = &a.to_ref(); + + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.n(), self.n() as u32); + assert_eq!( + res.rank(), + a.rank(), + "res rank: {} != a rank: {}", + res.rank(), + a.rank() + ); + + for row in 0..res.dnum().into() { + for col in 0..(res.rank() + 1).into() { + self.glwe_external_product_inplace(&mut res.at_mut(row, col), a, scratch); + } + } + } +} + +impl<BE: Backend> GGSWExternalProduct<BE> for Module<BE> where Self: GLWEExternalProduct<BE> {} + +impl GGSW<Vec<u8>> { + pub fn external_product_tmp_bytes<R, A, B, M, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, b_infos: &B) -> usize + where + R: GGSWInfos, + A: GGSWInfos, + B: GGSWInfos, + M: GGSWExternalProduct<BE>, + { + module.ggsw_external_product_tmp_bytes(res_infos, a_infos, b_infos) + } +} + +impl<DataSelf: DataMut> GGSW<DataSelf> { + pub fn external_product<A, B, M, BE: Backend>(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + M: GGSWExternalProduct<BE>, + A: GGSWToRef, + B: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.ggsw_external_product(self, a, b, scratch); + } + + pub fn external_product_inplace<A, M, BE: Backend>(&mut self, module: &M, a: &A, scratch: &mut Scratch<BE>) + where + M: GGSWExternalProduct<BE>, + A: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.ggsw_external_product_inplace(self, a, scratch); + } +}
@@ -1,143 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, -}; - -use crate::layouts::{GGSWCiphertext, GGSWInfos, GLWECiphertext, GLWEInfos, prepared::GGSWCiphertextPrepared}; - -impl GGSWCiphertext<Vec<u8>> { - #[allow(clippy::too_many_arguments)] - pub fn external_product_scratch_space<B: Backend, OUT, IN, GGSW>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - apply_infos: &GGSW, - ) -> usize - where - OUT: GGSWInfos, - IN: GGSWInfos, - GGSW: GGSWInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, - { - GLWECiphertext::external_product_scratch_space( - module, - &out_infos.glwe_layout(), - &in_infos.glwe_layout(), - apply_infos, - ) - } - - pub fn external_product_inplace_scratch_space<B: Backend, OUT, GGSW>( - module: &Module<B>, - out_infos: &OUT, - apply_infos: &GGSW, - ) -> usize - where - OUT: GGSWInfos, - GGSW: GGSWInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, - { - GLWECiphertext::external_product_inplace_scratch_space(module, &out_infos.glwe_layout(), apply_infos) - } -} - -impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> { - pub fn external_product<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GGSWCiphertext<DataLhs>, - rhs: &GGSWCiphertextPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - use crate::layouts::LWEInfos; - - assert_eq!(lhs.n(), self.n()); - assert_eq!(rhs.n(), self.n()); - - assert_eq!( - self.rank(), - lhs.rank(), - "ggsw_out rank: {} != ggsw_in rank: {}", - self.rank(), - lhs.rank() - ); - assert_eq!( - self.rank(), - rhs.rank(), - "ggsw_in rank: {} != ggsw_apply rank: {}", - self.rank(), - rhs.rank() - ); - - assert!(scratch.available() >= GGSWCiphertext::external_product_scratch_space(module, self, lhs, rhs)) - } - - let min_dnum: usize = self.dnum().min(lhs.dnum()).into(); - - (0..(self.rank() + 1).into()).for_each(|col_i| { - (0..min_dnum).for_each(|row_j| { - self.at_mut(row_j, col_i) - .external_product(module, &lhs.at(row_j, col_i), rhs, scratch); - }); - (min_dnum..self.dnum().into()).for_each(|row_i| { - self.at_mut(row_i, col_i).data.zero(); - }); - }); - } - - pub fn external_product_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGSWCiphertextPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - use crate::layouts::LWEInfos; - - assert_eq!(rhs.n(), self.n()); - assert_eq!( - self.rank(), - rhs.rank(), - "ggsw_out rank: {} != ggsw_apply: {}", - self.rank(), - rhs.rank() - ); - } - - (0..(self.rank() + 1).into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_j| { - self.at_mut(row_j, col_i) - .external_product_inplace(module, rhs, scratch); - }); - }); - } -}
@@ -1,102 +1,57 @@
use poulpy_hal::{ api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, + ModuleN, ScratchTakeBasic, VecZnxBigNormalize, VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalize, + VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, }, - layouts::{Backend, DataMut, DataRef, DataViewMut, Module, Scratch, VecZnx, VecZnxBig}, + layouts::{Backend, DataMut, DataViewMut, Module, Scratch, VecZnx, VecZnxBig}, }; use crate::{ - GLWEExternalProduct, GLWEExternalProductInplace, + ScratchTakeCore, layouts::{ - GGSWInfos, GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, GLWEInfos, LWEInfos, - prepared::{GGSWCiphertextPrepared, GGSWCiphertextPreparedToRef}, + GGSWInfos, GLWE, GLWEInfos, GLWEToMut, GLWEToRef, LWEInfos, + prepared::{GGSWPrepared, GGSWPreparedToRef}, }, }; -impl GLWECiphertext<Vec<u8>> { - #[allow(clippy::too_many_arguments)] - pub fn external_product_scratch_space<B: Backend, OUT, IN, GGSW>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - apply_infos: &GGSW, - ) -> usize +impl GLWE<Vec<u8>> { + pub fn external_product_tmp_bytes<R, A, B, M, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, b_infos: &B) -> usize where - OUT: GLWEInfos, - IN: GLWEInfos, - GGSW: GGSWInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, + R: GLWEInfos, + A: GLWEInfos, + B: GGSWInfos, + M: GLWEExternalProduct<BE>, { - let in_size: usize = in_infos - .k() - .div_ceil(apply_infos.base2k()) - .div_ceil(apply_infos.dsize().into()) as usize; - let out_size: usize = out_infos.size(); - let ggsw_size: usize = apply_infos.size(); - let res_dft: usize = module.vec_znx_dft_alloc_bytes((apply_infos.rank() + 1).into(), ggsw_size); - let a_dft: usize = module.vec_znx_dft_alloc_bytes((apply_infos.rank() + 1).into(), in_size); - let vmp: usize = module.vmp_apply_dft_to_dft_tmp_bytes( - out_size, - in_size, - in_size, // rows - (apply_infos.rank() + 1).into(), // cols in - (apply_infos.rank() + 1).into(), // cols out - ggsw_size, - ); - let normalize_big: usize = module.vec_znx_normalize_tmp_bytes(); - - if in_infos.base2k() == apply_infos.base2k() { - res_dft + a_dft + (vmp | normalize_big) - } else { - let normalize_conv: usize = VecZnx::alloc_bytes(module.n(), (apply_infos.rank() + 1).into(), in_size); - res_dft + ((a_dft + normalize_conv + (module.vec_znx_normalize_tmp_bytes() | vmp)) | normalize_big) - } - } - - pub fn external_product_inplace_scratch_space<B: Backend, OUT, GGSW>( - module: &Module<B>, - out_infos: &OUT, - apply_infos: &GGSW, - ) -> usize - where - OUT: GLWEInfos, - GGSW: GGSWInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, - { - Self::external_product_scratch_space(module, out_infos, out_infos, apply_infos) + module.glwe_external_product_tmp_bytes(res_infos, a_infos, b_infos) } } -impl<DataSelf: DataMut> GLWECiphertext<DataSelf> { - pub fn external_product<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &GGSWCiphertextPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: GLWEExternalProduct<B>, +impl<DataSelf: DataMut> GLWE<DataSelf> { + pub fn external_product<A, B, M, BE: Backend>(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + A: GLWEToRef, + B: GGSWPreparedToRef<BE>, + M: GLWEExternalProduct<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { - module.external_product(self, lhs, rhs, scratch); + module.glwe_external_product(self, a, b, scratch); } - pub fn external_product_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGSWCiphertextPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: GLWEExternalProductInplace<B>, + pub fn external_product_inplace<A, M, BE: Backend>(&mut self, module: &M, a: &A, scratch: &mut Scratch<BE>) + where + A: GGSWPreparedToRef<BE>, + M: GLWEExternalProduct<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { - module.external_product_inplace(self, rhs, scratch); + module.glwe_external_product_inplace(self, a, scratch); } } -impl<BE: Backend> GLWEExternalProductInplace<BE> for Module<BE> +pub trait GLWEExternalProduct<BE: Backend> where - Module<BE>: VecZnxDftAllocBytes + Self: Sized + + ModuleN + + VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes + VecZnxDftApply<BE>@@ -105,15 +60,47 @@ + VmpApplyDftToDftAdd<BE>
+ VecZnxIdftApplyConsume<BE> + VecZnxBigNormalize<BE> + VecZnxNormalize<BE>, - Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx, { - fn external_product_inplace<R, D>(&self, res: &mut R, ggsw: &D, scratch: &mut Scratch<BE>) + fn glwe_external_product_tmp_bytes<R, A, B>(&self, res_infos: &R, a_infos: &A, b_infos: &B) -> usize where - R: GLWECiphertextToMut, - D: GGSWCiphertextPreparedToRef<BE>, + R: GLWEInfos, + A: GLWEInfos, + B: GGSWInfos, { - let res: &mut GLWECiphertext<&mut [u8]> = &mut res.to_mut(); - let rhs: &GGSWCiphertextPrepared<&[u8], BE> = &ggsw.to_ref(); + let in_size: usize = a_infos + .k() + .div_ceil(b_infos.base2k()) + .div_ceil(b_infos.dsize().into()) as usize; + let out_size: usize = res_infos.size(); + let ggsw_size: usize = b_infos.size(); + let res_dft: usize = self.bytes_of_vec_znx_dft((b_infos.rank() + 1).into(), ggsw_size); + let a_dft: usize = self.bytes_of_vec_znx_dft((b_infos.rank() + 1).into(), in_size); + let vmp: usize = self.vmp_apply_dft_to_dft_tmp_bytes( + out_size, + in_size, + in_size, // rows + (b_infos.rank() + 1).into(), // cols in + (b_infos.rank() + 1).into(), // cols out + ggsw_size, + ); + let normalize_big: usize = self.vec_znx_normalize_tmp_bytes(); + + if a_infos.base2k() == b_infos.base2k() { + res_dft + a_dft + (vmp | normalize_big) + } else { + let normalize_conv: usize = VecZnx::bytes_of(self.n(), (b_infos.rank() + 1).into(), in_size); + res_dft + ((a_dft + normalize_conv + (self.vec_znx_normalize_tmp_bytes() | vmp)) | normalize_big) + } + } + + fn glwe_external_product_inplace<R, D>(&self, res: &mut R, a: &D, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + D: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let rhs: &GGSWPrepared<&[u8], BE> = &a.to_ref(); let basek_in: usize = res.base2k().into(); let basek_ggsw: usize = rhs.base2k().into();@@ -124,15 +111,15 @@ use poulpy_hal::api::ScratchAvailable;
assert_eq!(rhs.rank(), res.rank()); assert_eq!(rhs.n(), res.n()); - assert!(scratch.available() >= GLWECiphertext::external_product_inplace_scratch_space(self, res, rhs)); + assert!(scratch.available() >= self.glwe_external_product_tmp_bytes(res, res, rhs)); } let cols: usize = (rhs.rank() + 1).into(); let dsize: usize = rhs.dsize().into(); let a_size: usize = (res.size() * basek_in).div_ceil(basek_ggsw); - let (mut res_dft, scratch_1) = scratch.take_vec_znx_dft(res.n().into(), cols, rhs.size()); // Todo optimise - let (mut a_dft, scratch_2) = scratch_1.take_vec_znx_dft(res.n().into(), cols, a_size.div_ceil(dsize)); + let (mut res_dft, scratch_1) = scratch.take_vec_znx_dft(self, cols, rhs.size()); // Todo optimise + let (mut a_dft, scratch_2) = scratch_1.take_vec_znx_dft(self, cols, a_size.div_ceil(dsize)); a_dft.data_mut().fill(0); if basek_in == basek_ggsw {@@ -213,31 +200,18 @@ scratch_1,
); } } -} -impl<BE: Backend> GLWEExternalProduct<BE> for Module<BE> -where - Module<BE>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<BE> - + VmpApplyDftToDft<BE> - + VmpApplyDftToDftAdd<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxBigNormalize<BE> - + VecZnxNormalize<BE>, - Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx, -{ - fn external_product<R, A, D>(&self, res: &mut R, lhs: &A, rhs: &D, scratch: &mut Scratch<BE>) + fn glwe_external_product<R, A, D>(&self, res: &mut R, lhs: &A, rhs: &D, scratch: &mut Scratch<BE>) where - R: GLWECiphertextToMut, - A: GLWECiphertextToRef, - D: GGSWCiphertextPreparedToRef<BE>, + R: GLWEToMut, + A: GLWEToRef, + D: GGSWPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { - let res: &mut GLWECiphertext<&mut [u8]> = &mut res.to_mut(); - let lhs: &GLWECiphertext<&[u8]> = &lhs.to_ref(); + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let lhs: &GLWE<&[u8]> = &lhs.to_ref(); - let rhs: &GGSWCiphertextPrepared<&[u8], BE> = &rhs.to_ref(); + let rhs: &GGSWPrepared<&[u8], BE> = &rhs.to_ref(); let basek_in: usize = lhs.base2k().into(); let basek_ggsw: usize = rhs.base2k().into();@@ -251,7 +225,7 @@ assert_eq!(rhs.rank(), lhs.rank());
assert_eq!(rhs.rank(), res.rank()); assert_eq!(rhs.n(), res.n()); assert_eq!(lhs.n(), res.n()); - assert!(scratch.available() >= GLWECiphertext::external_product_scratch_space(self, res, lhs, rhs)); + assert!(scratch.available() >= self.glwe_external_product_tmp_bytes(res, lhs, rhs)); } let cols: usize = (rhs.rank() + 1).into();@@ -259,8 +233,8 @@ let dsize: usize = rhs.dsize().into();
let a_size: usize = (lhs.size() * basek_in).div_ceil(basek_ggsw); - let (mut res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n(), cols, rhs.size()); // Todo optimise - let (mut a_dft, scratch_2) = scratch_1.take_vec_znx_dft(self.n(), cols, a_size.div_ceil(dsize)); + let (mut res_dft, scratch_1) = scratch.take_vec_znx_dft(self, cols, rhs.size()); // Todo optimise + let (mut a_dft, scratch_2) = scratch_1.take_vec_znx_dft(self, cols, a_size.div_ceil(dsize)); a_dft.data_mut().fill(0); if basek_in == basek_ggsw {@@ -342,3 +316,20 @@ );
}); } } + +impl<BE: Backend> GLWEExternalProduct<BE> for Module<BE> where + Self: ModuleN + + VecZnxDftBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxNormalizeTmpBytes + + VecZnxDftApply<BE> + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalize<BE> + + VecZnxDftBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxNormalizeTmpBytes +{ +}
@@ -1,23 +1,7 @@
-use poulpy_hal::layouts::{Backend, Scratch}; - -use crate::layouts::{GLWECiphertextToMut, GLWECiphertextToRef, prepared::GGSWCiphertextPreparedToRef}; - -mod gglwe_atk; -mod gglwe_ksk; -mod ggsw_ct; -mod glwe_ct; - -pub trait GLWEExternalProduct<BE: Backend> { - fn external_product<R, A, D>(&self, res: &mut R, a: &A, ggsw: &D, scratch: &mut Scratch<BE>) - where - R: GLWECiphertextToMut, - A: GLWECiphertextToRef, - D: GGSWCiphertextPreparedToRef<BE>; -} +mod gglwe; +mod ggsw; +mod glwe; -pub trait GLWEExternalProductInplace<BE: Backend> { - fn external_product_inplace<R, D>(&self, res: &mut R, ggsw: &D, scratch: &mut Scratch<BE>) - where - R: GLWECiphertextToMut, - D: GGSWCiphertextPreparedToRef<BE>; -} +pub use gglwe::*; +pub use ggsw::*; +pub use glwe::*;
@@ -1,19 +1,14 @@
use std::collections::HashMap; use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAutomorphismInplace, VecZnxBigAddSmallInplace, - VecZnxBigAutomorphismInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNegateInplace, - VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRshInplace, - VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch}, + api::ModuleLogN, + layouts::{Backend, GaloisElement, Module, Scratch}, }; use crate::{ - GLWEOperations, TakeGLWECt, - layouts::{GGLWEInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GGLWEAutomorphismKeyPrepared}, + GLWEAdd, GLWEAutomorphism, GLWECopy, GLWENormalize, GLWERotate, GLWEShift, GLWESub, ScratchTakeCore, + glwe_trace::GLWETrace, + layouts::{GGLWEInfos, GGLWEPreparedToRef, GLWE, GLWEInfos, GLWEToMut, GLWEToRef, GetGaloisElement, LWEInfos}, }; /// [GLWEPacker] enables only the fly GLWE packing@@ -29,7 +24,7 @@
/// [Accumulator] stores intermediate packing result. /// There are Log(N) such accumulators in a [GLWEPacker]. struct Accumulator { - data: GLWECiphertext<Vec<u8>>, + data: GLWE<Vec<u8>>, value: bool, // Implicit flag for zero ciphertext control: bool, // Can be combined with incoming value }@@ -48,7 +43,7 @@ where
A: GLWEInfos, { Self { - data: GLWECiphertext::alloc(infos), + data: GLWE::alloc_from_infos(infos), value: false, control: false, }@@ -60,20 +55,19 @@ /// Instantiates a new [GLWEPacker].
/// /// # Arguments /// - /// * `module`: static backend FFT tables. /// * `log_batch`: packs coefficients which are multiples of X^{N/2^log_batch}. /// i.e. with `log_batch=0` only the constant coefficient is packed /// and N GLWE ciphertext can be packed. With `log_batch=2` all coefficients /// which are multiples of X^{N/4} are packed. Meaning that N/4 ciphertexts /// can be packed. - pub fn new<A>(infos: &A, log_batch: usize) -> Self + pub fn alloc<A>(infos: &A, log_batch: usize) -> Self where A: GLWEInfos, { let mut accumulators: Vec<Accumulator> = Vec::<Accumulator>::new(); let log_n: usize = infos.n().log2(); (0..log_n - log_batch).for_each(|_| accumulators.push(Accumulator::alloc(infos))); - Self { + GLWEPacker { accumulators, log_batch, counter: 0,@@ -90,17 +84,23 @@ self.counter = 0;
} /// Number of scratch space bytes required to call [Self::add]. - pub fn scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize + pub fn tmp_bytes<R, K, M, BE: Backend>(module: &M, res_infos: &R, key_infos: &K) -> usize where - OUT: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + R: GLWEInfos, + K: GGLWEInfos, + M: GLWEPacking<BE>, { - pack_core_scratch_space(module, out_infos, key_infos) + GLWE::bytes_of_from_infos(res_infos) + + module + .glwe_rsh_tmp_byte() + .max(module.glwe_automorphism_tmp_bytes(res_infos, res_infos, key_infos)) } - pub fn galois_elements<B: Backend>(module: &Module<B>) -> Vec<i64> { - GLWECiphertext::trace_galois_elements(module) + pub fn galois_elements<M, BE: Backend>(module: &M) -> Vec<i64> + where + M: GLWETrace<BE>, + { + module.glwe_trace_galois_elements() } /// Adds a GLWE ciphertext to the [GLWEPacker].@@ -111,38 +111,13 @@ /// * `res`: space to append fully packed ciphertext. Only when the number
/// of packed ciphertexts reaches N/2^log_batch is a result written. /// * `a`: ciphertext to pack. Can optionally give None to pack a 0 ciphertext. /// * `auto_keys`: a [HashMap] containing the [AutomorphismKeyExec]s. - /// * `scratch`: scratch space of size at least [Self::scratch_space]. - pub fn add<DataA: DataRef, DataAK: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - a: Option<&GLWECiphertext<DataA>>, - auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<DataAK, B>>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxCopy - + VecZnxRotateInplace<B> - + VecZnxSub - + VecZnxNegateInplace - + VecZnxRshInplace<B> - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxSubInplace - + VecZnxRotate - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + /// * `scratch`: scratch space of size at least [Self::tmp_bytes]. + pub fn add<A, K, M, BE: Backend>(&mut self, module: &M, a: Option<&A>, auto_keys: &HashMap<i64, K>, scratch: &mut Scratch<BE>) + where + A: GLWEToRef + GLWEInfos, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + M: GLWEPacking<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { assert!( (self.counter as u32) < self.accumulators[0].data.n(),@@ -162,14 +137,15 @@ self.counter += 1 << self.log_batch;
} /// Flush result to`res`. - pub fn flush<Data: DataMut, B: Backend>(&mut self, module: &Module<B>, res: &mut GLWECiphertext<Data>) + pub fn flush<R, M, BE: Backend>(&mut self, module: &M, res: &mut R) where - Module<B>: VecZnxCopy, + R: GLWEToMut, + M: GLWEPacking<BE>, { assert!(self.counter as u32 == self.accumulators[0].data.n()); // Copy result GLWE into res GLWE - res.copy( - module, + module.glwe_copy( + res, &self.accumulators[module.log_n() - self.log_batch - 1].data, );@@ -177,47 +153,96 @@ self.reset();
} } -fn pack_core_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize +impl<BE: Backend> GLWEPacking<BE> for Module<BE> where + Self: GLWEAutomorphism<BE> + + GaloisElement + + ModuleLogN + + GLWERotate<BE> + + GLWESub + + GLWEShift<BE> + + GLWEAdd + + GLWENormalize<BE> + + GLWECopy +{ +} + +pub trait GLWEPacking<BE: Backend> where - OUT: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + Self: GLWEAutomorphism<BE> + + GaloisElement + + ModuleLogN + + GLWERotate<BE> + + GLWESub + + GLWEShift<BE> + + GLWEAdd + + GLWENormalize<BE> + + GLWECopy, { - combine_scratch_space(module, out_infos, key_infos) + /// Packs [x_0: GLWE(m_0), x_1: GLWE(m_1), ..., x_i: GLWE(m_i)] + /// to [0: GLWE(m_0 * X^x_0 + m_1 * X^x_1 + ... + m_i * X^x_i)] + fn glwe_pack<R, K>( + &self, + cts: &mut HashMap<usize, &mut R>, + log_gap_out: usize, + keys: &HashMap<i64, K>, + scratch: &mut Scratch<BE>, + ) where + R: GLWEToMut + GLWEToRef + GLWEInfos, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + #[cfg(debug_assertions)] + { + assert!(*cts.keys().max().unwrap() < self.n()) + } + + let log_n: usize = self.log_n(); + + for i in 0..(log_n - log_gap_out) { + let t: usize = (1 << log_n).min(1 << (log_n - 1 - i)); + + let key: &K = if i == 0 { + keys.get(&-1).unwrap() + } else { + keys.get(&self.galois_element(1 << (i - 1))).unwrap() + }; + + for j in 0..t { + let mut a: Option<&mut R> = cts.remove(&j); + let mut b: Option<&mut R> = cts.remove(&(j + t)); + + pack_internal(self, &mut a, &mut b, i, key, scratch); + + if let Some(a) = a { + cts.insert(j, a); + } else if let Some(b) = b { + cts.insert(j, b); + } + } + } + } } -fn pack_core<D: DataRef, DataAK: DataRef, B: Backend>( - module: &Module<B>, - a: Option<&GLWECiphertext<D>>, +fn pack_core<A, K, M, BE: Backend>( + module: &M, + a: Option<&A>, accumulators: &mut [Accumulator], i: usize, - auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<DataAK, B>>, - scratch: &mut Scratch<B>, + auto_keys: &HashMap<i64, K>, + scratch: &mut Scratch<BE>, ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxCopy - + VecZnxRotateInplace<B> - + VecZnxSub - + VecZnxNegateInplace - + VecZnxRshInplace<B> - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxSubInplace - + VecZnxRotate - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + A: GLWEToRef + GLWEInfos, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + M: ModuleLogN + + GLWEAutomorphism<BE> + + GaloisElement + + GLWERotate<BE> + + GLWESub + + GLWEShift<BE> + + GLWEAdd + + GLWENormalize<BE> + + GLWECopy, + Scratch<BE>: ScratchTakeCore<BE>, { let log_n: usize = module.log_n();@@ -234,7 +259,7 @@ let acc_mut_ref: &mut Accumulator = &mut acc_prev[0]; // from split_at_mut
// No previous value -> copies and sets flags accordingly if let Some(a_ref) = a { - acc_mut_ref.data.copy(module, a_ref); + module.glwe_copy(&mut acc_mut_ref.data, a_ref); acc_mut_ref.value = true } else { acc_mut_ref.value = false@@ -258,7 +283,7 @@ );
} else { pack_core( module, - None::<&GLWECiphertext<Vec<u8>>>, + None::<&GLWE<Vec<u8>>>, acc_next, i + 1, auto_keys,@@ -268,53 +293,23 @@ }
} } -fn combine_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize -where - OUT: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, -{ - GLWECiphertext::alloc_bytes(out_infos) - + (GLWECiphertext::rsh_scratch_space(module.n()) - | GLWECiphertext::automorphism_inplace_scratch_space(module, out_infos, key_infos)) -} - /// [combine] merges two ciphertexts together. -fn combine<D: DataRef, DataAK: DataRef, B: Backend>( - module: &Module<B>, +fn combine<B, M, K, BE: Backend>( + module: &M, acc: &mut Accumulator, - b: Option<&GLWECiphertext<D>>, + b: Option<&B>, i: usize, - auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<DataAK, B>>, - scratch: &mut Scratch<B>, + auto_keys: &HashMap<i64, K>, + scratch: &mut Scratch<BE>, ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxCopy - + VecZnxRotateInplace<B> - + VecZnxSub - + VecZnxNegateInplace - + VecZnxRshInplace<B> - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxSubInplace - + VecZnxRotate - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeGLWECt, + B: GLWEToRef + GLWEInfos, + M: GLWEAutomorphism<BE> + GaloisElement + GLWERotate<BE> + GLWESub + GLWEShift<BE> + GLWEAdd + GLWENormalize<BE>, + B: GLWEToRef + GLWEInfos, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { let log_n: usize = acc.data.n().log2(); - let a: &mut GLWECiphertext<Vec<u8>> = &mut acc.data; + let a: &mut GLWE<Vec<u8>> = &mut acc.data; let gal_el: i64 = if i == 0 { -1@@ -336,53 +331,53 @@ // either mapped to garbage or twice their value which vanishes I(X)
// since 2*(I(X) * Q/2) = I(X) * Q = 0 mod Q. if acc.value { if let Some(b) = b { - let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(a); + let (mut tmp_b, scratch_1) = scratch.take_glwe(a); // a = a * X^-t - a.rotate_inplace(module, -t, scratch_1); + module.glwe_rotate_inplace(-t, a, scratch_1); // tmp_b = a * X^-t - b - tmp_b.sub(module, a, b); - tmp_b.rsh(module, 1, scratch_1); + module.glwe_sub(&mut tmp_b, a, b); + module.glwe_rsh(1, &mut tmp_b, scratch_1); // a = a * X^-t + b - a.add_inplace(module, b); - a.rsh(module, 1, scratch_1); + module.glwe_add_inplace(a, b); + module.glwe_rsh(1, a, scratch_1); - tmp_b.normalize_inplace(module, scratch_1); + module.glwe_normalize_inplace(&mut tmp_b, scratch_1); // tmp_b = phi(a * X^-t - b) - if let Some(key) = auto_keys.get(&gal_el) { - tmp_b.automorphism_inplace(module, key, scratch_1); + if let Some(auto_key) = auto_keys.get(&gal_el) { + module.glwe_automorphism_inplace(&mut tmp_b, auto_key, scratch_1); } else { panic!("auto_key[{gal_el}] not found"); } // a = a * X^-t + b - phi(a * X^-t - b) - a.sub_inplace_ab(module, &tmp_b); - a.normalize_inplace(module, scratch_1); + module.glwe_sub_inplace(a, &tmp_b); + module.glwe_normalize_inplace(a, scratch_1); // a = a + b * X^t - phi(a * X^-t - b) * X^t // = a + b * X^t - phi(a * X^-t - b) * - phi(X^t) // = a + b * X^t + phi(a - b * X^t) - a.rotate_inplace(module, t, scratch_1); + module.glwe_rotate_inplace(t, a, scratch_1); } else { - a.rsh(module, 1, scratch); + module.glwe_rsh(1, a, scratch); // a = a + phi(a) - if let Some(key) = auto_keys.get(&gal_el) { - a.automorphism_add_inplace(module, key, scratch); + if let Some(auto_key) = auto_keys.get(&gal_el) { + module.glwe_automorphism_add_inplace(a, auto_key, scratch); } else { panic!("auto_key[{gal_el}] not found"); } } } else if let Some(b) = b { - let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(a); - tmp_b.rotate(module, 1 << (log_n - i - 1), b); - tmp_b.rsh(module, 1, scratch_1); + let (mut tmp_b, scratch_1) = scratch.take_glwe(a); + module.glwe_rotate(t, &mut tmp_b, b); + module.glwe_rsh(1, &mut tmp_b, scratch_1); // a = (b* X^t - phi(b* X^t)) - if let Some(key) = auto_keys.get(&gal_el) { - a.automorphism_sub_negate(module, &tmp_b, key, scratch_1); + if let Some(auto_key) = auto_keys.get(&gal_el) { + module.glwe_automorphism_sub_negate(a, &tmp_b, auto_key, scratch_1); } else { panic!("auto_key[{gal_el}] not found"); }@@ -391,110 +386,20 @@ acc.value = true;
} } -/// Packs [x_0: GLWE(m_0), x_1: GLWE(m_1), ..., x_i: GLWE(m_i)] -/// to [0: GLWE(m_0 * X^x_0 + m_1 * X^x_1 + ... + m_i * X^x_i)] -pub fn glwe_packing<D: DataMut, ATK, B: Backend>( - module: &Module<B>, - cts: &mut HashMap<usize, &mut GLWECiphertext<D>>, - log_gap_out: usize, - auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<ATK, B>>, - scratch: &mut Scratch<B>, -) where - ATK: DataRef, - Module<B>: VecZnxRotateInplace<B> - + VecZnxNormalizeInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxSub - + VecZnxAddInplace - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxSubInplace - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxRotate - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnx + TakeVecZnxDft<B> + ScratchAvailable, -{ - #[cfg(debug_assertions)] - { - assert!(*cts.keys().max().unwrap() < module.n()) - } - - let log_n: usize = module.log_n(); - - (0..log_n - log_gap_out).for_each(|i| { - let t: usize = (1 << log_n).min(1 << (log_n - 1 - i)); - - let auto_key: &GGLWEAutomorphismKeyPrepared<ATK, B> = if i == 0 { - auto_keys.get(&-1).unwrap() - } else { - auto_keys.get(&module.galois_element(1 << (i - 1))).unwrap() - }; - - (0..t).for_each(|j| { - let mut a: Option<&mut GLWECiphertext<D>> = cts.remove(&j); - let mut b: Option<&mut GLWECiphertext<D>> = cts.remove(&(j + t)); - - pack_internal(module, &mut a, &mut b, i, auto_key, scratch); - - if let Some(a) = a { - cts.insert(j, a); - } else if let Some(b) = b { - cts.insert(j, b); - } - }); - }); -} - #[allow(clippy::too_many_arguments)] -fn pack_internal<A: DataMut, D: DataMut, DataAK: DataRef, B: Backend>( - module: &Module<B>, - a: &mut Option<&mut GLWECiphertext<A>>, - b: &mut Option<&mut GLWECiphertext<D>>, +fn pack_internal<M, A, B, K, BE: Backend>( + module: &M, + a: &mut Option<&mut A>, + b: &mut Option<&mut B>, i: usize, - auto_key: &GGLWEAutomorphismKeyPrepared<DataAK, B>, - scratch: &mut Scratch<B>, + auto_key: &K, + scratch: &mut Scratch<BE>, ) where - Module<B>: VecZnxRotateInplace<B> - + VecZnxNormalizeInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxSub - + VecZnxAddInplace - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxSubInplace - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxRotate - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnx + TakeVecZnxDft<B> + ScratchAvailable, + M: GLWEAutomorphism<BE> + GLWERotate<BE> + GLWESub + GLWEShift<BE> + GLWEAdd + GLWENormalize<BE>, + A: GLWEToMut + GLWEToRef + GLWEInfos, + B: GLWEToMut + GLWEToRef + GLWEInfos, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { // Goal is to evaluate: a = a + b*X^t + phi(a - b*X^t)) // We also use the identity: AUTO(a * X^t, g) = -X^t * AUTO(a, g)@@ -510,45 +415,45 @@ if let Some(a) = a.as_deref_mut() {
let t: i64 = 1 << (a.n().log2() - i - 1); if let Some(b) = b.as_deref_mut() { - let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(a); + let (mut tmp_b, scratch_1) = scratch.take_glwe(a); // a = a * X^-t - a.rotate_inplace(module, -t, scratch_1); + module.glwe_rotate_inplace(-t, a, scratch_1); // tmp_b = a * X^-t - b - tmp_b.sub(module, a, b); - tmp_b.rsh(module, 1, scratch_1); + module.glwe_sub(&mut tmp_b, a, b); + module.glwe_rsh(1, &mut tmp_b, scratch_1); // a = a * X^-t + b - a.add_inplace(module, b); - a.rsh(module, 1, scratch_1); + module.glwe_add_inplace(a, b); + module.glwe_rsh(1, a, scratch_1); - tmp_b.normalize_inplace(module, scratch_1); + module.glwe_normalize_inplace(&mut tmp_b, scratch_1); // tmp_b = phi(a * X^-t - b) - tmp_b.automorphism_inplace(module, auto_key, scratch_1); + module.glwe_automorphism_inplace(&mut tmp_b, auto_key, scratch_1); // a = a * X^-t + b - phi(a * X^-t - b) - a.sub_inplace_ab(module, &tmp_b); - a.normalize_inplace(module, scratch_1); + module.glwe_sub_inplace(a, &tmp_b); + module.glwe_normalize_inplace(a, scratch_1); // a = a + b * X^t - phi(a * X^-t - b) * X^t // = a + b * X^t - phi(a * X^-t - b) * - phi(X^t) // = a + b * X^t + phi(a - b * X^t) - a.rotate_inplace(module, t, scratch_1); + module.glwe_rotate_inplace(t, a, scratch_1); } else { - a.rsh(module, 1, scratch); + module.glwe_rsh(1, a, scratch); // a = a + phi(a) - a.automorphism_add_inplace(module, auto_key, scratch); + module.glwe_automorphism_add_inplace(a, auto_key, scratch); } } else if let Some(b) = b.as_deref_mut() { let t: i64 = 1 << (b.n().log2() - i - 1); - let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(b); - tmp_b.rotate(module, t, b); - tmp_b.rsh(module, 1, scratch_1); + let (mut tmp_b, scratch_1) = scratch.take_glwe(b); + module.glwe_rotate(t, &mut tmp_b, b); + module.glwe_rsh(1, &mut tmp_b, scratch_1); // a = (b* X^t - phi(b* X^t)) - b.automorphism_sub_negate(module, &tmp_b, auto_key, scratch_1); + module.glwe_automorphism_sub_negate(b, &tmp_b, auto_key, scratch_1); } }
@@ -1,181 +1,189 @@
use std::collections::HashMap; use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigAddSmallInplace, VecZnxBigAutomorphismInplace, VecZnxBigNormalize, - VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalize, - VecZnxNormalizeTmpBytes, VecZnxRshInplace, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnx}, + api::ModuleLogN, + layouts::{Backend, DataMut, GaloisElement, Module, Scratch, VecZnx, galois_element}, }; use crate::{ - TakeGLWECt, + GLWEAutomorphism, GLWECopy, GLWEShift, ScratchTakeCore, layouts::{ - Base2K, GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWEInfos, prepared::GGLWEAutomorphismKeyPrepared, + Base2K, GGLWEInfos, GGLWEPreparedToRef, GLWE, GLWEInfos, GLWELayout, GLWEToMut, GLWEToRef, GetGaloisElement, LWEInfos, }, - operations::GLWEOperations, }; -impl GLWECiphertext<Vec<u8>> { - pub fn trace_galois_elements<B: Backend>(module: &Module<B>) -> Vec<i64> { - let mut gal_els: Vec<i64> = Vec::new(); - (0..module.log_n()).for_each(|i| { - if i == 0 { - gal_els.push(-1); - } else { - gal_els.push(module.galois_element(1 << (i - 1))); - } - }); - gal_els - } - - pub fn trace_scratch_space<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - key_infos: &KEY, - ) -> usize +impl GLWE<Vec<u8>> { + pub fn trace_galois_elements<M, BE: Backend>(module: &M) -> Vec<i64> where - OUT: GLWEInfos, - IN: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + M: GLWETrace<BE>, { - let trace: usize = Self::automorphism_inplace_scratch_space(module, out_infos, key_infos); - if in_infos.base2k() != key_infos.base2k() { - let glwe_conv: usize = VecZnx::alloc_bytes( - module.n(), - (key_infos.rank_out() + 1).into(), - out_infos.k().min(in_infos.k()).div_ceil(key_infos.base2k()) as usize, - ) + module.vec_znx_normalize_tmp_bytes(); - return glwe_conv + trace; - } - - trace + module.glwe_trace_galois_elements() } - pub fn trace_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize + pub fn trace_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, key_infos: &K) -> usize where - OUT: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + R: GLWEInfos, + A: GLWEInfos, + K: GGLWEInfos, + M: GLWETrace<BE>, { - Self::trace_scratch_space(module, out_infos, out_infos, key_infos) + module.glwe_automorphism_tmp_bytes(res_infos, a_infos, key_infos) } } -impl<DataSelf: DataMut> GLWECiphertext<DataSelf> { - pub fn trace<DataLhs: DataRef, DataAK: DataRef, B: Backend>( +impl<D: DataMut> GLWE<D> { + pub fn trace<A, K, M, BE: Backend>( &mut self, - module: &Module<B>, + module: &M, start: usize, end: usize, - lhs: &GLWECiphertext<DataLhs>, - auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<DataAK, B>>, - scratch: &mut Scratch<B>, + a: &A, + keys: &HashMap<i64, K>, + scratch: &mut Scratch<BE>, ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxCopy - + VecZnxNormalizeTmpBytes - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + A: GLWEToRef, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: GLWETrace<BE>, { - self.copy(module, lhs); - self.trace_inplace(module, start, end, auto_keys, scratch); + module.glwe_trace(self, start, end, a, keys, scratch); } - pub fn trace_inplace<DataAK: DataRef, B: Backend>( + pub fn trace_inplace<K, M, BE: Backend>( &mut self, - module: &Module<B>, + module: &M, start: usize, end: usize, - auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<DataAK, B>>, - scratch: &mut Scratch<B>, + keys: &HashMap<i64, K>, + scratch: &mut Scratch<BE>, ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: GLWETrace<BE>, { - let basek_ksk: Base2K = auto_keys - .get(auto_keys.keys().next().unwrap()) - .unwrap() - .base2k(); + module.glwe_trace_inplace(self, start, end, keys, scratch); + } +} + +impl<BE: Backend> GLWETrace<BE> for Module<BE> where + Self: ModuleLogN + GaloisElement + GLWEAutomorphism<BE> + GLWEShift<BE> + GLWECopy +{ +} + +#[inline(always)] +pub fn trace_galois_elements(log_n: usize, cyclotomic_order: i64) -> Vec<i64> { + (0..log_n) + .map(|i| { + if i == 0 { + -1 + } else { + galois_element(1 << (i - 1), cyclotomic_order) + } + }) + .collect() +} + +pub trait GLWETrace<BE: Backend> +where + Self: ModuleLogN + GaloisElement + GLWEAutomorphism<BE> + GLWEShift<BE> + GLWECopy, +{ + fn glwe_trace_galois_elements(&self) -> Vec<i64> { + trace_galois_elements(self.log_n(), self.cyclotomic_order()) + } + + fn glwe_trace_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize + where + R: GLWEInfos, + A: GLWEInfos, + K: GGLWEInfos, + { + let trace: usize = self.glwe_automorphism_tmp_bytes(res_infos, a_infos, key_infos); + if a_infos.base2k() != key_infos.base2k() { + let glwe_conv: usize = VecZnx::bytes_of( + self.n(), + (key_infos.rank_out() + 1).into(), + res_infos.k().min(a_infos.k()).div_ceil(key_infos.base2k()) as usize, + ) + self.vec_znx_normalize_tmp_bytes(); + return glwe_conv + trace; + } + + trace + } + + fn glwe_trace<R, A, K>(&self, res: &mut R, start: usize, end: usize, a: &A, keys: &HashMap<i64, K>, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + A: GLWEToRef, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + self.glwe_copy(res, a); + self.glwe_trace_inplace(res, start, end, keys, scratch); + } + + fn glwe_trace_inplace<R, K>(&self, res: &mut R, start: usize, end: usize, keys: &HashMap<i64, K>, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + + let basek_ksk: Base2K = keys.get(keys.keys().next().unwrap()).unwrap().base2k(); #[cfg(debug_assertions)] { - assert_eq!(self.n(), module.n() as u32); + assert_eq!(res.n(), self.n() as u32); assert!(start < end); - assert!(end <= module.log_n()); - for key in auto_keys.values() { - assert_eq!(key.n(), module.n() as u32); + assert!(end <= self.log_n()); + for key in keys.values() { + assert_eq!(key.n(), self.n() as u32); assert_eq!(key.base2k(), basek_ksk); - assert_eq!(key.rank_in(), self.rank()); - assert_eq!(key.rank_out(), self.rank()); + assert_eq!(key.rank_in(), res.rank()); + assert_eq!(key.rank_out(), res.rank()); } } - if self.base2k() != basek_ksk { - let (mut self_conv, scratch_1) = scratch.take_glwe_ct(&GLWECiphertextLayout { - n: module.n().into(), + if res.base2k() != basek_ksk { + let (mut self_conv, scratch_1) = scratch.take_glwe(&GLWELayout { + n: self.n().into(), base2k: basek_ksk, - k: self.k(), - rank: self.rank(), + k: res.k(), + rank: res.rank(), }); - for j in 0..(self.rank() + 1).into() { - module.vec_znx_normalize( + for j in 0..(res.rank() + 1).into() { + self.vec_znx_normalize( basek_ksk.into(), &mut self_conv.data, j, basek_ksk.into(), - &self.data, + res.data(), j, scratch_1, ); } for i in start..end { - self_conv.rsh(module, 1, scratch_1); + self.glwe_rsh(1, &mut self_conv, scratch_1); let p: i64 = if i == 0 { -1 } else { - module.galois_element(1 << (i - 1)) + self.galois_element(1 << (i - 1)) }; - if let Some(key) = auto_keys.get(&p) { - self_conv.automorphism_add_inplace(module, key, scratch_1); + if let Some(key) = keys.get(&p) { + self.glwe_automorphism_add_inplace(&mut self_conv, key, scratch_1); } else { - panic!("auto_keys[{p}] is empty") + panic!("keys[{p}] is empty") } } - for j in 0..(self.rank() + 1).into() { - module.vec_znx_normalize( - self.base2k().into(), - &mut self.data, + for j in 0..(res.rank() + 1).into() { + self.vec_znx_normalize( + res.base2k().into(), + res.data_mut(), j, basek_ksk.into(), &self_conv.data,@@ -184,19 +192,21 @@ scratch_1,
); } } else { + // println!("res: {}", res); + for i in start..end { - self.rsh(module, 1, scratch); + self.glwe_rsh(1, res, scratch); let p: i64 = if i == 0 { -1 } else { - module.galois_element(1 << (i - 1)) + self.galois_element(1 << (i - 1)) }; - if let Some(key) = auto_keys.get(&p) { - self.automorphism_add_inplace(module, key, scratch); + if let Some(key) = keys.get(&p) { + self.glwe_automorphism_add_inplace(res, key, scratch); } else { - panic!("auto_keys[{p}] is empty") + panic!("keys[{p}] is empty") } } }
@@ -0,0 +1,199 @@
+use poulpy_hal::layouts::{Backend, DataMut, Module, Scratch}; + +use crate::{ + ScratchTakeCore, + keyswitching::GLWEKeyswitch, + layouts::{GGLWE, GGLWEInfos, GGLWEPreparedToRef, GGLWEToMut, GGLWEToRef, GLWEAutomorphismKey, GLWESwitchingKey}, +}; + +impl GLWEAutomorphismKey<Vec<u8>> { + pub fn keyswitch_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, key_infos: &K) -> usize + where + R: GGLWEInfos, + A: GGLWEInfos, + K: GGLWEInfos, + M: GGLWEKeyswitch<BE>, + { + module.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos) + } +} + +impl<DataSelf: DataMut> GLWEAutomorphismKey<DataSelf> { + pub fn keyswitch<A, B, M, BE: Backend>(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + A: GGLWEToRef + GGLWEToRef, + B: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: GGLWEKeyswitch<BE>, + { + module.gglwe_keyswitch(self, a, b, scratch); + } + + pub fn keyswitch_inplace<A, M, BE: Backend>(&mut self, module: &M, a: &A, scratch: &mut Scratch<BE>) + where + A: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: GGLWEKeyswitch<BE>, + { + module.gglwe_keyswitch_inplace(self, a, scratch); + } +} + +impl GLWESwitchingKey<Vec<u8>> { + pub fn keyswitch_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, key_infos: &K) -> usize + where + R: GGLWEInfos, + A: GGLWEInfos, + K: GGLWEInfos, + M: GGLWEKeyswitch<BE>, + { + module.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos) + } +} + +impl<DataSelf: DataMut> GLWESwitchingKey<DataSelf> { + pub fn keyswitch<A, B, M, BE: Backend>(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + A: GGLWEToRef, + B: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: GGLWEKeyswitch<BE>, + { + module.gglwe_keyswitch(self, a, b, scratch); + } + + pub fn keyswitch_inplace<A, M, BE: Backend>(&mut self, module: &M, a: &A, scratch: &mut Scratch<BE>) + where + A: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: GGLWEKeyswitch<BE>, + { + module.gglwe_keyswitch_inplace(self, a, scratch); + } +} + +impl GGLWE<Vec<u8>> { + pub fn keyswitch_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, key_infos: &K) -> usize + where + R: GGLWEInfos, + A: GGLWEInfos, + K: GGLWEInfos, + M: GGLWEKeyswitch<BE>, + { + module.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos) + } +} + +impl<DataSelf: DataMut> GGLWE<DataSelf> { + pub fn keyswitch<A, B, M, BE: Backend>(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + A: GGLWEToRef, + B: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: GGLWEKeyswitch<BE>, + { + module.gglwe_keyswitch(self, a, b, scratch); + } + + pub fn keyswitch_inplace<A, M, BE: Backend>(&mut self, module: &M, a: &A, scratch: &mut Scratch<BE>) + where + A: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: GGLWEKeyswitch<BE>, + { + module.gglwe_keyswitch_inplace(self, a, scratch); + } +} + +impl<BE: Backend> GGLWEKeyswitch<BE> for Module<BE> where Self: GLWEKeyswitch<BE> {} + +pub trait GGLWEKeyswitch<BE: Backend> +where + Self: GLWEKeyswitch<BE>, +{ + fn gglwe_keyswitch_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize + where + R: GGLWEInfos, + A: GGLWEInfos, + K: GGLWEInfos, + { + self.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos) + } + + fn gglwe_keyswitch<R, A, B>(&self, res: &mut R, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + R: GGLWEToMut, + A: GGLWEToRef, + B: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GGLWE<&[u8]> = &a.to_ref(); + + assert_eq!( + res.rank_in(), + a.rank_in(), + "res input rank: {} != a input rank: {}", + res.rank_in(), + a.rank_in() + ); + assert_eq!( + a.rank_out(), + b.rank_in(), + "res output rank: {} != b input rank: {}", + a.rank_out(), + b.rank_in() + ); + assert_eq!( + res.rank_out(), + b.rank_out(), + "res output rank: {} != b output rank: {}", + res.rank_out(), + b.rank_out() + ); + assert!( + res.dnum() <= a.dnum(), + "res.dnum()={} > a.dnum()={}", + res.dnum(), + a.dnum() + ); + assert_eq!( + res.dsize(), + a.dsize(), + "res dsize: {} != a dsize: {}", + res.dsize(), + a.dsize() + ); + + for row in 0..res.dnum().into() { + for col in 0..res.rank_in().into() { + self.glwe_keyswitch(&mut res.at_mut(row, col), &a.at(row, col), b, scratch); + } + } + } + + fn gglwe_keyswitch_inplace<R, A>(&self, res: &mut R, a: &A, scratch: &mut Scratch<BE>) + where + R: GGLWEToMut, + A: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); + + assert_eq!( + res.rank_out(), + a.rank_out(), + "res output rank: {} != a output rank: {}", + res.rank_out(), + a.rank_out() + ); + + for row in 0..res.dnum().into() { + for col in 0..res.rank_in().into() { + self.glwe_keyswitch_inplace(&mut res.at_mut(row, col), a, scratch); + } + } + } +} + +impl<DataSelf: DataMut> GLWESwitchingKey<DataSelf> {}
@@ -1,224 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, - VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, -}; - -use crate::layouts::{ - GGLWEAutomorphismKey, GGLWEInfos, GGLWESwitchingKey, GLWECiphertext, GLWEInfos, - prepared::{GGLWEAutomorphismKeyPrepared, GGLWESwitchingKeyPrepared}, -}; - -impl GGLWEAutomorphismKey<Vec<u8>> { - pub fn keyswitch_scratch_space<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - key_infos: &KEY, - ) -> usize - where - OUT: GGLWEInfos, - IN: GGLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, - { - GGLWESwitchingKey::keyswitch_scratch_space(module, out_infos, in_infos, key_infos) - } - - pub fn keyswitch_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize - where - OUT: GGLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, - { - GGLWESwitchingKey::keyswitch_inplace_scratch_space(module, out_infos, key_infos) - } -} - -impl<DataSelf: DataMut> GGLWEAutomorphismKey<DataSelf> { - pub fn keyswitch<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GGLWEAutomorphismKey<DataLhs>, - rhs: &GGLWESwitchingKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - self.key.keyswitch(module, &lhs.key, rhs, scratch); - } - - pub fn keyswitch_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGLWEAutomorphismKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - self.key.keyswitch_inplace(module, &rhs.key, scratch); - } -} - -impl GGLWESwitchingKey<Vec<u8>> { - pub fn keyswitch_scratch_space<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - key_apply: &KEY, - ) -> usize - where - OUT: GGLWEInfos, - IN: GGLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, - { - GLWECiphertext::keyswitch_scratch_space(module, out_infos, in_infos, key_apply) - } - - pub fn keyswitch_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_apply: &KEY) -> usize - where - OUT: GGLWEInfos + GLWEInfos, - KEY: GGLWEInfos + GLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, - { - GLWECiphertext::keyswitch_inplace_scratch_space(module, out_infos, key_apply) - } -} - -impl<DataSelf: DataMut> GGLWESwitchingKey<DataSelf> { - pub fn keyswitch<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GGLWESwitchingKey<DataLhs>, - rhs: &GGLWESwitchingKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - assert_eq!( - self.rank_in(), - lhs.rank_in(), - "ksk_out input rank: {} != ksk_in input rank: {}", - self.rank_in(), - lhs.rank_in() - ); - assert_eq!( - lhs.rank_out(), - rhs.rank_in(), - "ksk_in output rank: {} != ksk_apply input rank: {}", - self.rank_out(), - rhs.rank_in() - ); - assert_eq!( - self.rank_out(), - rhs.rank_out(), - "ksk_out output rank: {} != ksk_apply output rank: {}", - self.rank_out(), - rhs.rank_out() - ); - assert!( - self.dnum() <= lhs.dnum(), - "self.dnum()={} > lhs.dnum()={}", - self.dnum(), - lhs.dnum() - ); - assert_eq!( - self.dsize(), - lhs.dsize(), - "ksk_out dsize: {} != ksk_in dsize: {}", - self.dsize(), - lhs.dsize() - ) - } - - (0..self.rank_in().into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_j| { - self.at_mut(row_j, col_i) - .keyswitch(module, &lhs.at(row_j, col_i), rhs, scratch); - }); - }); - - (self.dnum().min(lhs.dnum()).into()..self.dnum().into()).for_each(|row_i| { - (0..self.rank_in().into()).for_each(|col_j| { - self.at_mut(row_i, col_j).data.zero(); - }); - }); - } - - pub fn keyswitch_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGLWESwitchingKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - assert_eq!( - self.rank_out(), - rhs.rank_out(), - "ksk_out output rank: {} != ksk_apply output rank: {}", - self.rank_out(), - rhs.rank_out() - ); - } - - (0..self.rank_in().into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_j| { - self.at_mut(row_j, col_i) - .keyswitch_inplace(module, rhs, scratch) - }); - }); - } -}
@@ -0,0 +1,129 @@
+use poulpy_hal::layouts::{Backend, DataMut, Module, Scratch, VecZnx}; + +use crate::{ + GGSWExpandRows, ScratchTakeCore, + keyswitching::GLWEKeyswitch, + layouts::{GGLWEInfos, GGLWEPreparedToRef, GGSW, GGSWInfos, GGSWToMut, GGSWToRef, prepared::GLWETensorKeyPreparedToRef}, +}; + +impl GGSW<Vec<u8>> { + pub fn keyswitch_tmp_bytes<R, A, K, T, M, BE: Backend>( + module: &M, + res_infos: &R, + a_infos: &A, + key_infos: &K, + tsk_infos: &T, + ) -> usize + where + R: GGSWInfos, + A: GGSWInfos, + K: GGLWEInfos, + T: GGLWEInfos, + M: GGSWKeyswitch<BE>, + { + module.ggsw_keyswitch_tmp_bytes(res_infos, a_infos, key_infos, tsk_infos) + } +} + +impl<D: DataMut> GGSW<D> { + pub fn keyswitch<M, A, K, T, BE: Backend>(&mut self, module: &M, a: &A, key: &K, tsk: &T, scratch: &mut Scratch<BE>) + where + A: GGSWToRef, + K: GGLWEPreparedToRef<BE>, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + M: GGSWKeyswitch<BE>, + { + module.ggsw_keyswitch(self, a, key, tsk, scratch); + } + + pub fn keyswitch_inplace<M, K, T, BE: Backend>(&mut self, module: &M, key: &K, tsk: &T, scratch: &mut Scratch<BE>) + where + K: GGLWEPreparedToRef<BE>, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + M: GGSWKeyswitch<BE>, + { + module.ggsw_keyswitch_inplace(self, key, tsk, scratch); + } +} + +impl<BE: Backend> GGSWKeyswitch<BE> for Module<BE> where Self: GLWEKeyswitch<BE> + GGSWExpandRows<BE> {} + +pub trait GGSWKeyswitch<BE: Backend> +where + Self: GLWEKeyswitch<BE> + GGSWExpandRows<BE>, +{ + fn ggsw_keyswitch_tmp_bytes<R, A, K, T>(&self, res_infos: &R, a_infos: &A, key_infos: &K, tsk_infos: &T) -> usize + where + R: GGSWInfos, + A: GGSWInfos, + K: GGLWEInfos, + T: GGLWEInfos, + { + assert_eq!(key_infos.rank_in(), key_infos.rank_out()); + assert_eq!(tsk_infos.rank_in(), tsk_infos.rank_out()); + assert_eq!(key_infos.rank_in(), tsk_infos.rank_in()); + + let rank: usize = key_infos.rank_out().into(); + + let size_out: usize = res_infos.k().div_ceil(res_infos.base2k()) as usize; + let res_znx: usize = VecZnx::bytes_of(self.n(), rank + 1, size_out); + let ci_dft: usize = self.bytes_of_vec_znx_dft(rank + 1, size_out); + let ks: usize = self.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos); + let expand_rows: usize = self.ggsw_expand_rows_tmp_bytes(res_infos, tsk_infos); + let res_dft: usize = self.bytes_of_vec_znx_dft(rank + 1, size_out); + + if a_infos.base2k() == tsk_infos.base2k() { + res_znx + ci_dft + (ks | expand_rows | res_dft) + } else { + let a_conv: usize = VecZnx::bytes_of( + self.n(), + 1, + res_infos.k().div_ceil(tsk_infos.base2k()) as usize, + ) + self.vec_znx_normalize_tmp_bytes(); + res_znx + ci_dft + (a_conv | ks | expand_rows | res_dft) + } + } + + fn ggsw_keyswitch<R, A, K, T>(&self, res: &mut R, a: &A, key: &K, tsk: &T, scratch: &mut Scratch<BE>) + where + R: GGSWToMut, + A: GGSWToRef, + K: GGLWEPreparedToRef<BE>, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + let a: &GGSW<&[u8]> = &a.to_ref(); + + assert!(res.dnum() <= a.dnum()); + assert_eq!(res.dsize(), a.dsize()); + + for row in 0..a.dnum().into() { + // Key-switch column 0, i.e. + // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0s0' + a1s1' + a2s2') + M[i], a0, a1, a2) + self.glwe_keyswitch(&mut res.at_mut(row, 0), &a.at(row, 0), key, scratch); + } + + self.ggsw_expand_row(res, tsk, scratch); + } + + fn ggsw_keyswitch_inplace<R, K, T>(&self, res: &mut R, key: &K, tsk: &T, scratch: &mut Scratch<BE>) + where + R: GGSWToMut, + K: GGLWEPreparedToRef<BE>, + T: GLWETensorKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + + for row in 0..res.dnum().into() { + // Key-switch column 0, i.e. + // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0s0' + a1s1' + a2s2') + M[i], a0, a1, a2) + self.glwe_keyswitch_inplace(&mut res.at_mut(row, 0), key, scratch); + } + + self.ggsw_expand_row(res, tsk, scratch); + } +}
@@ -1,366 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, - VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAddInplace, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxDftCopy, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, - VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnx, VmpPMat, ZnxInfos}, -}; - -use crate::{ - layouts::{ - GGLWECiphertext, GGLWEInfos, GGSWCiphertext, GGSWInfos, GLWECiphertext, GLWEInfos, LWEInfos, - prepared::{GGLWESwitchingKeyPrepared, GGLWETensorKeyPrepared}, - }, - operations::GLWEOperations, -}; - -impl GGSWCiphertext<Vec<u8>> { - pub(crate) fn expand_row_scratch_space<B: Backend, OUT, TSK>(module: &Module<B>, out_infos: &OUT, tsk_infos: &TSK) -> usize - where - OUT: GGSWInfos, - TSK: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigAllocBytes + VecZnxNormalizeTmpBytes, - { - let tsk_size: usize = tsk_infos.k().div_ceil(tsk_infos.base2k()) as usize; - let size_in: usize = out_infos - .k() - .div_ceil(tsk_infos.base2k()) - .div_ceil(tsk_infos.dsize().into()) as usize; - - let tmp_dft_i: usize = module.vec_znx_dft_alloc_bytes((tsk_infos.rank_out() + 1).into(), tsk_size); - let tmp_a: usize = module.vec_znx_dft_alloc_bytes(1, size_in); - let vmp: usize = module.vmp_apply_dft_to_dft_tmp_bytes( - tsk_size, - size_in, - size_in, - (tsk_infos.rank_in()).into(), // Verify if rank+1 - (tsk_infos.rank_out()).into(), // Verify if rank+1 - tsk_size, - ); - let tmp_idft: usize = module.vec_znx_big_alloc_bytes(1, tsk_size); - let norm: usize = module.vec_znx_normalize_tmp_bytes(); - - tmp_dft_i + ((tmp_a + vmp) | (tmp_idft + norm)) - } - - #[allow(clippy::too_many_arguments)] - pub fn keyswitch_scratch_space<B: Backend, OUT, IN, KEY, TSK>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - apply_infos: &KEY, - tsk_infos: &TSK, - ) -> usize - where - OUT: GGSWInfos, - IN: GGSWInfos, - KEY: GGLWEInfos, - TSK: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigAllocBytes - + VecZnxNormalizeTmpBytes - + VecZnxBigNormalizeTmpBytes, - { - #[cfg(debug_assertions)] - { - assert_eq!(apply_infos.rank_in(), apply_infos.rank_out()); - assert_eq!(tsk_infos.rank_in(), tsk_infos.rank_out()); - assert_eq!(apply_infos.rank_in(), tsk_infos.rank_in()); - } - - let rank: usize = apply_infos.rank_out().into(); - - let size_out: usize = out_infos.k().div_ceil(out_infos.base2k()) as usize; - let res_znx: usize = VecZnx::alloc_bytes(module.n(), rank + 1, size_out); - let ci_dft: usize = module.vec_znx_dft_alloc_bytes(rank + 1, size_out); - let ks: usize = GLWECiphertext::keyswitch_scratch_space(module, out_infos, in_infos, apply_infos); - let expand_rows: usize = GGSWCiphertext::expand_row_scratch_space(module, out_infos, tsk_infos); - let res_dft: usize = module.vec_znx_dft_alloc_bytes(rank + 1, size_out); - - if in_infos.base2k() == tsk_infos.base2k() { - res_znx + ci_dft + (ks | expand_rows | res_dft) - } else { - let a_conv: usize = VecZnx::alloc_bytes( - module.n(), - 1, - out_infos.k().div_ceil(tsk_infos.base2k()) as usize, - ) + module.vec_znx_normalize_tmp_bytes(); - res_znx + ci_dft + (a_conv | ks | expand_rows | res_dft) - } - } - - #[allow(clippy::too_many_arguments)] - pub fn keyswitch_inplace_scratch_space<B: Backend, OUT, KEY, TSK>( - module: &Module<B>, - out_infos: &OUT, - apply_infos: &KEY, - tsk_infos: &TSK, - ) -> usize - where - OUT: GGSWInfos, - KEY: GGLWEInfos, - TSK: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigAllocBytes - + VecZnxNormalizeTmpBytes - + VecZnxBigNormalizeTmpBytes, - { - GGSWCiphertext::keyswitch_scratch_space(module, out_infos, out_infos, apply_infos, tsk_infos) - } -} - -impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> { - pub fn from_gglwe<DataA, DataTsk, B: Backend>( - &mut self, - module: &Module<B>, - a: &GGLWECiphertext<DataA>, - tsk: &GGLWETensorKeyPrepared<DataTsk, B>, - scratch: &mut Scratch<B>, - ) where - DataA: DataRef, - DataTsk: DataRef, - Module<B>: VecZnxCopy - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigAllocBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<B> - + VecZnxDftCopy<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftAddInplace<B> - + VecZnxBigNormalize<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxNormalize<B>, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - use crate::layouts::{GLWEInfos, LWEInfos}; - - assert_eq!(self.rank(), a.rank_out()); - assert_eq!(self.dnum(), a.dnum()); - assert_eq!(self.n(), module.n() as u32); - assert_eq!(a.n(), module.n() as u32); - assert_eq!(tsk.n(), module.n() as u32); - } - (0..self.dnum().into()).for_each(|row_i| { - self.at_mut(row_i, 0).copy(module, &a.at(row_i, 0)); - }); - self.expand_row(module, tsk, scratch); - } - - pub fn keyswitch<DataLhs: DataRef, DataKsk: DataRef, DataTsk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - lhs: &GGSWCiphertext<DataLhs>, - ksk: &GGLWESwitchingKeyPrepared<DataKsk, B>, - tsk: &GGLWETensorKeyPrepared<DataTsk, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftCopy<B> - + VecZnxDftAddInplace<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxNormalize<B>, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnx, - { - (0..lhs.dnum().into()).for_each(|row_i| { - // Key-switch column 0, i.e. - // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0s0' + a1s1' + a2s2') + M[i], a0, a1, a2) - self.at_mut(row_i, 0) - .keyswitch(module, &lhs.at(row_i, 0), ksk, scratch); - }); - self.expand_row(module, tsk, scratch); - } - - pub fn keyswitch_inplace<DataKsk: DataRef, DataTsk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - ksk: &GGLWESwitchingKeyPrepared<DataKsk, B>, - tsk: &GGLWETensorKeyPrepared<DataTsk, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftCopy<B> - + VecZnxDftAddInplace<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxNormalize<B>, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnx, - { - (0..self.dnum().into()).for_each(|row_i| { - // Key-switch column 0, i.e. - // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0s0' + a1s1' + a2s2') + M[i], a0, a1, a2) - self.at_mut(row_i, 0) - .keyswitch_inplace(module, ksk, scratch); - }); - self.expand_row(module, tsk, scratch); - } - - pub fn expand_row<DataTsk: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - tsk: &GGLWETensorKeyPrepared<DataTsk, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigAllocBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<B> - + VecZnxDftCopy<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftAddInplace<B> - + VecZnxBigNormalize<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxNormalize<B>, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnx, - { - let basek_in: usize = self.base2k().into(); - let basek_tsk: usize = tsk.base2k().into(); - - assert!(scratch.available() >= GGSWCiphertext::expand_row_scratch_space(module, self, tsk)); - - let n: usize = self.n().into(); - let rank: usize = self.rank().into(); - let cols: usize = rank + 1; - - let a_size: usize = (self.size() * basek_in).div_ceil(basek_tsk); - - // Keyswitch the j-th row of the col 0 - for row_i in 0..self.dnum().into() { - let a = &self.at(row_i, 0).data; - - // Pre-compute DFT of (a0, a1, a2) - let (mut ci_dft, scratch_1) = scratch.take_vec_znx_dft(n, cols, a_size); - - if basek_in == basek_tsk { - for i in 0..cols { - module.vec_znx_dft_apply(1, 0, &mut ci_dft, i, a, i); - } - } else { - let (mut a_conv, scratch_2) = scratch_1.take_vec_znx(n, 1, a_size); - for i in 0..cols { - module.vec_znx_normalize(basek_tsk, &mut a_conv, 0, basek_in, a, i, scratch_2); - module.vec_znx_dft_apply(1, 0, &mut ci_dft, i, &a_conv, 0); - } - } - - for col_j in 1..cols { - // Example for rank 3: - // - // Note: M is a vector (m, Bm, B^2m, B^3m, ...), so each column is - // actually composed of that many dnum and we focus on a specific row here - // implicitely given ci_dft. - // - // # Input - // - // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0 , a1 , a2 ) - // col 1: (0, 0, 0, 0) - // col 2: (0, 0, 0, 0) - // col 3: (0, 0, 0, 0) - // - // # Output - // - // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0 , a1 , a2 ) - // col 1: (-(b0s0 + b1s1 + b2s2) , b0 + M[i], b1 , b2 ) - // col 2: (-(c0s0 + c1s1 + c2s2) , c0 , c1 + M[i], c2 ) - // col 3: (-(d0s0 + d1s1 + d2s2) , d0 , d1 , d2 + M[i]) - - let dsize: usize = tsk.dsize().into(); - - let (mut tmp_dft_i, scratch_2) = scratch_1.take_vec_znx_dft(n, cols, tsk.size()); - let (mut tmp_a, scratch_3) = scratch_2.take_vec_znx_dft(n, 1, ci_dft.size().div_ceil(dsize)); - - { - // Performs a key-switch for each combination of s[i]*s[j], i.e. for a0, a1, a2 - // - // # Example for col=1 - // - // a0 * (-(f0s0 + f1s1 + f1s2) + s0^2, f0, f1, f2) = (-(a0f0s0 + a0f1s1 + a0f1s2) + a0s0^2, a0f0, a0f1, a0f2) - // + - // a1 * (-(g0s0 + g1s1 + g1s2) + s0s1, g0, g1, g2) = (-(a1g0s0 + a1g1s1 + a1g1s2) + a1s0s1, a1g0, a1g1, a1g2) - // + - // a2 * (-(h0s0 + h1s1 + h1s2) + s0s2, h0, h1, h2) = (-(a2h0s0 + a2h1s1 + a2h1s2) + a2s0s2, a2h0, a2h1, a2h2) - // = - // (-(x0s0 + x1s1 + x2s2) + s0(a0s0 + a1s1 + a2s2), x0, x1, x2) - for col_i in 1..cols { - let pmat: &VmpPMat<DataTsk, B> = &tsk.at(col_i - 1, col_j - 1).key.data; // Selects Enc(s[i]s[j]) - - // Extracts a[i] and multipies with Enc(s[i]s[j]) - for di in 0..dsize { - tmp_a.set_size((ci_dft.size() + di) / dsize); - - // Small optimization for dsize > 2 - // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then - // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. - // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last dsize-1 limbs, but this introduce - // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same - // noise is kept with respect to the ideal functionality. - tmp_dft_i.set_size(tsk.size() - ((dsize - di) as isize - 2).max(0) as usize); - - module.vec_znx_dft_copy(dsize, dsize - 1 - di, &mut tmp_a, 0, &ci_dft, col_i); - if di == 0 && col_i == 1 { - module.vmp_apply_dft_to_dft(&mut tmp_dft_i, &tmp_a, pmat, scratch_3); - } else { - module.vmp_apply_dft_to_dft_add(&mut tmp_dft_i, &tmp_a, pmat, di, scratch_3); - } - } - } - } - - // Adds -(sum a[i] * s[i]) + m) on the i-th column of tmp_idft_i - // - // (-(x0s0 + x1s1 + x2s2) + a0s0s0 + a1s0s1 + a2s0s2, x0, x1, x2) - // + - // (0, -(a0s0 + a1s1 + a2s2) + M[i], 0, 0) - // = - // (-(x0s0 + x1s1 + x2s2) + s0(a0s0 + a1s1 + a2s2), x0 -(a0s0 + a1s1 + a2s2) + M[i], x1, x2) - // = - // (-(x0s0 + x1s1 + x2s2), x0 + M[i], x1, x2) - module.vec_znx_dft_add_inplace(&mut tmp_dft_i, col_j, &ci_dft, 0); - let (mut tmp_idft, scratch_3) = scratch_2.take_vec_znx_big(n, 1, tsk.size()); - for i in 0..cols { - module.vec_znx_idft_apply_tmpa(&mut tmp_idft, 0, &mut tmp_dft_i, i); - module.vec_znx_big_normalize( - basek_in, - &mut self.at_mut(row_i, col_j).data, - i, - basek_tsk, - &tmp_idft, - 0, - scratch_3, - ); - } - } - } - } -}
@@ -0,0 +1,370 @@
+use poulpy_hal::{ + api::{ + ModuleN, ScratchAvailable, ScratchTakeBasic, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, + VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, + VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, + }, + layouts::{Backend, DataMut, DataViewMut, Module, Scratch, VecZnx, VecZnxBig, VecZnxDft, VmpPMat, ZnxInfos}, +}; + +use crate::{ + ScratchTakeCore, + layouts::{GGLWEInfos, GGLWEPrepared, GGLWEPreparedToRef, GLWE, GLWEInfos, GLWEToMut, GLWEToRef, LWEInfos}, +}; + +impl GLWE<Vec<u8>> { + pub fn keyswitch_tmp_bytes<M, R, A, B, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, key_infos: &B) -> usize + where + R: GLWEInfos, + A: GLWEInfos, + B: GGLWEInfos, + M: GLWEKeyswitch<BE>, + { + module.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos) + } +} + +impl<D: DataMut> GLWE<D> { + pub fn keyswitch<A, B, M, BE: Backend>(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch<BE>) + where + A: GLWEToRef, + B: GGLWEPreparedToRef<BE>, + M: GLWEKeyswitch<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_keyswitch(self, a, b, scratch); + } + + pub fn keyswitch_inplace<A, M, BE: Backend>(&mut self, module: &M, a: &A, scratch: &mut Scratch<BE>) + where + A: GGLWEPreparedToRef<BE>, + M: GLWEKeyswitch<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_keyswitch_inplace(self, a, scratch); + } +} + +impl<BE: Backend> GLWEKeyswitch<BE> for Module<BE> where + Self: Sized + + ModuleN + + VecZnxDftBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VecZnxNormalizeTmpBytes + + VecZnxDftBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxDftApply<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalize<BE> + + VecZnxNormalizeTmpBytes +{ +} + +pub trait GLWEKeyswitch<BE: Backend> +where + Self: Sized + + ModuleN + + VecZnxDftBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VecZnxNormalizeTmpBytes + + VecZnxDftBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxDftApply<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalize<BE> + + VecZnxNormalizeTmpBytes, +{ + fn glwe_keyswitch_tmp_bytes<R, A, B>(&self, res_infos: &R, a_infos: &A, key_infos: &B) -> usize + where + R: GLWEInfos, + A: GLWEInfos, + B: GGLWEInfos, + { + let in_size: usize = a_infos + .k() + .div_ceil(key_infos.base2k()) + .div_ceil(key_infos.dsize().into()) as usize; + let out_size: usize = res_infos.size(); + let ksk_size: usize = key_infos.size(); + let res_dft: usize = self.bytes_of_vec_znx_dft((key_infos.rank_out() + 1).into(), ksk_size); // TODO OPTIMIZE + let ai_dft: usize = self.bytes_of_vec_znx_dft((key_infos.rank_in()).into(), in_size); + let vmp: usize = self.vmp_apply_dft_to_dft_tmp_bytes( + out_size, + in_size, + in_size, + (key_infos.rank_in()).into(), + (key_infos.rank_out() + 1).into(), + ksk_size, + ) + self.bytes_of_vec_znx_dft((key_infos.rank_in()).into(), in_size); + let normalize_big: usize = self.vec_znx_big_normalize_tmp_bytes(); + if a_infos.base2k() == key_infos.base2k() { + res_dft + ((ai_dft + vmp) | normalize_big) + } else if key_infos.dsize() == 1 { + // In this case, we only need one column, temporary, that we can drop once a_dft is computed. + let normalize_conv: usize = VecZnx::bytes_of(self.n(), 1, in_size) + self.vec_znx_normalize_tmp_bytes(); + res_dft + (((ai_dft + normalize_conv) | vmp) | normalize_big) + } else { + // Since we stride over a to get a_dft when dsize > 1, we need to store the full columns of a with in the base conversion. + let normalize_conv: usize = VecZnx::bytes_of(self.n(), (key_infos.rank_in()).into(), in_size); + res_dft + ((ai_dft + normalize_conv + (self.vec_znx_normalize_tmp_bytes() | vmp)) | normalize_big) + } + } + + fn glwe_keyswitch<R, A, K>(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + A: GLWEToRef, + K: GGLWEPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); + let b: &GGLWEPrepared<&[u8], BE> = &key.to_ref(); + + assert_eq!( + a.rank(), + b.rank_in(), + "a.rank(): {} != b.rank_in(): {}", + a.rank(), + b.rank_in() + ); + assert_eq!( + res.rank(), + b.rank_out(), + "res.rank(): {} != b.rank_out(): {}", + res.rank(), + b.rank_out() + ); + + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.n(), self.n() as u32); + assert_eq!(b.n(), self.n() as u32); + + let scrach_needed: usize = self.glwe_keyswitch_tmp_bytes(res, a, b); + + assert!( + scratch.available() >= scrach_needed, + "scratch.available()={} < glwe_keyswitch_tmp_bytes={scrach_needed}", + scratch.available(), + ); + + let basek_out: usize = res.base2k().into(); + let base2k_out: usize = b.base2k().into(); + + let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self, (res.rank() + 1).into(), b.size()); // Todo optimise + let res_big: VecZnxBig<&mut [u8], BE> = keyswitch_internal(self, res_dft, a, b, scratch_1); + (0..(res.rank() + 1).into()).for_each(|i| { + self.vec_znx_big_normalize( + basek_out, + &mut res.data, + i, + base2k_out, + &res_big, + i, + scratch_1, + ); + }) + } + + fn glwe_keyswitch_inplace<R, K>(&self, res: &mut R, key: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + K: GGLWEPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GGLWEPrepared<&[u8], BE> = &key.to_ref(); + + assert_eq!( + res.rank(), + a.rank_in(), + "res.rank(): {} != a.rank_in(): {}", + res.rank(), + a.rank_in() + ); + assert_eq!( + res.rank(), + a.rank_out(), + "res.rank(): {} != b.rank_out(): {}", + res.rank(), + a.rank_out() + ); + + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.n(), self.n() as u32); + + let scrach_needed: usize = self.glwe_keyswitch_tmp_bytes(res, res, a); + + assert!( + scratch.available() >= scrach_needed, + "scratch.available()={} < glwe_keyswitch_tmp_bytes={scrach_needed}", + scratch.available(), + ); + + let base2k_in: usize = res.base2k().into(); + let base2k_out: usize = a.base2k().into(); + + let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self, (res.rank() + 1).into(), a.size()); // Todo optimise + let res_big: VecZnxBig<&mut [u8], BE> = keyswitch_internal(self, res_dft, res, a, scratch_1); + (0..(res.rank() + 1).into()).for_each(|i| { + self.vec_znx_big_normalize( + base2k_in, + &mut res.data, + i, + base2k_out, + &res_big, + i, + scratch_1, + ); + }) + } +} + +impl GLWE<Vec<u8>> {} + +impl<DataSelf: DataMut> GLWE<DataSelf> {} + +pub(crate) fn keyswitch_internal<BE: Backend, M, DR, A, K>( + module: &M, + mut res: VecZnxDft<DR, BE>, + a: &A, + key: &K, + scratch: &mut Scratch<BE>, +) -> VecZnxBig<DR, BE> +where + DR: DataMut, + A: GLWEToRef, + K: GGLWEPreparedToRef<BE>, + M: ModuleN + + VecZnxDftBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VmpApplyDftToDftTmpBytes + + VmpApplyDftToDft<BE> + + VmpApplyDftToDftAdd<BE> + + VecZnxDftApply<BE> + + VecZnxIdftApplyConsume<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxNormalize<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + let a: &GLWE<&[u8]> = &a.to_ref(); + let key: &GGLWEPrepared<&[u8], BE> = &key.to_ref(); + + let base2k_in: usize = a.base2k().into(); + let base2k_out: usize = key.base2k().into(); + let cols: usize = (a.rank() + 1).into(); + let a_size: usize = (a.size() * base2k_in).div_ceil(base2k_out); + let pmat: &VmpPMat<&[u8], BE> = &key.data; + + if key.dsize() == 1 { + let (mut ai_dft, scratch_1) = scratch.take_vec_znx_dft(module, cols - 1, a.size()); + + if base2k_in == base2k_out { + (0..cols - 1).for_each(|col_i| { + module.vec_znx_dft_apply(1, 0, &mut ai_dft, col_i, a.data(), col_i + 1); + }); + } else { + let (mut a_conv, scratch_2) = scratch_1.take_vec_znx(module.n(), 1, a_size); + (0..cols - 1).for_each(|col_i| { + module.vec_znx_normalize( + base2k_out, + &mut a_conv, + 0, + base2k_in, + a.data(), + col_i + 1, + scratch_2, + ); + module.vec_znx_dft_apply(1, 0, &mut ai_dft, col_i, &a_conv, 0); + }); + } + + module.vmp_apply_dft_to_dft(&mut res, &ai_dft, pmat, scratch_1); + } else { + let dsize: usize = key.dsize().into(); + + let (mut ai_dft, scratch_1) = scratch.take_vec_znx_dft(module, cols - 1, a_size.div_ceil(dsize)); + ai_dft.data_mut().fill(0); + + if base2k_in == base2k_out { + for di in 0..dsize { + ai_dft.set_size((a_size + di) / dsize); + + // Small optimization for dsize > 2 + // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then + // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. + // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last dsize-1 limbs, but this introduce + // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same + // noise is kept with respect to the ideal functionality. + res.set_size(pmat.size() - ((dsize - di) as isize - 2).max(0) as usize); + + for j in 0..cols - 1 { + module.vec_znx_dft_apply(dsize, dsize - di - 1, &mut ai_dft, j, a.data(), j + 1); + } + + if di == 0 { + module.vmp_apply_dft_to_dft(&mut res, &ai_dft, pmat, scratch_1); + } else { + module.vmp_apply_dft_to_dft_add(&mut res, &ai_dft, pmat, di, scratch_1); + } + } + } else { + let (mut a_conv, scratch_2) = scratch_1.take_vec_znx(module.n(), cols - 1, a_size); + for j in 0..cols - 1 { + module.vec_znx_normalize( + base2k_out, + &mut a_conv, + j, + base2k_in, + a.data(), + j + 1, + scratch_2, + ); + } + + for di in 0..dsize { + ai_dft.set_size((a_size + di) / dsize); + + // Small optimization for dsize > 2 + // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then + // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. + // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last dsize-1 limbs, but this introduce + // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same + // noise is kept with respect to the ideal functionality. + res.set_size(pmat.size() - ((dsize - di) as isize - 2).max(0) as usize); + + for j in 0..cols - 1 { + module.vec_znx_dft_apply(dsize, dsize - di - 1, &mut ai_dft, j, &a_conv, j); + } + + if di == 0 { + module.vmp_apply_dft_to_dft(&mut res, &ai_dft, pmat, scratch_2); + } else { + module.vmp_apply_dft_to_dft_add(&mut res, &ai_dft, pmat, di, scratch_2); + } + } + } + + res.set_size(res.max_size()); + } + + let mut res_big: VecZnxBig<DR, BE> = module.vec_znx_idft_apply_consume(res); + module.vec_znx_big_add_small_inplace(&mut res_big, 0, a.data(), 0); + res_big +}
@@ -1,414 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, - VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, DataViewMut, Module, Scratch, VecZnx, VecZnxBig, VecZnxDft, VmpPMat, ZnxInfos}, -}; - -use crate::layouts::{GGLWEInfos, GLWECiphertext, GLWEInfos, LWEInfos, prepared::GGLWESwitchingKeyPrepared}; - -impl GLWECiphertext<Vec<u8>> { - pub fn keyswitch_scratch_space<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - key_apply: &KEY, - ) -> usize - where - OUT: GLWEInfos, - IN: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, - { - let in_size: usize = in_infos - .k() - .div_ceil(key_apply.base2k()) - .div_ceil(key_apply.dsize().into()) as usize; - let out_size: usize = out_infos.size(); - let ksk_size: usize = key_apply.size(); - let res_dft: usize = module.vec_znx_dft_alloc_bytes((key_apply.rank_out() + 1).into(), ksk_size); // TODO OPTIMIZE - let ai_dft: usize = module.vec_znx_dft_alloc_bytes((key_apply.rank_in()).into(), in_size); - let vmp: usize = module.vmp_apply_dft_to_dft_tmp_bytes( - out_size, - in_size, - in_size, - (key_apply.rank_in()).into(), - (key_apply.rank_out() + 1).into(), - ksk_size, - ) + module.vec_znx_dft_alloc_bytes((key_apply.rank_in()).into(), in_size); - let normalize_big: usize = module.vec_znx_big_normalize_tmp_bytes(); - if in_infos.base2k() == key_apply.base2k() { - res_dft + ((ai_dft + vmp) | normalize_big) - } else if key_apply.dsize() == 1 { - // In this case, we only need one column, temporary, that we can drop once a_dft is computed. - let normalize_conv: usize = VecZnx::alloc_bytes(module.n(), 1, in_size) + module.vec_znx_normalize_tmp_bytes(); - res_dft + (((ai_dft + normalize_conv) | vmp) | normalize_big) - } else { - // Since we stride over a to get a_dft when dsize > 1, we need to store the full columns of a with in the base conversion. - let normalize_conv: usize = VecZnx::alloc_bytes(module.n(), (key_apply.rank_in()).into(), in_size); - res_dft + ((ai_dft + normalize_conv + (module.vec_znx_normalize_tmp_bytes() | vmp)) | normalize_big) - } - } - - pub fn keyswitch_inplace_scratch_space<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_apply: &KEY) -> usize - where - OUT: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, - { - Self::keyswitch_scratch_space(module, out_infos, out_infos, key_apply) - } -} - -impl<DataSelf: DataRef> GLWECiphertext<DataSelf> { - #[allow(dead_code)] - pub(crate) fn assert_keyswitch<B: Backend, DataLhs, DataRhs>( - &self, - module: &Module<B>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &GGLWESwitchingKeyPrepared<DataRhs, B>, - scratch: &Scratch<B>, - ) where - DataLhs: DataRef, - DataRhs: DataRef, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable, - { - assert_eq!( - lhs.rank(), - rhs.rank_in(), - "lhs.rank(): {} != rhs.rank_in(): {}", - lhs.rank(), - rhs.rank_in() - ); - assert_eq!( - self.rank(), - rhs.rank_out(), - "self.rank(): {} != rhs.rank_out(): {}", - self.rank(), - rhs.rank_out() - ); - assert_eq!(rhs.n(), self.n()); - assert_eq!(lhs.n(), self.n()); - - let scrach_needed: usize = GLWECiphertext::keyswitch_scratch_space(module, self, lhs, rhs); - - assert!( - scratch.available() >= scrach_needed, - "scratch.available()={} < GLWECiphertext::keyswitch_scratch_space( - module, - self.base2k(), - self.k(), - lhs.base2k(), - lhs.k(), - rhs.base2k(), - rhs.k(), - rhs.dsize(), - rhs.rank_in(), - rhs.rank_out(), - )={scrach_needed}", - scratch.available(), - ); - } - - #[allow(dead_code)] - pub(crate) fn assert_keyswitch_inplace<B: Backend, DataRhs>( - &self, - module: &Module<B>, - rhs: &GGLWESwitchingKeyPrepared<DataRhs, B>, - scratch: &Scratch<B>, - ) where - DataRhs: DataRef, - Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable, - { - assert_eq!( - self.rank(), - rhs.rank_out(), - "self.rank(): {} != rhs.rank_out(): {}", - self.rank(), - rhs.rank_out() - ); - - assert_eq!(rhs.n(), self.n()); - - let scrach_needed: usize = GLWECiphertext::keyswitch_inplace_scratch_space(module, self, rhs); - - assert!( - scratch.available() >= scrach_needed, - "scratch.available()={} < GLWECiphertext::keyswitch_scratch_space()={scrach_needed}", - scratch.available(), - ); - } -} - -impl<DataSelf: DataMut> GLWECiphertext<DataSelf> { - pub fn keyswitch<DataLhs: DataRef, DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - glwe_in: &GLWECiphertext<DataLhs>, - rhs: &GGLWESwitchingKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - self.assert_keyswitch(module, glwe_in, rhs, scratch); - } - - let basek_out: usize = self.base2k().into(); - let basek_ksk: usize = rhs.base2k().into(); - - let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n().into(), (self.rank() + 1).into(), rhs.size()); // Todo optimise - let res_big: VecZnxBig<_, B> = glwe_in.keyswitch_internal(module, res_dft, rhs, scratch_1); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_big_normalize( - basek_out, - &mut self.data, - i, - basek_ksk, - &res_big, - i, - scratch_1, - ); - }) - } - - pub fn keyswitch_inplace<DataRhs: DataRef, B: Backend>( - &mut self, - module: &Module<B>, - rhs: &GGLWESwitchingKeyPrepared<DataRhs, B>, - scratch: &mut Scratch<B>, - ) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - self.assert_keyswitch_inplace(module, rhs, scratch); - } - - let basek_in: usize = self.base2k().into(); - let basek_ksk: usize = rhs.base2k().into(); - - let (res_dft, scratch_1) = scratch.take_vec_znx_dft(self.n().into(), (self.rank() + 1).into(), rhs.size()); // Todo optimise - let res_big: VecZnxBig<_, B> = self.keyswitch_internal(module, res_dft, rhs, scratch_1); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_big_normalize( - basek_in, - &mut self.data, - i, - basek_ksk, - &res_big, - i, - scratch_1, - ); - }) - } -} - -impl<D: DataRef> GLWECiphertext<D> { - pub(crate) fn keyswitch_internal<B: Backend, DataRes, DataKey>( - &self, - module: &Module<B>, - res_dft: VecZnxDft<DataRes, B>, - rhs: &GGLWESwitchingKeyPrepared<DataKey, B>, - scratch: &mut Scratch<B>, - ) -> VecZnxBig<DataRes, B> - where - DataRes: DataMut, - DataKey: DataRef, - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + TakeVecZnx, - { - if rhs.dsize() == 1 { - return keyswitch_vmp_one_digit( - module, - self.base2k().into(), - rhs.base2k().into(), - res_dft, - &self.data, - &rhs.key.data, - scratch, - ); - } - - keyswitch_vmp_multiple_digits( - module, - self.base2k().into(), - rhs.base2k().into(), - res_dft, - &self.data, - &rhs.key.data, - rhs.dsize().into(), - scratch, - ) - } -} - -fn keyswitch_vmp_one_digit<B: Backend, DataRes, DataIn, DataVmp>( - module: &Module<B>, - basek_in: usize, - basek_ksk: usize, - mut res_dft: VecZnxDft<DataRes, B>, - a: &VecZnx<DataIn>, - mat: &VmpPMat<DataVmp, B>, - scratch: &mut Scratch<B>, -) -> VecZnxBig<DataRes, B> -where - DataRes: DataMut, - DataIn: DataRef, - DataVmp: DataRef, - Module<B>: VecZnxDftAllocBytes - + VecZnxDftApply<B> - + VmpApplyDftToDft<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + TakeVecZnx, -{ - let cols: usize = a.cols(); - - let a_size: usize = (a.size() * basek_in).div_ceil(basek_ksk); - let (mut ai_dft, scratch_1) = scratch.take_vec_znx_dft(a.n(), cols - 1, a.size()); - - if basek_in == basek_ksk { - (0..cols - 1).for_each(|col_i| { - module.vec_znx_dft_apply(1, 0, &mut ai_dft, col_i, a, col_i + 1); - }); - } else { - let (mut a_conv, scratch_2) = scratch_1.take_vec_znx(a.n(), 1, a_size); - (0..cols - 1).for_each(|col_i| { - module.vec_znx_normalize(basek_ksk, &mut a_conv, 0, basek_in, a, col_i + 1, scratch_2); - module.vec_znx_dft_apply(1, 0, &mut ai_dft, col_i, &a_conv, 0); - }); - } - - module.vmp_apply_dft_to_dft(&mut res_dft, &ai_dft, mat, scratch_1); - let mut res_big: VecZnxBig<DataRes, B> = module.vec_znx_idft_apply_consume(res_dft); - module.vec_znx_big_add_small_inplace(&mut res_big, 0, a, 0); - res_big -} - -#[allow(clippy::too_many_arguments)] -fn keyswitch_vmp_multiple_digits<B: Backend, DataRes, DataIn, DataVmp>( - module: &Module<B>, - basek_in: usize, - basek_ksk: usize, - mut res_dft: VecZnxDft<DataRes, B>, - a: &VecZnx<DataIn>, - mat: &VmpPMat<DataVmp, B>, - dsize: usize, - scratch: &mut Scratch<B>, -) -> VecZnxBig<DataRes, B> -where - DataRes: DataMut, - DataIn: DataRef, - DataVmp: DataRef, - Module<B>: VecZnxDftAllocBytes - + VecZnxDftApply<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + TakeVecZnx, -{ - let cols: usize = a.cols(); - let a_size: usize = (a.size() * basek_in).div_ceil(basek_ksk); - let (mut ai_dft, scratch_1) = scratch.take_vec_znx_dft(a.n(), cols - 1, a_size.div_ceil(dsize)); - ai_dft.data_mut().fill(0); - - if basek_in == basek_ksk { - for di in 0..dsize { - ai_dft.set_size((a_size + di) / dsize); - - // Small optimization for dsize > 2 - // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then - // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. - // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last dsize-1 limbs, but this introduce - // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same - // noise is kept with respect to the ideal functionality. - res_dft.set_size(mat.size() - ((dsize - di) as isize - 2).max(0) as usize); - - for j in 0..cols - 1 { - module.vec_znx_dft_apply(dsize, dsize - di - 1, &mut ai_dft, j, a, j + 1); - } - - if di == 0 { - module.vmp_apply_dft_to_dft(&mut res_dft, &ai_dft, mat, scratch_1); - } else { - module.vmp_apply_dft_to_dft_add(&mut res_dft, &ai_dft, mat, di, scratch_1); - } - } - } else { - let (mut a_conv, scratch_2) = scratch_1.take_vec_znx(a.n(), cols - 1, a_size); - for j in 0..cols - 1 { - module.vec_znx_normalize(basek_ksk, &mut a_conv, j, basek_in, a, j + 1, scratch_2); - } - - for di in 0..dsize { - ai_dft.set_size((a_size + di) / dsize); - - // Small optimization for dsize > 2 - // VMP produce some error e, and since we aggregate vmp * 2^{di * B}, then - // we also aggregate ei * 2^{di * B}, with the largest error being ei * 2^{(dsize-1) * B}. - // As such we can ignore the last dsize-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last dsize-1 limbs, but this introduce - // ~0.5 to 1 bit of additional noise, and thus not chosen here to ensure that the same - // noise is kept with respect to the ideal functionality. - res_dft.set_size(mat.size() - ((dsize - di) as isize - 2).max(0) as usize); - - for j in 0..cols - 1 { - module.vec_znx_dft_apply(dsize, dsize - di - 1, &mut ai_dft, j, &a_conv, j); - } - - if di == 0 { - module.vmp_apply_dft_to_dft(&mut res_dft, &ai_dft, mat, scratch_2); - } else { - module.vmp_apply_dft_to_dft_add(&mut res_dft, &ai_dft, mat, di, scratch_2); - } - } - } - - res_dft.set_size(res_dft.max_size()); - let mut res_big: VecZnxBig<DataRes, B> = module.vec_znx_idft_apply_consume(res_dft); - module.vec_znx_big_add_small_inplace(&mut res_big, 0, a, 0); - res_big -}
@@ -0,0 +1,116 @@
+use poulpy_hal::{ + api::ScratchAvailable, + layouts::{Backend, DataMut, Module, Scratch, ZnxView, ZnxViewMut, ZnxZero}, +}; + +use crate::{ + LWESampleExtract, ScratchTakeCore, + keyswitching::GLWEKeyswitch, + layouts::{GGLWEInfos, GGLWEPreparedToRef, GLWE, GLWELayout, LWE, LWEInfos, LWEToMut, LWEToRef, Rank, TorusPrecision}, +}; + +impl LWE<Vec<u8>> { + pub fn keyswitch_tmp_bytes<M, R, A, K, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, key_infos: &K) -> usize + where + R: LWEInfos, + A: LWEInfos, + K: GGLWEInfos, + M: LWEKeySwitch<BE>, + { + module.lwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos) + } +} + +impl<D: DataMut> LWE<D> { + pub fn keyswitch<M, A, K, BE: Backend>(&mut self, module: &M, a: &A, ksk: &K, scratch: &mut Scratch<BE>) + where + A: LWEToRef, + K: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + M: LWEKeySwitch<BE>, + { + module.lwe_keyswitch(self, a, ksk, scratch); + } +} + +impl<BE: Backend> LWEKeySwitch<BE> for Module<BE> where Self: GLWEKeyswitch<BE> + LWESampleExtract {} + +pub trait LWEKeySwitch<BE: Backend> +where + Self: GLWEKeyswitch<BE> + LWESampleExtract, +{ + fn lwe_keyswitch_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize + where + R: LWEInfos, + A: LWEInfos, + K: GGLWEInfos, + { + let max_k: TorusPrecision = a_infos.k().max(res_infos.k()); + + let glwe_a_infos: GLWELayout = GLWELayout { + n: self.n().into(), + base2k: a_infos.base2k(), + k: max_k, + rank: Rank(1), + }; + + let glwe_res_infos: GLWELayout = GLWELayout { + n: self.n().into(), + base2k: res_infos.base2k(), + k: max_k, + rank: Rank(1), + }; + + let glwe_in: usize = GLWE::bytes_of_from_infos(&glwe_a_infos); + let glwe_out: usize = GLWE::bytes_of_from_infos(&glwe_res_infos); + let ks: usize = self.glwe_keyswitch_tmp_bytes(&glwe_res_infos, &glwe_a_infos, key_infos); + + glwe_in + glwe_out + ks + } + + fn lwe_keyswitch<R, A, K>(&self, res: &mut R, a: &A, ksk: &K, scratch: &mut Scratch<BE>) + where + R: LWEToMut, + A: LWEToRef, + K: GGLWEPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut LWE<&mut [u8]> = &mut res.to_mut(); + let a: &LWE<&[u8]> = &a.to_ref(); + + assert!(res.n().as_usize() <= self.n()); + assert!(a.n().as_usize() <= self.n()); + assert_eq!(ksk.n(), self.n() as u32); + assert!(scratch.available() >= self.lwe_keyswitch_tmp_bytes(res, a, ksk)); + + let max_k: TorusPrecision = res.k().max(a.k()); + + let a_size: usize = a.k().div_ceil(ksk.base2k()) as usize; + + let (mut glwe_in, scratch_1) = scratch.take_glwe(&GLWELayout { + n: ksk.n(), + base2k: a.base2k(), + k: max_k, + rank: Rank(1), + }); + glwe_in.data.zero(); + + let (mut glwe_out, scratch_1) = scratch_1.take_glwe(&GLWELayout { + n: ksk.n(), + base2k: res.base2k(), + k: max_k, + rank: Rank(1), + }); + + let n_lwe: usize = a.n().into(); + + for i in 0..a_size { + let data_lwe: &[i64] = a.data.at(0, i); + glwe_in.data.at_mut(0, i)[0] = data_lwe[0]; + glwe_in.data.at_mut(1, i)[..n_lwe].copy_from_slice(&data_lwe[1..]); + } + + self.glwe_keyswitch(&mut glwe_out, &glwe_in, ksk, scratch_1); + self.lwe_sample_extract(res, &glwe_out); + } +}
@@ -1,126 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, - VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, - VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxView, ZnxViewMut, ZnxZero}, -}; - -use crate::{ - TakeGLWECt, - layouts::{ - GGLWEInfos, GLWECiphertext, GLWECiphertextLayout, LWECiphertext, LWEInfos, Rank, TorusPrecision, - prepared::LWESwitchingKeyPrepared, - }, -}; - -impl LWECiphertext<Vec<u8>> { - pub fn keyswitch_scratch_space<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - out_infos: &OUT, - in_infos: &IN, - key_infos: &KEY, - ) -> usize - where - OUT: LWEInfos, - IN: LWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes, - { - let max_k: TorusPrecision = in_infos.k().max(out_infos.k()); - - let glwe_in_infos: GLWECiphertextLayout = GLWECiphertextLayout { - n: module.n().into(), - base2k: in_infos.base2k(), - k: max_k, - rank: Rank(1), - }; - - let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { - n: module.n().into(), - base2k: out_infos.base2k(), - k: max_k, - rank: Rank(1), - }; - - let glwe_in: usize = GLWECiphertext::alloc_bytes(&glwe_in_infos); - let glwe_out: usize = GLWECiphertext::alloc_bytes(&glwe_out_infos); - let ks: usize = GLWECiphertext::keyswitch_scratch_space(module, &glwe_out_infos, &glwe_in_infos, key_infos); - - glwe_in + glwe_out + ks - } -} - -impl<DLwe: DataMut> LWECiphertext<DLwe> { - pub fn keyswitch<A, DKs, B: Backend>( - &mut self, - module: &Module<B>, - a: &LWECiphertext<A>, - ksk: &LWESwitchingKeyPrepared<DKs, B>, - scratch: &mut Scratch<B>, - ) where - A: DataRef, - DKs: DataRef, - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxCopy, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - assert!(self.n() <= module.n() as u32); - assert!(a.n() <= module.n() as u32); - assert!(scratch.available() >= LWECiphertext::keyswitch_scratch_space(module, self, a, ksk)); - } - - let max_k: TorusPrecision = self.k().max(a.k()); - - let a_size: usize = a.k().div_ceil(ksk.base2k()) as usize; - - let (mut glwe_in, scratch_1) = scratch.take_glwe_ct(&GLWECiphertextLayout { - n: ksk.n(), - base2k: a.base2k(), - k: max_k, - rank: Rank(1), - }); - glwe_in.data.zero(); - - let (mut glwe_out, scratch_1) = scratch_1.take_glwe_ct(&GLWECiphertextLayout { - n: ksk.n(), - base2k: self.base2k(), - k: max_k, - rank: Rank(1), - }); - - let n_lwe: usize = a.n().into(); - - for i in 0..a_size { - let data_lwe: &[i64] = a.data.at(0, i); - glwe_in.data.at_mut(0, i)[0] = data_lwe[0]; - glwe_in.data.at_mut(1, i)[..n_lwe].copy_from_slice(&data_lwe[1..]); - } - - glwe_out.keyswitch(module, &glwe_in, &ksk.0, scratch_1); - self.sample_extract(&glwe_out); - } -}
@@ -1,4 +1,9 @@
-mod gglwe_ct; -mod ggsw_ct; -mod glwe_ct; -mod lwe_ct; +mod gglwe; +mod ggsw; +mod glwe; +mod lwe; + +pub use gglwe::*; +pub use ggsw::*; +pub use glwe::*; +pub use lwe::*;
@@ -0,0 +1,319 @@
+use poulpy_hal::{ + api::{VecZnxCopy, VecZnxFillUniform}, + layouts::{ + Backend, Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, Module, ReaderFrom, WriterTo, ZnxInfos, + }, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToMut, GLWEInfos, LWEInfos, Rank, TorusPrecision, + compressed::{GLWECompressed, GLWEDecompress}, +}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::fmt; + +#[derive(PartialEq, Eq, Clone)] +pub struct GGLWECompressed<D: Data> { + pub(crate) data: MatZnx<D>, + pub(crate) base2k: Base2K, + pub(crate) k: TorusPrecision, + pub(crate) rank_out: Rank, + pub(crate) dsize: Dsize, + pub(crate) seed: Vec<[u8; 32]>, +} + +pub trait GGLWECompressedSeedMut { + fn seed_mut(&mut self) -> &mut Vec<[u8; 32]>; +} + +impl<D: DataMut> GGLWECompressedSeedMut for GGLWECompressed<D> { + fn seed_mut(&mut self) -> &mut Vec<[u8; 32]> { + &mut self.seed + } +} + +pub trait GGLWECompressedSeed { + fn seed(&self) -> &Vec<[u8; 32]>; +} + +impl<D: DataRef> GGLWECompressedSeed for GGLWECompressed<D> { + fn seed(&self) -> &Vec<[u8; 32]> { + &self.seed + } +} +impl<D: Data> LWEInfos for GGLWECompressed<D> { + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } + + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn size(&self) -> usize { + self.data.size() + } +} +impl<D: Data> GLWEInfos for GGLWECompressed<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data> GGLWEInfos for GGLWECompressed<D> { + fn rank_in(&self) -> Rank { + Rank(self.data.cols_in() as u32) + } + + fn rank_out(&self) -> Rank { + self.rank_out + } + + fn dsize(&self) -> Dsize { + self.dsize + } + + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) + } +} + +impl<D: DataRef> fmt::Debug for GGLWECompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for GGLWECompressed<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.data.fill_uniform(log_bound, source); + } +} + +impl<D: DataRef> fmt::Display for GGLWECompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "(GGLWECompressed: base2k={} k={} dsize={}) {}", + self.base2k.0, self.k.0, self.dsize.0, self.data + ) + } +} + +impl GGLWECompressed<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.rank_out(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, rank_out: Rank, dnum: Dnum, dsize: Dsize) -> Self { + let size: usize = k.0.div_ceil(base2k.0) as usize; + debug_assert!( + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + GGLWECompressed { + data: MatZnx::alloc( + n.into(), + dnum.into(), + rank_in.into(), + 1, + k.0.div_ceil(base2k.0) as usize, + ), + k, + base2k, + dsize, + rank_out, + seed: vec![[0u8; 32]; (dnum.0 * rank_in.0) as usize], + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize { + let size: usize = k.0.div_ceil(base2k.0) as usize; + debug_assert!( + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + MatZnx::bytes_of( + n.into(), + dnum.into(), + rank_in.into(), + 1, + k.0.div_ceil(base2k.0) as usize, + ) + } +} + +impl<D: DataRef> GGLWECompressed<D> { + pub(crate) fn at(&self, row: usize, col: usize) -> GLWECompressed<&[u8]> { + let rank_in: usize = self.rank_in().into(); + GLWECompressed { + data: self.data.at(row, col), + k: self.k, + base2k: self.base2k, + rank: self.rank_out, + seed: self.seed[rank_in * row + col], + } + } +} + +impl<D: DataMut> GGLWECompressed<D> { + pub(crate) fn at_mut(&mut self, row: usize, col: usize) -> GLWECompressed<&mut [u8]> { + let rank_in: usize = self.rank_in().into(); + GLWECompressed { + k: self.k, + base2k: self.base2k, + rank: self.rank_out, + data: self.data.at_mut(row, col), + seed: self.seed[rank_in * row + col], // Warning: value is copied and not borrow mut + } + } +} + +impl<D: DataMut> ReaderFrom for GGLWECompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); + self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); + self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); + self.rank_out = Rank(reader.read_u32::<LittleEndian>()?); + let seed_len: u32 = reader.read_u32::<LittleEndian>()?; + self.seed = vec![[0u8; 32]; seed_len as usize]; + for s in &mut self.seed { + reader.read_exact(s)?; + } + self.data.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GGLWECompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u32::<LittleEndian>(self.k.into())?; + writer.write_u32::<LittleEndian>(self.base2k.into())?; + writer.write_u32::<LittleEndian>(self.dsize.into())?; + writer.write_u32::<LittleEndian>(self.rank_out.into())?; + writer.write_u32::<LittleEndian>(self.seed.len() as u32)?; + for s in &self.seed { + writer.write_all(s)?; + } + self.data.write_to(writer) + } +} + +pub trait GGLWEDecompress +where + Self: GLWEDecompress, +{ + fn decompress_gglwe<R, O>(&self, res: &mut R, other: &O) + where + R: GGLWEToMut, + O: GGLWECompressedToRef, + { + let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); + let other: &GGLWECompressed<&[u8]> = &other.to_ref(); + + assert_eq!(res.dsize(), other.dsize()); + assert!(res.dnum() <= other.dnum()); + + let rank_in: usize = res.rank_in().into(); + let dnum: usize = res.dnum().into(); + + for row_i in 0..dnum { + for col_i in 0..rank_in { + self.decompress_glwe(&mut res.at_mut(row_i, col_i), &other.at(row_i, col_i)); + } + } + } +} + +impl<B: Backend> GGLWEDecompress for Module<B> where Self: VecZnxFillUniform + VecZnxCopy {} + +impl<D: DataMut> GGLWE<D> { + pub fn decompress<O, M>(&mut self, module: &M, other: &O) + where + O: GGLWECompressedToRef, + M: GGLWEDecompress, + { + module.decompress_gglwe(self, other); + } +} + +pub trait GGLWECompressedToMut { + fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]>; +} + +impl<D: DataMut> GGLWECompressedToMut for GGLWECompressed<D> { + fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]> { + GGLWECompressed { + k: self.k(), + base2k: self.base2k(), + dsize: self.dsize(), + seed: self.seed.clone(), + rank_out: self.rank_out, + data: self.data.to_mut(), + } + } +} + +pub trait GGLWECompressedToRef { + fn to_ref(&self) -> GGLWECompressed<&[u8]>; +} + +impl<D: DataRef> GGLWECompressedToRef for GGLWECompressed<D> { + fn to_ref(&self) -> GGLWECompressed<&[u8]> { + GGLWECompressed { + k: self.k(), + base2k: self.base2k(), + dsize: self.dsize(), + seed: self.seed.clone(), + rank_out: self.rank_out, + data: self.data.to_ref(), + } + } +}
@@ -1,133 +0,0 @@
-use poulpy_hal::{ - api::{VecZnxCopy, VecZnxFillUniform}, - layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, - source::Source, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKey, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, - compressed::{Decompress, GGLWESwitchingKeyCompressed}, -}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::fmt; - -#[derive(PartialEq, Eq, Clone)] -pub struct GGLWEAutomorphismKeyCompressed<D: Data> { - pub(crate) key: GGLWESwitchingKeyCompressed<D>, - pub(crate) p: i64, -} - -impl<D: Data> LWEInfos for GGLWEAutomorphismKeyCompressed<D> { - fn n(&self) -> Degree { - self.key.n() - } - - fn base2k(&self) -> Base2K { - self.key.base2k() - } - - fn k(&self) -> TorusPrecision { - self.key.k() - } - - fn size(&self) -> usize { - self.key.size() - } -} -impl<D: Data> GLWEInfos for GGLWEAutomorphismKeyCompressed<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data> GGLWEInfos for GGLWEAutomorphismKeyCompressed<D> { - fn rank_in(&self) -> Rank { - self.key.rank_in() - } - - fn rank_out(&self) -> Rank { - self.key.rank_out() - } - - fn dsize(&self) -> Dsize { - self.key.dsize() - } - - fn dnum(&self) -> Dnum { - self.key.dnum() - } -} - -impl<D: DataRef> fmt::Debug for GGLWEAutomorphismKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for GGLWEAutomorphismKeyCompressed<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.key.fill_uniform(log_bound, source); - } -} - -impl<D: DataRef> fmt::Display for GGLWEAutomorphismKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "(AutomorphismKeyCompressed: p={}) {}", self.p, self.key) - } -} - -impl GGLWEAutomorphismKeyCompressed<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - debug_assert_eq!(infos.rank_in(), infos.rank_out()); - Self { - key: GGLWESwitchingKeyCompressed::alloc(infos), - p: 0, - } - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { - Self { - key: GGLWESwitchingKeyCompressed::alloc_with(n, base2k, k, rank, rank, dnum, dsize), - p: 0, - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - debug_assert_eq!(infos.rank_in(), infos.rank_out()); - GGLWESwitchingKeyCompressed::alloc_bytes(infos) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { - GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rank, dnum, dsize) - } -} - -impl<D: DataMut> ReaderFrom for GGLWEAutomorphismKeyCompressed<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.p = reader.read_u64::<LittleEndian>()? as i64; - self.key.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GGLWEAutomorphismKeyCompressed<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u64::<LittleEndian>(self.p as u64)?; - self.key.write_to(writer) - } -} - -impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, GGLWEAutomorphismKeyCompressed<DR>> for GGLWEAutomorphismKey<D> -where - Module<B>: VecZnxFillUniform + VecZnxCopy, -{ - fn decompress(&mut self, module: &Module<B>, other: &GGLWEAutomorphismKeyCompressed<DR>) { - self.key.decompress(module, &other.key); - self.p = other.p; - } -}
@@ -1,291 +0,0 @@
-use poulpy_hal::{ - api::{VecZnxCopy, VecZnxFillUniform}, - layouts::{Backend, Data, DataMut, DataRef, FillUniform, MatZnx, Module, ReaderFrom, WriterTo, ZnxInfos}, - source::Source, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWECiphertext, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, - compressed::{Decompress, GLWECiphertextCompressed}, -}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::fmt; - -#[derive(PartialEq, Eq, Clone)] -pub struct GGLWECiphertextCompressed<D: Data> { - pub(crate) data: MatZnx<D>, - pub(crate) base2k: Base2K, - pub(crate) k: TorusPrecision, - pub(crate) rank_out: Rank, - pub(crate) dsize: Dsize, - pub(crate) seed: Vec<[u8; 32]>, -} - -impl<D: Data> LWEInfos for GGLWECiphertextCompressed<D> { - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn size(&self) -> usize { - self.data.size() - } -} -impl<D: Data> GLWEInfos for GGLWECiphertextCompressed<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data> GGLWEInfos for GGLWECiphertextCompressed<D> { - fn rank_in(&self) -> Rank { - Rank(self.data.cols_in() as u32) - } - - fn rank_out(&self) -> Rank { - self.rank_out - } - - fn dsize(&self) -> Dsize { - self.dsize - } - - fn dnum(&self) -> Dnum { - Dnum(self.data.rows() as u32) - } -} - -impl<D: DataRef> fmt::Debug for GGLWECiphertextCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for GGLWECiphertextCompressed<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.data.fill_uniform(log_bound, source); - } -} - -impl<D: DataRef> fmt::Display for GGLWECiphertextCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "(GGLWECiphertextCompressed: base2k={} k={} dsize={}) {}", - self.base2k.0, self.k.0, self.dsize.0, self.data - ) - } -} - -impl GGLWECiphertextCompressed<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - Self::alloc_with( - infos.n(), - infos.base2k(), - infos.k(), - infos.rank_in(), - infos.rank_out(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_with( - n: Degree, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - rank_out: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> Self { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - Self { - data: MatZnx::alloc( - n.into(), - dnum.into(), - rank_in.into(), - 1, - k.0.div_ceil(base2k.0) as usize, - ), - k, - base2k, - dsize, - rank_out, - seed: vec![[0u8; 32]; (dnum.0 * rank_in.0) as usize], - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - Self::alloc_bytes_with( - infos.n(), - infos.base2k(), - infos.k(), - infos.rank_in(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - MatZnx::alloc_bytes( - n.into(), - dnum.into(), - rank_in.into(), - 1, - k.0.div_ceil(base2k.0) as usize, - ) - } -} - -impl<D: DataRef> GGLWECiphertextCompressed<D> { - pub(crate) fn at(&self, row: usize, col: usize) -> GLWECiphertextCompressed<&[u8]> { - let rank_in: usize = self.rank_in().into(); - GLWECiphertextCompressed { - data: self.data.at(row, col), - k: self.k, - base2k: self.base2k, - rank: self.rank_out, - seed: self.seed[rank_in * row + col], - } - } -} - -impl<D: DataMut> GGLWECiphertextCompressed<D> { - pub(crate) fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertextCompressed<&mut [u8]> { - let rank_in: usize = self.rank_in().into(); - GLWECiphertextCompressed { - k: self.k, - base2k: self.base2k, - rank: self.rank_out, - data: self.data.at_mut(row, col), - seed: self.seed[rank_in * row + col], // Warning: value is copied and not borrow mut - } - } -} - -impl<D: DataMut> ReaderFrom for GGLWECiphertextCompressed<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); - self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); - self.rank_out = Rank(reader.read_u32::<LittleEndian>()?); - let seed_len: u32 = reader.read_u32::<LittleEndian>()?; - self.seed = vec![[0u8; 32]; seed_len as usize]; - for s in &mut self.seed { - reader.read_exact(s)?; - } - self.data.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GGLWECiphertextCompressed<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u32::<LittleEndian>(self.k.into())?; - writer.write_u32::<LittleEndian>(self.base2k.into())?; - writer.write_u32::<LittleEndian>(self.dsize.into())?; - writer.write_u32::<LittleEndian>(self.rank_out.into())?; - writer.write_u32::<LittleEndian>(self.seed.len() as u32)?; - for s in &self.seed { - writer.write_all(s)?; - } - self.data.write_to(writer) - } -} - -impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GGLWECiphertextCompressed<DR>> for GGLWECiphertext<D> -where - Module<B>: VecZnxFillUniform + VecZnxCopy, -{ - fn decompress(&mut self, module: &Module<B>, other: &GGLWECiphertextCompressed<DR>) { - #[cfg(debug_assertions)] - { - assert_eq!( - self.n(), - other.n(), - "invalid receiver: self.n()={} != other.n()={}", - self.n(), - other.n() - ); - assert_eq!( - self.size(), - other.size(), - "invalid receiver: self.size()={} != other.size()={}", - self.size(), - other.size() - ); - assert_eq!( - self.rank_in(), - other.rank_in(), - "invalid receiver: self.rank_in()={} != other.rank_in()={}", - self.rank_in(), - other.rank_in() - ); - assert_eq!( - self.rank_out(), - other.rank_out(), - "invalid receiver: self.rank_out()={} != other.rank_out()={}", - self.rank_out(), - other.rank_out() - ); - - assert_eq!( - self.dnum(), - other.dnum(), - "invalid receiver: self.dnum()={} != other.dnum()={}", - self.dnum(), - other.dnum() - ); - } - - let rank_in: usize = self.rank_in().into(); - let dnum: usize = self.dnum().into(); - - (0..rank_in).for_each(|col_i| { - (0..dnum).for_each(|row_i| { - self.at_mut(row_i, col_i) - .decompress(module, &other.at(row_i, col_i)); - }); - }); - } -}
@@ -1,149 +0,0 @@
-use poulpy_hal::{ - api::{VecZnxCopy, VecZnxFillUniform}, - layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, - source::Source, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision, - compressed::{Decompress, GGLWECiphertextCompressed}, -}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::fmt; - -#[derive(PartialEq, Eq, Clone)] -pub struct GGLWESwitchingKeyCompressed<D: Data> { - pub(crate) key: GGLWECiphertextCompressed<D>, - pub(crate) sk_in_n: usize, // Degree of sk_in - pub(crate) sk_out_n: usize, // Degree of sk_out -} - -impl<D: Data> LWEInfos for GGLWESwitchingKeyCompressed<D> { - fn n(&self) -> Degree { - self.key.n() - } - - fn base2k(&self) -> Base2K { - self.key.base2k() - } - - fn k(&self) -> TorusPrecision { - self.key.k() - } - - fn size(&self) -> usize { - self.key.size() - } -} -impl<D: Data> GLWEInfos for GGLWESwitchingKeyCompressed<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data> GGLWEInfos for GGLWESwitchingKeyCompressed<D> { - fn rank_in(&self) -> Rank { - self.key.rank_in() - } - - fn rank_out(&self) -> Rank { - self.key.rank_out() - } - - fn dsize(&self) -> Dsize { - self.key.dsize() - } - - fn dnum(&self) -> Dnum { - self.key.dnum() - } -} - -impl<D: DataRef> fmt::Debug for GGLWESwitchingKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for GGLWESwitchingKeyCompressed<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.key.fill_uniform(log_bound, source); - } -} - -impl<D: DataRef> fmt::Display for GGLWESwitchingKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "(GLWESwitchingKeyCompressed: sk_in_n={} sk_out_n={}) {}", - self.sk_in_n, self.sk_out_n, self.key.data - ) - } -} - -impl GGLWESwitchingKeyCompressed<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - GGLWESwitchingKeyCompressed { - key: GGLWECiphertextCompressed::alloc(infos), - sk_in_n: 0, - sk_out_n: 0, - } - } - - pub fn alloc_with( - n: Degree, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - rank_out: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> Self { - GGLWESwitchingKeyCompressed { - key: GGLWECiphertextCompressed::alloc_with(n, base2k, k, rank_in, rank_out, dnum, dsize), - sk_in_n: 0, - sk_out_n: 0, - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - GGLWECiphertextCompressed::alloc_bytes(infos) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize { - GGLWECiphertextCompressed::alloc_bytes_with(n, base2k, k, rank_in, dnum, dsize) - } -} - -impl<D: DataMut> ReaderFrom for GGLWESwitchingKeyCompressed<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.sk_in_n = reader.read_u64::<LittleEndian>()? as usize; - self.sk_out_n = reader.read_u64::<LittleEndian>()? as usize; - self.key.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GGLWESwitchingKeyCompressed<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u64::<LittleEndian>(self.sk_in_n as u64)?; - writer.write_u64::<LittleEndian>(self.sk_out_n as u64)?; - self.key.write_to(writer) - } -} - -impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, GGLWESwitchingKeyCompressed<DR>> for GGLWESwitchingKey<D> -where - Module<B>: VecZnxFillUniform + VecZnxCopy, -{ - fn decompress(&mut self, module: &Module<B>, other: &GGLWESwitchingKeyCompressed<DR>) { - self.key.decompress(module, &other.key); - self.sk_in_n = other.sk_in_n; - self.sk_out_n = other.sk_out_n; - } -}
@@ -1,207 +0,0 @@
-use poulpy_hal::{ - api::{VecZnxCopy, VecZnxFillUniform}, - layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, - source::Source, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWETensorKey, GLWEInfos, LWEInfos, Rank, TorusPrecision, - compressed::{Decompress, GGLWESwitchingKeyCompressed}, -}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::fmt; - -#[derive(PartialEq, Eq, Clone)] -pub struct GGLWETensorKeyCompressed<D: Data> { - pub(crate) keys: Vec<GGLWESwitchingKeyCompressed<D>>, -} - -impl<D: Data> LWEInfos for GGLWETensorKeyCompressed<D> { - fn n(&self) -> Degree { - self.keys[0].n() - } - - fn base2k(&self) -> Base2K { - self.keys[0].base2k() - } - - fn k(&self) -> TorusPrecision { - self.keys[0].k() - } - fn size(&self) -> usize { - self.keys[0].size() - } -} -impl<D: Data> GLWEInfos for GGLWETensorKeyCompressed<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data> GGLWEInfos for GGLWETensorKeyCompressed<D> { - fn rank_in(&self) -> Rank { - self.rank_out() - } - - fn rank_out(&self) -> Rank { - self.keys[0].rank_out() - } - - fn dsize(&self) -> Dsize { - self.keys[0].dsize() - } - - fn dnum(&self) -> Dnum { - self.keys[0].dnum() - } -} - -impl<D: DataRef> fmt::Debug for GGLWETensorKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for GGLWETensorKeyCompressed<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.keys - .iter_mut() - .for_each(|key: &mut GGLWESwitchingKeyCompressed<D>| key.fill_uniform(log_bound, source)) - } -} - -impl<D: DataRef> fmt::Display for GGLWETensorKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "(GLWETensorKeyCompressed)",)?; - for (i, key) in self.keys.iter().enumerate() { - write!(f, "{i}: {key}")?; - } - Ok(()) - } -} - -impl GGLWETensorKeyCompressed<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWETensorKeyCompressed" - ); - Self::alloc_with( - infos.n(), - infos.base2k(), - infos.k(), - infos.rank_out(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { - let mut keys: Vec<GGLWESwitchingKeyCompressed<Vec<u8>>> = Vec::new(); - let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1); - (0..pairs).for_each(|_| { - keys.push(GGLWESwitchingKeyCompressed::alloc_with( - n, - base2k, - k, - Rank(1), - rank, - dnum, - dsize, - )); - }); - Self { keys } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWETensorKeyCompressed" - ); - let rank_out: usize = infos.rank_out().into(); - let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1); - pairs - * GGLWESwitchingKeyCompressed::alloc_bytes_with( - infos.n(), - infos.base2k(), - infos.k(), - Rank(1), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { - let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize; - pairs * GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, Rank(1), dnum, dsize) - } -} - -impl<D: DataMut> ReaderFrom for GGLWETensorKeyCompressed<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - let len: usize = reader.read_u64::<LittleEndian>()? as usize; - if self.keys.len() != len { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("self.keys.len()={} != read len={}", self.keys.len(), len), - )); - } - for key in &mut self.keys { - key.read_from(reader)?; - } - Ok(()) - } -} - -impl<D: DataRef> WriterTo for GGLWETensorKeyCompressed<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u64::<LittleEndian>(self.keys.len() as u64)?; - for key in &self.keys { - key.write_to(writer)?; - } - Ok(()) - } -} - -impl<D: DataMut> GGLWETensorKeyCompressed<D> { - pub(crate) fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKeyCompressed<D> { - if i > j { - std::mem::swap(&mut i, &mut j); - }; - let rank: usize = self.rank_out().into(); - &mut self.keys[i * rank + j - (i * (i + 1) / 2)] - } -} - -impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, GGLWETensorKeyCompressed<DR>> for GGLWETensorKey<D> -where - Module<B>: VecZnxFillUniform + VecZnxCopy, -{ - fn decompress(&mut self, module: &Module<B>, other: &GGLWETensorKeyCompressed<DR>) { - #[cfg(debug_assertions)] - { - assert_eq!( - self.keys.len(), - other.keys.len(), - "invalid receiver: self.keys.len()={} != other.keys.len()={}", - self.keys.len(), - other.keys.len() - ); - } - - self.keys - .iter_mut() - .zip(other.keys.iter()) - .for_each(|(a, b)| { - a.decompress(module, b); - }); - } -}
@@ -0,0 +1,307 @@
+use poulpy_hal::{ + layouts::{ + Backend, Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, Module, ReaderFrom, WriterTo, ZnxInfos, + }, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGSW, GGSWInfos, GGSWToMut, GLWEInfos, LWEInfos, Rank, TorusPrecision, + compressed::{GLWECompressed, GLWEDecompress}, +}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::fmt; + +#[derive(PartialEq, Eq, Clone)] +pub struct GGSWCompressed<D: Data> { + pub(crate) data: MatZnx<D>, + pub(crate) k: TorusPrecision, + pub(crate) base2k: Base2K, + pub(crate) dsize: Dsize, + pub(crate) rank: Rank, + pub(crate) seed: Vec<[u8; 32]>, +} + +pub trait GGSWCompressedSeedMut { + fn seed_mut(&mut self) -> &mut Vec<[u8; 32]>; +} + +impl<D: DataMut> GGSWCompressedSeedMut for GGSWCompressed<D> { + fn seed_mut(&mut self) -> &mut Vec<[u8; 32]> { + &mut self.seed + } +} + +pub trait GGSWCompressedSeed { + fn seed(&self) -> &Vec<[u8; 32]>; +} + +impl<D: DataRef> GGSWCompressedSeed for GGSWCompressed<D> { + fn seed(&self) -> &Vec<[u8; 32]> { + &self.seed + } +} + +impl<D: Data> LWEInfos for GGSWCompressed<D> { + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } + + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + fn size(&self) -> usize { + self.data.size() + } +} +impl<D: Data> GLWEInfos for GGSWCompressed<D> { + fn rank(&self) -> Rank { + self.rank + } +} + +impl<D: Data> GGSWInfos for GGSWCompressed<D> { + fn dsize(&self) -> Dsize { + self.dsize + } + + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) + } +} + +impl<D: DataRef> fmt::Debug for GGSWCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.data) + } +} + +impl<D: DataRef> fmt::Display for GGSWCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "(GGSWCompressed: base2k={} k={} dsize={}) {}", + self.base2k, self.k, self.dsize, self.data + ) + } +} + +impl<D: DataMut> FillUniform for GGSWCompressed<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.data.fill_uniform(log_bound, source); + } +} + +impl GGSWCompressed<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGSWInfos, + { + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { + let size: usize = k.0.div_ceil(base2k.0) as usize; + assert!( + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + GGSWCompressed { + data: MatZnx::alloc( + n.into(), + dnum.into(), + (rank + 1).into(), + 1, + k.0.div_ceil(base2k.0) as usize, + ), + k, + base2k, + dsize, + rank, + seed: vec![[0u8; 32]; dnum.as_usize() * (rank.as_usize() + 1)], + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGSWInfos, + { + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { + let size: usize = k.0.div_ceil(base2k.0) as usize; + assert!( + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + MatZnx::bytes_of( + n.into(), + dnum.into(), + (rank + 1).into(), + 1, + k.0.div_ceil(base2k.0) as usize, + ) + } +} + +impl<D: DataRef> GGSWCompressed<D> { + pub fn at(&self, row: usize, col: usize) -> GLWECompressed<&[u8]> { + let rank: usize = self.rank().into(); + GLWECompressed { + data: self.data.at(row, col), + k: self.k, + base2k: self.base2k, + rank: self.rank, + seed: self.seed[row * (rank + 1) + col], + } + } +} + +impl<D: DataMut> GGSWCompressed<D> { + pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECompressed<&mut [u8]> { + let rank: usize = self.rank().into(); + GLWECompressed { + data: self.data.at_mut(row, col), + k: self.k, + base2k: self.base2k, + rank: self.rank, + seed: self.seed[row * (rank + 1) + col], + } + } +} + +impl<D: DataMut> ReaderFrom for GGSWCompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); + self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); + self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); + self.rank = Rank(reader.read_u32::<LittleEndian>()?); + let seed_len: usize = reader.read_u32::<LittleEndian>()? as usize; + self.seed = vec![[0u8; 32]; seed_len]; + for s in &mut self.seed { + reader.read_exact(s)?; + } + self.data.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GGSWCompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u32::<LittleEndian>(self.k.into())?; + writer.write_u32::<LittleEndian>(self.base2k.into())?; + writer.write_u32::<LittleEndian>(self.dsize.into())?; + writer.write_u32::<LittleEndian>(self.rank.into())?; + writer.write_u32::<LittleEndian>(self.seed.len() as u32)?; + for s in &self.seed { + writer.write_all(s)?; + } + self.data.write_to(writer) + } +} + +pub trait GGSWDecompress +where + Self: GLWEDecompress, +{ + fn decompress_ggsw<R, O>(&self, res: &mut R, other: &O) + where + R: GGSWToMut, + O: GGSWCompressedToRef, + { + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + let other: &GGSWCompressed<&[u8]> = &other.to_ref(); + + assert_eq!(res.rank(), other.rank()); + let dnum: usize = res.dnum().into(); + let rank: usize = res.rank().into(); + + for row_i in 0..dnum { + for col_j in 0..rank + 1 { + self.decompress_glwe(&mut res.at_mut(row_i, col_j), &other.at(row_i, col_j)); + } + } + } +} + +impl<B: Backend> GGSWDecompress for Module<B> where Self: GLWEDecompress {} + +impl<D: DataMut> GGSW<D> { + pub fn decompress<O, M>(&mut self, module: &M, other: &O) + where + O: GGSWCompressedToRef, + M: GGSWDecompress, + { + module.decompress_ggsw(self, other); + } +} + +pub trait GGSWCompressedToMut { + fn to_mut(&mut self) -> GGSWCompressed<&mut [u8]>; +} + +impl<D: DataMut> GGSWCompressedToMut for GGSWCompressed<D> { + fn to_mut(&mut self) -> GGSWCompressed<&mut [u8]> { + GGSWCompressed { + k: self.k(), + base2k: self.base2k(), + dsize: self.dsize(), + rank: self.rank(), + seed: self.seed.clone(), + data: self.data.to_mut(), + } + } +} + +pub trait GGSWCompressedToRef { + fn to_ref(&self) -> GGSWCompressed<&[u8]>; +} + +impl<D: DataRef> GGSWCompressedToRef for GGSWCompressed<D> { + fn to_ref(&self) -> GGSWCompressed<&[u8]> { + GGSWCompressed { + k: self.k(), + base2k: self.base2k(), + dsize: self.dsize(), + rank: self.rank(), + seed: self.seed.clone(), + data: self.data.to_ref(), + } + } +}
@@ -1,237 +0,0 @@
-use poulpy_hal::{ - api::{VecZnxCopy, VecZnxFillUniform}, - layouts::{Backend, Data, DataMut, DataRef, FillUniform, MatZnx, Module, ReaderFrom, WriterTo, ZnxInfos}, - source::Source, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, - compressed::{Decompress, GLWECiphertextCompressed}, -}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::fmt; - -#[derive(PartialEq, Eq, Clone)] -pub struct GGSWCiphertextCompressed<D: Data> { - pub(crate) data: MatZnx<D>, - pub(crate) k: TorusPrecision, - pub(crate) base2k: Base2K, - pub(crate) dsize: Dsize, - pub(crate) rank: Rank, - pub(crate) seed: Vec<[u8; 32]>, -} - -impl<D: Data> LWEInfos for GGSWCiphertextCompressed<D> { - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - fn size(&self) -> usize { - self.data.size() - } -} -impl<D: Data> GLWEInfos for GGSWCiphertextCompressed<D> { - fn rank(&self) -> Rank { - self.rank - } -} - -impl<D: Data> GGSWInfos for GGSWCiphertextCompressed<D> { - fn dsize(&self) -> Dsize { - self.dsize - } - - fn dnum(&self) -> Dnum { - Dnum(self.data.rows() as u32) - } -} - -impl<D: DataRef> fmt::Debug for GGSWCiphertextCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.data) - } -} - -impl<D: DataRef> fmt::Display for GGSWCiphertextCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "(GGSWCiphertextCompressed: base2k={} k={} dsize={}) {}", - self.base2k, self.k, self.dsize, self.data - ) - } -} - -impl<D: DataMut> FillUniform for GGSWCiphertextCompressed<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.data.fill_uniform(log_bound, source); - } -} - -impl GGSWCiphertextCompressed<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGSWInfos, - { - Self::alloc_with( - infos.n(), - infos.base2k(), - infos.k(), - infos.rank(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - Self { - data: MatZnx::alloc( - n.into(), - dnum.into(), - (rank + 1).into(), - 1, - k.0.div_ceil(base2k.0) as usize, - ), - k, - base2k, - dsize, - rank, - seed: Vec::new(), - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGSWInfos, - { - Self::alloc_bytes_with( - infos.n(), - infos.base2k(), - infos.k(), - infos.rank(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - MatZnx::alloc_bytes( - n.into(), - dnum.into(), - (rank + 1).into(), - 1, - k.0.div_ceil(base2k.0) as usize, - ) - } -} - -impl<D: DataRef> GGSWCiphertextCompressed<D> { - pub fn at(&self, row: usize, col: usize) -> GLWECiphertextCompressed<&[u8]> { - let rank: usize = self.rank().into(); - GLWECiphertextCompressed { - data: self.data.at(row, col), - k: self.k, - base2k: self.base2k, - rank: self.rank, - seed: self.seed[row * (rank + 1) + col], - } - } -} - -impl<D: DataMut> GGSWCiphertextCompressed<D> { - pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertextCompressed<&mut [u8]> { - let rank: usize = self.rank().into(); - GLWECiphertextCompressed { - data: self.data.at_mut(row, col), - k: self.k, - base2k: self.base2k, - rank: self.rank, - seed: self.seed[row * (rank + 1) + col], - } - } -} - -impl<D: DataMut> ReaderFrom for GGSWCiphertextCompressed<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); - self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); - self.rank = Rank(reader.read_u32::<LittleEndian>()?); - let seed_len: usize = reader.read_u32::<LittleEndian>()? as usize; - self.seed = vec![[0u8; 32]; seed_len]; - for s in &mut self.seed { - reader.read_exact(s)?; - } - self.data.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GGSWCiphertextCompressed<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u32::<LittleEndian>(self.k.into())?; - writer.write_u32::<LittleEndian>(self.base2k.into())?; - writer.write_u32::<LittleEndian>(self.dsize.into())?; - writer.write_u32::<LittleEndian>(self.rank.into())?; - writer.write_u32::<LittleEndian>(self.seed.len() as u32)?; - for s in &self.seed { - writer.write_all(s)?; - } - self.data.write_to(writer) - } -} - -impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GGSWCiphertextCompressed<DR>> for GGSWCiphertext<D> -where - Module<B>: VecZnxFillUniform + VecZnxCopy, -{ - fn decompress(&mut self, module: &Module<B>, other: &GGSWCiphertextCompressed<DR>) { - #[cfg(debug_assertions)] - { - assert_eq!(self.rank(), other.rank()) - } - - let dnum: usize = self.dnum().into(); - let rank: usize = self.rank().into(); - (0..dnum).for_each(|row_i| { - (0..rank + 1).for_each(|col_j| { - self.at_mut(row_i, col_j) - .decompress(module, &other.at(row_i, col_j)); - }); - }); - } -}
@@ -0,0 +1,218 @@
+use poulpy_hal::{ + api::{VecZnxCopy, VecZnxFillUniform}, + layouts::{ + Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo, ZnxInfos, + }, + source::Source, +}; + +use crate::layouts::{Base2K, Degree, GLWE, GLWEInfos, GLWEToMut, GetDegree, LWEInfos, Rank, SetGLWEInfos, TorusPrecision}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::fmt; + +#[derive(PartialEq, Eq, Clone)] +pub struct GLWECompressed<D: Data> { + pub(crate) data: VecZnx<D>, + pub(crate) base2k: Base2K, + pub(crate) k: TorusPrecision, + pub(crate) rank: Rank, + pub(crate) seed: [u8; 32], +} + +pub trait GLWECompressedSeedMut { + fn seed_mut(&mut self) -> &mut [u8; 32]; +} + +impl<D: DataMut> GLWECompressedSeedMut for GLWECompressed<D> { + fn seed_mut(&mut self) -> &mut [u8; 32] { + &mut self.seed + } +} + +pub trait GLWECompressedSeed { + fn seed(&self) -> &[u8; 32]; +} + +impl<D: DataRef> GLWECompressedSeed for GLWECompressed<D> { + fn seed(&self) -> &[u8; 32] { + &self.seed + } +} + +impl<D: Data> LWEInfos for GLWECompressed<D> { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn size(&self) -> usize { + self.data.size() + } + + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } +} +impl<D: Data> GLWEInfos for GLWECompressed<D> { + fn rank(&self) -> Rank { + self.rank + } +} + +impl<D: DataRef> fmt::Debug for GLWECompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataRef> fmt::Display for GLWECompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "GLWECompressed: base2k={} k={} rank={} seed={:?}: {}", + self.base2k(), + self.k(), + self.rank(), + self.seed, + self.data + ) + } +} + +impl<D: DataMut> FillUniform for GLWECompressed<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.data.fill_uniform(log_bound, source); + } +} + +impl GLWECompressed<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GLWEInfos, + { + Self::alloc(infos.n(), infos.base2k(), infos.k(), infos.rank()) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self { + GLWECompressed { + data: VecZnx::alloc(n.into(), 1, k.0.div_ceil(base2k.0) as usize), + base2k, + k, + rank, + seed: [0u8; 32], + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GLWEInfos, + { + Self::bytes_of(infos.n(), infos.base2k(), infos.k()) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision) -> usize { + VecZnx::bytes_of(n.into(), 1, k.0.div_ceil(base2k.0) as usize) + } +} + +impl<D: DataMut> ReaderFrom for GLWECompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); + self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); + self.rank = Rank(reader.read_u32::<LittleEndian>()?); + reader.read_exact(&mut self.seed)?; + self.data.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GLWECompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u32::<LittleEndian>(self.k.into())?; + writer.write_u32::<LittleEndian>(self.base2k.into())?; + writer.write_u32::<LittleEndian>(self.rank.into())?; + writer.write_all(&self.seed)?; + self.data.write_to(writer) + } +} + +pub trait GLWEDecompress +where + Self: GetDegree + VecZnxFillUniform + VecZnxCopy, +{ + fn decompress_glwe<R, O>(&self, res: &mut R, other: &O) + where + R: GLWEToMut + SetGLWEInfos, + O: GLWECompressedToRef + GLWEInfos, + { + { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let other: &GLWECompressed<&[u8]> = &other.to_ref(); + assert_eq!( + res.n(), + self.ring_degree(), + "invalid receiver: res.n()={} != other.n()={}", + res.n(), + self.ring_degree() + ); + + assert_eq!(res.glwe_layout(), other.glwe_layout()); + + let mut source: Source = Source::new(other.seed); + + self.vec_znx_copy(&mut res.data, 0, &other.data, 0); + (1..(other.rank() + 1).into()).for_each(|i| { + self.vec_znx_fill_uniform(other.base2k.into(), &mut res.data, i, &mut source); + }); + } + + res.set_base2k(other.base2k()); + res.set_k(other.k()); + } +} + +impl<B: Backend> GLWEDecompress for Module<B> where Self: GetDegree + VecZnxFillUniform + VecZnxCopy {} + +impl<D: DataMut> GLWE<D> { + pub fn decompress<O, M>(&mut self, module: &M, other: &O) + where + O: GLWECompressedToRef + GLWEInfos, + M: GLWEDecompress, + { + module.decompress_glwe(self, other); + } +} + +pub trait GLWECompressedToRef { + fn to_ref(&self) -> GLWECompressed<&[u8]>; +} + +impl<D: DataRef> GLWECompressedToRef for GLWECompressed<D> { + fn to_ref(&self) -> GLWECompressed<&[u8]> { + GLWECompressed { + seed: self.seed, + base2k: self.base2k, + k: self.k, + rank: self.rank, + data: self.data.to_ref(), + } + } +} + +pub trait GLWECompressedToMut { + fn to_mut(&mut self) -> GLWECompressed<&mut [u8]>; +} + +impl<D: DataMut> GLWECompressedToMut for GLWECompressed<D> { + fn to_mut(&mut self) -> GLWECompressed<&mut [u8]> { + GLWECompressed { + seed: self.seed, + base2k: self.base2k, + k: self.k, + rank: self.rank, + data: self.data.to_mut(), + } + } +}
@@ -0,0 +1,192 @@
+use poulpy_hal::{ + layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWECompressed, GGLWECompressedSeedMut, GGLWECompressedToMut, GGLWECompressedToRef, + GGLWEDecompress, GGLWEInfos, GGLWEToMut, GLWEAutomorphismKey, GLWEDecompress, GLWEInfos, GetGaloisElement, LWEInfos, Rank, + SetGaloisElement, TorusPrecision, +}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::fmt; + +#[derive(PartialEq, Eq, Clone)] +pub struct GLWEAutomorphismKeyCompressed<D: Data> { + pub(crate) key: GGLWECompressed<D>, + pub(crate) p: i64, +} + +impl<D: DataRef> GetGaloisElement for GLWEAutomorphismKeyCompressed<D> { + fn p(&self) -> i64 { + self.p + } +} + +impl<D: Data> LWEInfos for GLWEAutomorphismKeyCompressed<D> { + fn n(&self) -> Degree { + self.key.n() + } + + fn base2k(&self) -> Base2K { + self.key.base2k() + } + + fn k(&self) -> TorusPrecision { + self.key.k() + } + + fn size(&self) -> usize { + self.key.size() + } +} + +impl<D: Data> GLWEInfos for GLWEAutomorphismKeyCompressed<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data> GGLWEInfos for GLWEAutomorphismKeyCompressed<D> { + fn rank_in(&self) -> Rank { + self.key.rank_in() + } + + fn rank_out(&self) -> Rank { + self.key.rank_out() + } + + fn dsize(&self) -> Dsize { + self.key.dsize() + } + + fn dnum(&self) -> Dnum { + self.key.dnum() + } +} + +impl<D: DataRef> fmt::Debug for GLWEAutomorphismKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for GLWEAutomorphismKeyCompressed<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.key.fill_uniform(log_bound, source); + } +} + +impl<D: DataRef> fmt::Display for GLWEAutomorphismKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(AutomorphismKeyCompressed: p={}) {}", self.p, self.key) + } +} + +impl GLWEAutomorphismKeyCompressed<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { + GLWEAutomorphismKeyCompressed { + key: GGLWECompressed::alloc(n, base2k, k, rank, rank, dnum, dsize), + p: 0, + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { + GGLWECompressed::bytes_of(n, base2k, k, rank, dnum, dsize) + } +} + +impl<D: DataMut> ReaderFrom for GLWEAutomorphismKeyCompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.p = reader.read_u64::<LittleEndian>()? as i64; + self.key.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GLWEAutomorphismKeyCompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u64::<LittleEndian>(self.p as u64)?; + self.key.write_to(writer) + } +} + +pub trait AutomorphismKeyDecompress +where + Self: GGLWEDecompress, +{ + fn decompress_automorphism_key<R, O>(&self, res: &mut R, other: &O) + where + R: GGLWEToMut + SetGaloisElement, + O: GGLWECompressedToRef + GetGaloisElement, + { + self.decompress_gglwe(res, other); + res.set_p(other.p()); + } +} + +impl<B: Backend> AutomorphismKeyDecompress for Module<B> where Self: GLWEDecompress {} + +impl<D: DataMut> GLWEAutomorphismKey<D> +where + Self: SetGaloisElement, +{ + pub fn decompress<O, M>(&mut self, module: &M, other: &O) + where + O: GGLWECompressedToRef + GetGaloisElement, + M: AutomorphismKeyDecompress, + { + module.decompress_automorphism_key(self, other); + } +} + +impl<D: DataRef> GGLWECompressedToRef for GLWEAutomorphismKeyCompressed<D> { + fn to_ref(&self) -> GGLWECompressed<&[u8]> { + self.key.to_ref() + } +} + +impl<D: DataMut> GGLWECompressedToMut for GLWEAutomorphismKeyCompressed<D> { + fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]> { + self.key.to_mut() + } +} + +impl<D: DataMut> GGLWECompressedSeedMut for GLWEAutomorphismKeyCompressed<D> { + fn seed_mut(&mut self) -> &mut Vec<[u8; 32]> { + &mut self.key.seed + } +} + +impl<D: DataMut> SetGaloisElement for GLWEAutomorphismKeyCompressed<D> { + fn set_p(&mut self, p: i64) { + self.p = p + } +}
@@ -1,178 +0,0 @@
-use poulpy_hal::{ - api::{VecZnxCopy, VecZnxFillUniform}, - layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, VecZnx, WriterTo, ZnxInfos}, - source::Source, -}; - -use crate::layouts::{Base2K, Degree, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision, compressed::Decompress}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::fmt; - -#[derive(PartialEq, Eq, Clone)] -pub struct GLWECiphertextCompressed<D: Data> { - pub(crate) data: VecZnx<D>, - pub(crate) base2k: Base2K, - pub(crate) k: TorusPrecision, - pub(crate) rank: Rank, - pub(crate) seed: [u8; 32], -} - -impl<D: Data> LWEInfos for GLWECiphertextCompressed<D> { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn size(&self) -> usize { - self.data.size() - } - - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } -} -impl<D: Data> GLWEInfos for GLWECiphertextCompressed<D> { - fn rank(&self) -> Rank { - self.rank - } -} - -impl<D: DataRef> fmt::Debug for GLWECiphertextCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataRef> fmt::Display for GLWECiphertextCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GLWECiphertextCompressed: base2k={} k={} rank={} seed={:?}: {}", - self.base2k(), - self.k(), - self.rank(), - self.seed, - self.data - ) - } -} - -impl<D: DataMut> FillUniform for GLWECiphertextCompressed<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.data.fill_uniform(log_bound, source); - } -} - -impl GLWECiphertextCompressed<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GLWEInfos, - { - Self::alloc_with(infos.n(), infos.base2k(), infos.k(), infos.rank()) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self { - Self { - data: VecZnx::alloc(n.into(), 1, k.0.div_ceil(base2k.0) as usize), - base2k, - k, - rank, - seed: [0u8; 32], - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GLWEInfos, - { - Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k()) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision) -> usize { - VecZnx::alloc_bytes(n.into(), 1, k.0.div_ceil(base2k.0) as usize) - } -} - -impl<D: DataMut> ReaderFrom for GLWECiphertextCompressed<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); - self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.rank = Rank(reader.read_u32::<LittleEndian>()?); - reader.read_exact(&mut self.seed)?; - self.data.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GLWECiphertextCompressed<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u32::<LittleEndian>(self.k.into())?; - writer.write_u32::<LittleEndian>(self.base2k.into())?; - writer.write_u32::<LittleEndian>(self.rank.into())?; - writer.write_all(&self.seed)?; - self.data.write_to(writer) - } -} - -impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GLWECiphertextCompressed<DR>> for GLWECiphertext<D> -where - Module<B>: VecZnxFillUniform + VecZnxCopy, -{ - fn decompress(&mut self, module: &Module<B>, other: &GLWECiphertextCompressed<DR>) { - #[cfg(debug_assertions)] - { - assert_eq!( - self.n(), - other.n(), - "invalid receiver: self.n()={} != other.n()={}", - self.n(), - other.n() - ); - assert_eq!( - self.size(), - other.size(), - "invalid receiver: self.size()={} != other.size()={}", - self.size(), - other.size() - ); - assert_eq!( - self.rank(), - other.rank(), - "invalid receiver: self.rank()={} != other.rank()={}", - self.rank(), - other.rank() - ); - } - - let mut source: Source = Source::new(other.seed); - self.decompress_internal(module, other, &mut source); - } -} - -impl<D: DataMut> GLWECiphertext<D> { - pub(crate) fn decompress_internal<DataOther, B: Backend>( - &mut self, - module: &Module<B>, - other: &GLWECiphertextCompressed<DataOther>, - source: &mut Source, - ) where - DataOther: DataRef, - Module<B>: VecZnxCopy + VecZnxFillUniform, - { - #[cfg(debug_assertions)] - { - assert_eq!(self.rank(), other.rank()); - debug_assert_eq!(self.size(), other.size()); - } - - module.vec_znx_copy(&mut self.data, 0, &other.data, 0); - (1..(other.rank() + 1).into()).for_each(|i| { - module.vec_znx_fill_uniform(other.base2k.into(), &mut self.data, i, source); - }); - - self.base2k = other.base2k; - self.k = other.k; - } -}
@@ -0,0 +1,201 @@
+use poulpy_hal::{ + layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWECompressedSeedMut, GGLWEInfos, GGLWEToMut, GLWEInfos, GLWESwitchingKey, + GLWESwitchingKeyDegrees, GLWESwitchingKeyDegreesMut, LWEInfos, Rank, TorusPrecision, + compressed::{GGLWECompressed, GGLWECompressedToMut, GGLWECompressedToRef, GGLWEDecompress}, +}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::fmt; + +#[derive(PartialEq, Eq, Clone)] +pub struct GLWESwitchingKeyCompressed<D: Data> { + pub(crate) key: GGLWECompressed<D>, + pub(crate) input_degree: Degree, // Degree of sk_in + pub(crate) output_degree: Degree, // Degree of sk_out +} + +impl<D: DataMut> GGLWECompressedSeedMut for GLWESwitchingKeyCompressed<D> { + fn seed_mut(&mut self) -> &mut Vec<[u8; 32]> { + &mut self.key.seed + } +} + +impl<D: DataRef> GLWESwitchingKeyDegrees for GLWESwitchingKeyCompressed<D> { + fn output_degree(&self) -> &Degree { + &self.output_degree + } + + fn input_degree(&self) -> &Degree { + &self.input_degree + } +} + +impl<D: DataMut> GLWESwitchingKeyDegreesMut for GLWESwitchingKeyCompressed<D> { + fn output_degree(&mut self) -> &mut Degree { + &mut self.output_degree + } + + fn input_degree(&mut self) -> &mut Degree { + &mut self.input_degree + } +} + +impl<D: Data> LWEInfos for GLWESwitchingKeyCompressed<D> { + fn n(&self) -> Degree { + self.key.n() + } + + fn base2k(&self) -> Base2K { + self.key.base2k() + } + + fn k(&self) -> TorusPrecision { + self.key.k() + } + + fn size(&self) -> usize { + self.key.size() + } +} +impl<D: Data> GLWEInfos for GLWESwitchingKeyCompressed<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data> GGLWEInfos for GLWESwitchingKeyCompressed<D> { + fn rank_in(&self) -> Rank { + self.key.rank_in() + } + + fn rank_out(&self) -> Rank { + self.key.rank_out() + } + + fn dsize(&self) -> Dsize { + self.key.dsize() + } + + fn dnum(&self) -> Dnum { + self.key.dnum() + } +} + +impl<D: DataRef> fmt::Debug for GLWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for GLWESwitchingKeyCompressed<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.key.fill_uniform(log_bound, source); + } +} + +impl<D: DataRef> fmt::Display for GLWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "(GLWESwitchingKeyCompressed: sk_in_n={} sk_out_n={}) {}", + self.input_degree, self.output_degree, self.key.data + ) + } +} + +impl GLWESwitchingKeyCompressed<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.rank_out(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, rank_out: Rank, dnum: Dnum, dsize: Dsize) -> Self { + GLWESwitchingKeyCompressed { + key: GGLWECompressed::alloc(n, base2k, k, rank_in, rank_out, dnum, dsize), + input_degree: Degree(0), + output_degree: Degree(0), + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + GGLWECompressed::bytes_of_from_infos(infos) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize +where { + GGLWECompressed::bytes_of(n, base2k, k, rank_in, dnum, dsize) + } +} + +impl<D: DataMut> ReaderFrom for GLWESwitchingKeyCompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.input_degree = Degree(reader.read_u32::<LittleEndian>()?); + self.output_degree = Degree(reader.read_u32::<LittleEndian>()?); + self.key.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GLWESwitchingKeyCompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u32::<LittleEndian>(self.input_degree.into())?; + writer.write_u32::<LittleEndian>(self.output_degree.into())?; + self.key.write_to(writer) + } +} + +pub trait GLWESwitchingKeyDecompress +where + Self: GGLWEDecompress, +{ + fn decompress_glwe_switching_key<R, O>(&self, res: &mut R, other: &O) + where + R: GGLWEToMut + GLWESwitchingKeyDegreesMut, + O: GGLWECompressedToRef + GLWESwitchingKeyDegrees, + { + self.decompress_gglwe(res, other); + + *res.input_degree() = *other.input_degree(); + *res.output_degree() = *other.output_degree(); + } +} + +impl<B: Backend> GLWESwitchingKeyDecompress for Module<B> where Self: GGLWEDecompress {} + +impl<D: DataMut> GLWESwitchingKey<D> { + pub fn decompress<O, M>(&mut self, module: &M, other: &O) + where + O: GGLWECompressedToRef + GLWESwitchingKeyDegrees, + M: GLWESwitchingKeyDecompress, + { + module.decompress_glwe_switching_key(self, other); + } +} + +impl<D: DataMut> GGLWECompressedToMut for GLWESwitchingKeyCompressed<D> { + fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]> { + self.key.to_mut() + } +} + +impl<D: DataRef> GGLWECompressedToRef for GLWESwitchingKeyCompressed<D> { + fn to_ref(&self) -> GGLWECompressed<&[u8]> { + self.key.to_ref() + } +}
@@ -0,0 +1,246 @@
+use poulpy_hal::{ + layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWECompressed, GGLWECompressedToMut, GGLWECompressedToRef, GGLWEDecompress, GGLWEInfos, + GLWEInfos, GLWETensorKey, GLWETensorKeyToMut, LWEInfos, Rank, TorusPrecision, +}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::fmt; + +#[derive(PartialEq, Eq, Clone)] +pub struct GLWETensorKeyCompressed<D: Data> { + pub(crate) keys: Vec<GGLWECompressed<D>>, +} + +impl<D: Data> LWEInfos for GLWETensorKeyCompressed<D> { + fn n(&self) -> Degree { + self.keys[0].n() + } + + fn base2k(&self) -> Base2K { + self.keys[0].base2k() + } + + fn k(&self) -> TorusPrecision { + self.keys[0].k() + } + fn size(&self) -> usize { + self.keys[0].size() + } +} +impl<D: Data> GLWEInfos for GLWETensorKeyCompressed<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data> GGLWEInfos for GLWETensorKeyCompressed<D> { + fn rank_in(&self) -> Rank { + self.rank_out() + } + + fn rank_out(&self) -> Rank { + self.keys[0].rank_out() + } + + fn dsize(&self) -> Dsize { + self.keys[0].dsize() + } + + fn dnum(&self) -> Dnum { + self.keys[0].dnum() + } +} + +impl<D: DataRef> fmt::Debug for GLWETensorKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for GLWETensorKeyCompressed<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.keys + .iter_mut() + .for_each(|key: &mut GGLWECompressed<D>| key.fill_uniform(log_bound, source)) + } +} + +impl<D: DataRef> fmt::Display for GLWETensorKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "(GLWETensorKeyCompressed)",)?; + for (i, key) in self.keys.iter().enumerate() { + write!(f, "{i}: {key}")?; + } + Ok(()) + } +} + +impl GLWETensorKeyCompressed<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { + let pairs: u32 = (((rank.as_u32() + 1) * rank.as_u32()) >> 1).max(1); + GLWETensorKeyCompressed { + keys: (0..pairs) + .map(|_| GGLWECompressed::alloc(n, base2k, k, Rank(1), rank, dnum, dsize)) + .collect(), + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { + let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize; + pairs * GGLWECompressed::bytes_of(n, base2k, k, Rank(1), dnum, dsize) + } +} + +impl<D: DataMut> ReaderFrom for GLWETensorKeyCompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + let len: usize = reader.read_u64::<LittleEndian>()? as usize; + if self.keys.len() != len { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("self.keys.len()={} != read len={}", self.keys.len(), len), + )); + } + for key in &mut self.keys { + key.read_from(reader)?; + } + Ok(()) + } +} + +impl<D: DataRef> WriterTo for GLWETensorKeyCompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u64::<LittleEndian>(self.keys.len() as u64)?; + for key in &self.keys { + key.write_to(writer)?; + } + Ok(()) + } +} + +pub trait GLWETensorKeyCompressedAtRef<D: DataRef> { + fn at(&self, i: usize, j: usize) -> &GGLWECompressed<D>; +} + +impl<D: DataRef> GLWETensorKeyCompressedAtRef<D> for GLWETensorKeyCompressed<D> { + fn at(&self, mut i: usize, mut j: usize) -> &GGLWECompressed<D> { + if i > j { + std::mem::swap(&mut i, &mut j); + }; + let rank: usize = self.rank_out().into(); + &self.keys[i * rank + j - (i * (i + 1) / 2)] + } +} + +pub trait GLWETensorKeyCompressedAtMut<D: DataMut> { + fn at_mut(&mut self, i: usize, j: usize) -> &mut GGLWECompressed<D>; +} + +impl<D: DataMut> GLWETensorKeyCompressedAtMut<D> for GLWETensorKeyCompressed<D> { + fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWECompressed<D> { + if i > j { + std::mem::swap(&mut i, &mut j); + }; + let rank: usize = self.rank_out().into(); + &mut self.keys[i * rank + j - (i * (i + 1) / 2)] + } +} + +pub trait GLWETensorKeyDecompress +where + Self: GGLWEDecompress, +{ + fn decompress_tensor_key<R, O>(&self, res: &mut R, other: &O) + where + R: GLWETensorKeyToMut, + O: GLWETensorKeyCompressedToRef, + { + let res: &mut GLWETensorKey<&mut [u8]> = &mut res.to_mut(); + let other: &GLWETensorKeyCompressed<&[u8]> = &other.to_ref(); + + assert_eq!( + res.keys.len(), + other.keys.len(), + "invalid receiver: res.keys.len()={} != other.keys.len()={}", + res.keys.len(), + other.keys.len() + ); + + for (a, b) in res.keys.iter_mut().zip(other.keys.iter()) { + self.decompress_gglwe(a, b); + } + } +} + +impl<B: Backend> GLWETensorKeyDecompress for Module<B> where Self: GGLWEDecompress {} + +impl<D: DataMut> GLWETensorKey<D> { + pub fn decompress<O, M>(&mut self, module: &M, other: &O) + where + O: GLWETensorKeyCompressedToRef, + M: GLWETensorKeyDecompress, + { + module.decompress_tensor_key(self, other); + } +} + +pub trait GLWETensorKeyCompressedToMut { + fn to_mut(&mut self) -> GLWETensorKeyCompressed<&mut [u8]>; +} + +impl<D: DataMut> GLWETensorKeyCompressedToMut for GLWETensorKeyCompressed<D> +where + GGLWECompressed<D>: GGLWECompressedToMut, +{ + fn to_mut(&mut self) -> GLWETensorKeyCompressed<&mut [u8]> { + GLWETensorKeyCompressed { + keys: self.keys.iter_mut().map(|c| c.to_mut()).collect(), + } + } +} + +pub trait GLWETensorKeyCompressedToRef { + fn to_ref(&self) -> GLWETensorKeyCompressed<&[u8]>; +} + +impl<D: DataRef> GLWETensorKeyCompressedToRef for GLWETensorKeyCompressed<D> +where + GGLWECompressed<D>: GGLWECompressedToRef, +{ + fn to_ref(&self) -> GLWETensorKeyCompressed<&[u8]> { + GLWETensorKeyCompressed { + keys: self.keys.iter().map(|c| c.to_ref()).collect(), + } + } +}
@@ -1,136 +0,0 @@
-use std::fmt; - -use poulpy_hal::{ - layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo}, - source::Source, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, compressed::GGLWESwitchingKeyCompressed, -}; - -#[derive(PartialEq, Eq, Clone)] -pub struct GLWEToLWESwitchingKeyCompressed<D: Data>(pub(crate) GGLWESwitchingKeyCompressed<D>); - -impl<D: Data> LWEInfos for GLWEToLWESwitchingKeyCompressed<D> { - fn base2k(&self) -> Base2K { - self.0.base2k() - } - - fn k(&self) -> TorusPrecision { - self.0.k() - } - - fn n(&self) -> Degree { - self.0.n() - } - fn size(&self) -> usize { - self.0.size() - } -} - -impl<D: Data> GLWEInfos for GLWEToLWESwitchingKeyCompressed<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data> GGLWEInfos for GLWEToLWESwitchingKeyCompressed<D> { - fn rank_in(&self) -> Rank { - self.0.rank_in() - } - - fn dsize(&self) -> Dsize { - self.0.dsize() - } - - fn rank_out(&self) -> Rank { - self.0.rank_out() - } - - fn dnum(&self) -> Dnum { - self.0.dnum() - } -} - -impl<D: DataRef> fmt::Debug for GLWEToLWESwitchingKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for GLWEToLWESwitchingKeyCompressed<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.0.fill_uniform(log_bound, source); - } -} - -impl<D: DataRef> fmt::Display for GLWEToLWESwitchingKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "(GLWEToLWESwitchingKeyCompressed) {}", self.0) - } -} - -impl<D: DataMut> ReaderFrom for GLWEToLWESwitchingKeyCompressed<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.0.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GLWEToLWESwitchingKeyCompressed<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - self.0.write_to(writer) - } -} - -impl GLWEToLWESwitchingKeyCompressed<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" - ); - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" - ); - Self(GGLWESwitchingKeyCompressed::alloc(infos)) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self { - Self(GGLWESwitchingKeyCompressed::alloc_with( - n, - base2k, - k, - rank_in, - Rank(1), - dnum, - Dsize(1), - )) - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" - ); - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" - ); - GGLWESwitchingKeyCompressed::alloc_bytes(infos) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_in: Rank) -> usize { - GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, rank_in, dnum, Dsize(1)) - } -}
@@ -0,0 +1,181 @@
+use std::fmt; + +use poulpy_hal::{ + layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWECompressed, GGLWECompressedToMut, GGLWECompressedToRef, GGLWEInfos, GGLWEToMut, GLWEInfos, + GLWESwitchingKeyDegrees, GLWESwitchingKeyDegreesMut, GLWEToLWESwitchingKey, LWEInfos, Rank, TorusPrecision, + compressed::{GLWESwitchingKeyCompressed, GLWESwitchingKeyDecompress}, +}; + +#[derive(PartialEq, Eq, Clone)] +pub struct GLWEToLWESwitchingKeyCompressed<D: Data>(pub(crate) GLWESwitchingKeyCompressed<D>); + +impl<D: Data> LWEInfos for GLWEToLWESwitchingKeyCompressed<D> { + fn base2k(&self) -> Base2K { + self.0.base2k() + } + + fn k(&self) -> TorusPrecision { + self.0.k() + } + + fn n(&self) -> Degree { + self.0.n() + } + fn size(&self) -> usize { + self.0.size() + } +} + +impl<D: Data> GLWEInfos for GLWEToLWESwitchingKeyCompressed<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data> GGLWEInfos for GLWEToLWESwitchingKeyCompressed<D> { + fn rank_in(&self) -> Rank { + self.0.rank_in() + } + + fn dsize(&self) -> Dsize { + self.0.dsize() + } + + fn rank_out(&self) -> Rank { + self.0.rank_out() + } + + fn dnum(&self) -> Dnum { + self.0.dnum() + } +} + +impl<D: DataRef> fmt::Debug for GLWEToLWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for GLWEToLWESwitchingKeyCompressed<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.0.fill_uniform(log_bound, source); + } +} + +impl<D: DataRef> fmt::Display for GLWEToLWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(GLWEToLWESwitchingKeyCompressed) {}", self.0) + } +} + +impl<D: DataMut> ReaderFrom for GLWEToLWESwitchingKeyCompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.0.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GLWEToLWESwitchingKeyCompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + self.0.write_to(writer) + } +} + +impl GLWEToLWESwitchingKeyCompressed<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" + ); + assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" + ); + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.dnum(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self { + GLWEToLWESwitchingKeyCompressed(GLWESwitchingKeyCompressed::alloc( + n, + base2k, + k, + rank_in, + Rank(1), + dnum, + Dsize(1), + )) + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" + ); + assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is unsupported for GLWEToLWESwitchingKeyCompressed" + ); + GLWESwitchingKeyCompressed::bytes_of_from_infos(infos) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_in: Rank) -> usize { + GLWESwitchingKeyCompressed::bytes_of(n, base2k, k, rank_in, dnum, Dsize(1)) + } +} + +pub trait GLWEToLWESwitchingKeyDecompress +where + Self: GLWESwitchingKeyDecompress, +{ + fn decompress_glwe_to_lwe_switching_key<R, O>(&self, res: &mut R, other: &O) + where + R: GGLWEToMut + GLWESwitchingKeyDegreesMut, + O: GGLWECompressedToRef + GLWESwitchingKeyDegrees, + { + self.decompress_glwe_switching_key(res, other); + } +} + +impl<B: Backend> GLWEToLWESwitchingKeyDecompress for Module<B> where Self: GLWESwitchingKeyDecompress {} + +impl<D: DataMut> GLWEToLWESwitchingKey<D> { + pub fn decompress<O, M>(&mut self, module: &M, other: &O) + where + O: GGLWECompressedToRef + GLWESwitchingKeyDegrees, + M: GLWEToLWESwitchingKeyDecompress, + { + module.decompress_glwe_to_lwe_switching_key(self, other); + } +} + +impl<D: DataRef> GGLWECompressedToRef for GLWEToLWESwitchingKeyCompressed<D> { + fn to_ref(&self) -> GGLWECompressed<&[u8]> { + self.0.to_ref() + } +} + +impl<D: DataMut> GGLWECompressedToMut for GLWEToLWESwitchingKeyCompressed<D> { + fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]> { + self.0.to_mut() + } +}
@@ -0,0 +1,182 @@
+use std::fmt; + +use poulpy_hal::{ + api::ZnFillUniform, + layouts::{ + Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo, Zn, ZnToMut, ZnToRef, ZnxInfos, ZnxView, + ZnxViewMut, + }, + source::Source, +}; + +use crate::layouts::{Base2K, Degree, LWE, LWEInfos, LWEToMut, TorusPrecision}; + +#[derive(PartialEq, Eq, Clone)] +pub struct LWECompressed<D: Data> { + pub(crate) data: Zn<D>, + pub(crate) k: TorusPrecision, + pub(crate) base2k: Base2K, + pub(crate) seed: [u8; 32], +} + +impl<D: Data> LWEInfos for LWECompressed<D> { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } + + fn size(&self) -> usize { + self.data.size() + } +} + +impl<D: DataRef> fmt::Debug for LWECompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataRef> fmt::Display for LWECompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "LWECompressed: base2k={} k={} seed={:?}: {}", + self.base2k(), + self.k(), + self.seed, + self.data + ) + } +} + +impl<D: DataMut> FillUniform for LWECompressed<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.data.fill_uniform(log_bound, source); + } +} + +impl LWECompressed<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: LWEInfos, + { + Self::alloc(infos.base2k(), infos.k()) + } + + pub fn alloc(base2k: Base2K, k: TorusPrecision) -> Self { + LWECompressed { + data: Zn::alloc(1, 1, k.0.div_ceil(base2k.0) as usize), + k, + base2k, + seed: [0u8; 32], + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: LWEInfos, + { + Self::bytes_of(infos.base2k(), infos.k()) + } + + pub fn bytes_of(base2k: Base2K, k: TorusPrecision) -> usize { + Zn::bytes_of(1, 1, k.0.div_ceil(base2k.0) as usize) + } +} + +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +impl<D: DataMut> ReaderFrom for LWECompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); + self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); + reader.read_exact(&mut self.seed)?; + self.data.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for LWECompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u32::<LittleEndian>(self.k.into())?; + writer.write_u32::<LittleEndian>(self.base2k.into())?; + writer.write_all(&self.seed)?; + self.data.write_to(writer) + } +} + +pub trait LWEDecompress +where + Self: ZnFillUniform, +{ + fn decompress_lwe<R, O>(&self, res: &mut R, other: &O) + where + R: LWEToMut, + O: LWECompressedToRef, + { + let res: &mut LWE<&mut [u8]> = &mut res.to_mut(); + let other: &LWECompressed<&[u8]> = &other.to_ref(); + + assert_eq!(res.lwe_layout(), other.lwe_layout()); + + let mut source: Source = Source::new(other.seed); + self.zn_fill_uniform( + res.n().into(), + other.base2k().into(), + &mut res.data, + 0, + &mut source, + ); + for i in 0..res.size() { + res.data.at_mut(0, i)[0] = other.data.at(0, i)[0]; + } + } +} + +impl<B: Backend> LWEDecompress for Module<B> where Self: ZnFillUniform {} + +impl<D: DataMut> LWE<D> { + pub fn decompress<O, M>(&mut self, module: &M, other: &O) + where + O: LWECompressedToRef, + M: LWEDecompress, + { + module.decompress_lwe(self, other); + } +} + +pub trait LWECompressedToRef { + fn to_ref(&self) -> LWECompressed<&[u8]>; +} + +impl<D: DataRef> LWECompressedToRef for LWECompressed<D> { + fn to_ref(&self) -> LWECompressed<&[u8]> { + LWECompressed { + k: self.k, + base2k: self.base2k, + seed: self.seed, + data: self.data.to_ref(), + } + } +} + +pub trait LWECompressedToMut { + fn to_mut(&mut self) -> LWECompressed<&mut [u8]>; +} + +impl<D: DataMut> LWECompressedToMut for LWECompressed<D> { + fn to_mut(&mut self) -> LWECompressed<&mut [u8]> { + LWECompressed { + k: self.k, + base2k: self.base2k, + seed: self.seed, + data: self.data.to_mut(), + } + } +}
@@ -1,129 +0,0 @@
-use std::fmt; - -use poulpy_hal::{ - api::ZnFillUniform, - layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo, Zn, ZnxInfos, ZnxView, ZnxViewMut}, - source::Source, -}; - -use crate::layouts::{Base2K, Degree, LWECiphertext, LWEInfos, TorusPrecision, compressed::Decompress}; - -#[derive(PartialEq, Eq, Clone)] -pub struct LWECiphertextCompressed<D: Data> { - pub(crate) data: Zn<D>, - pub(crate) k: TorusPrecision, - pub(crate) base2k: Base2K, - pub(crate) seed: [u8; 32], -} - -impl<D: Data> LWEInfos for LWECiphertextCompressed<D> { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - fn size(&self) -> usize { - self.data.size() - } -} - -impl<D: DataRef> fmt::Debug for LWECiphertextCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataRef> fmt::Display for LWECiphertextCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "LWECiphertextCompressed: base2k={} k={} seed={:?}: {}", - self.base2k(), - self.k(), - self.seed, - self.data - ) - } -} - -impl<D: DataMut> FillUniform for LWECiphertextCompressed<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.data.fill_uniform(log_bound, source); - } -} - -impl LWECiphertextCompressed<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: LWEInfos, - { - Self::alloc_with(infos.base2k(), infos.k()) - } - - pub fn alloc_with(base2k: Base2K, k: TorusPrecision) -> Self { - Self { - data: Zn::alloc(1, 1, k.0.div_ceil(base2k.0) as usize), - k, - base2k, - seed: [0u8; 32], - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: LWEInfos, - { - Self::alloc_bytes_with(infos.base2k(), infos.k()) - } - - pub fn alloc_bytes_with(base2k: Base2K, k: TorusPrecision) -> usize { - Zn::alloc_bytes(1, 1, k.0.div_ceil(base2k.0) as usize) - } -} - -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -impl<D: DataMut> ReaderFrom for LWECiphertextCompressed<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); - self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - reader.read_exact(&mut self.seed)?; - self.data.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for LWECiphertextCompressed<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u32::<LittleEndian>(self.k.into())?; - writer.write_u32::<LittleEndian>(self.base2k.into())?; - writer.write_all(&self.seed)?; - self.data.write_to(writer) - } -} - -impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, LWECiphertextCompressed<DR>> for LWECiphertext<D> -where - Module<B>: ZnFillUniform, -{ - fn decompress(&mut self, module: &Module<B>, other: &LWECiphertextCompressed<DR>) { - debug_assert_eq!(self.size(), other.size()); - let mut source: Source = Source::new(other.seed); - module.zn_fill_uniform( - self.n().into(), - other.base2k().into(), - &mut self.data, - 0, - &mut source, - ); - (0..self.size()).for_each(|i| { - self.data.at_mut(0, i)[0] = other.data.at(0, i)[0]; - }); - } -}
@@ -1,155 +0,0 @@
-use poulpy_hal::{ - api::{VecZnxCopy, VecZnxFillUniform}, - layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, - source::Source, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWESwitchingKey, Rank, TorusPrecision, - compressed::{Decompress, GGLWESwitchingKeyCompressed}, -}; -use std::fmt; - -#[derive(PartialEq, Eq, Clone)] -pub struct LWESwitchingKeyCompressed<D: Data>(pub(crate) GGLWESwitchingKeyCompressed<D>); - -impl<D: Data> LWEInfos for LWESwitchingKeyCompressed<D> { - fn base2k(&self) -> Base2K { - self.0.base2k() - } - - fn k(&self) -> TorusPrecision { - self.0.k() - } - - fn n(&self) -> Degree { - self.0.n() - } - fn size(&self) -> usize { - self.0.size() - } -} -impl<D: Data> GLWEInfos for LWESwitchingKeyCompressed<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data> GGLWEInfos for LWESwitchingKeyCompressed<D> { - fn dsize(&self) -> Dsize { - self.0.dsize() - } - - fn rank_in(&self) -> Rank { - self.0.rank_in() - } - - fn rank_out(&self) -> Rank { - self.0.rank_out() - } - - fn dnum(&self) -> Dnum { - self.0.dnum() - } -} - -impl<D: DataRef> fmt::Debug for LWESwitchingKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for LWESwitchingKeyCompressed<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.0.fill_uniform(log_bound, source); - } -} - -impl<D: DataRef> fmt::Display for LWESwitchingKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "(LWESwitchingKeyCompressed) {}", self.0) - } -} - -impl<D: DataMut> ReaderFrom for LWESwitchingKeyCompressed<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.0.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for LWESwitchingKeyCompressed<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - self.0.write_to(writer) - } -} - -impl LWESwitchingKeyCompressed<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for LWESwitchingKeyCompressed" - ); - debug_assert_eq!( - infos.rank_in().0, - 1, - "rank_in > 1 is not supported for LWESwitchingKeyCompressed" - ); - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is not supported for LWESwitchingKeyCompressed" - ); - Self(GGLWESwitchingKeyCompressed::alloc(infos)) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self { - Self(GGLWESwitchingKeyCompressed::alloc_with( - n, - base2k, - k, - Rank(1), - Rank(1), - dnum, - Dsize(1), - )) - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for LWESwitchingKey" - ); - debug_assert_eq!( - infos.rank_in().0, - 1, - "rank_in > 1 is not supported for LWESwitchingKey" - ); - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is not supported for LWESwitchingKey" - ); - GGLWESwitchingKeyCompressed::alloc_bytes(infos) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize { - GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, Rank(1), dnum, Dsize(1)) - } -} - -impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, LWESwitchingKeyCompressed<DR>> for LWESwitchingKey<D> -where - Module<B>: VecZnxFillUniform + VecZnxCopy, -{ - fn decompress(&mut self, module: &Module<B>, other: &LWESwitchingKeyCompressed<DR>) { - self.0.decompress(module, &other.0); - } -}
@@ -0,0 +1,183 @@
+use poulpy_hal::{ + layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWECompressed, GGLWECompressedToMut, GGLWECompressedToRef, GGLWEInfos, GGLWEToMut, GLWEInfos, + GLWESwitchingKeyDegrees, GLWESwitchingKeyDegreesMut, LWEInfos, LWESwitchingKey, Rank, TorusPrecision, + compressed::{GLWESwitchingKeyCompressed, GLWESwitchingKeyDecompress}, +}; +use std::fmt; + +#[derive(PartialEq, Eq, Clone)] +pub struct LWESwitchingKeyCompressed<D: Data>(pub(crate) GLWESwitchingKeyCompressed<D>); + +impl<D: Data> LWEInfos for LWESwitchingKeyCompressed<D> { + fn base2k(&self) -> Base2K { + self.0.base2k() + } + + fn k(&self) -> TorusPrecision { + self.0.k() + } + + fn n(&self) -> Degree { + self.0.n() + } + fn size(&self) -> usize { + self.0.size() + } +} +impl<D: Data> GLWEInfos for LWESwitchingKeyCompressed<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data> GGLWEInfos for LWESwitchingKeyCompressed<D> { + fn dsize(&self) -> Dsize { + self.0.dsize() + } + + fn rank_in(&self) -> Rank { + self.0.rank_in() + } + + fn rank_out(&self) -> Rank { + self.0.rank_out() + } + + fn dnum(&self) -> Dnum { + self.0.dnum() + } +} + +impl<D: DataRef> fmt::Debug for LWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for LWESwitchingKeyCompressed<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.0.fill_uniform(log_bound, source); + } +} + +impl<D: DataRef> fmt::Display for LWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(LWESwitchingKeyCompressed) {}", self.0) + } +} + +impl<D: DataMut> ReaderFrom for LWESwitchingKeyCompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.0.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for LWESwitchingKeyCompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + self.0.write_to(writer) + } +} + +impl LWESwitchingKeyCompressed<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for LWESwitchingKeyCompressed" + ); + assert_eq!( + infos.rank_in().0, + 1, + "rank_in > 1 is not supported for LWESwitchingKeyCompressed" + ); + assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is not supported for LWESwitchingKeyCompressed" + ); + Self::alloc(infos.n(), infos.base2k(), infos.k(), infos.dnum()) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self { + LWESwitchingKeyCompressed(GLWESwitchingKeyCompressed::alloc( + n, + base2k, + k, + Rank(1), + Rank(1), + dnum, + Dsize(1), + )) + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for LWESwitchingKeyCompressed" + ); + assert_eq!( + infos.rank_in().0, + 1, + "rank_in > 1 is not supported for LWESwitchingKeyCompressed" + ); + assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is not supported for LWESwitchingKeyCompressed" + ); + GLWESwitchingKeyCompressed::bytes_of_from_infos(infos) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize { + GLWESwitchingKeyCompressed::bytes_of(n, base2k, k, Rank(1), dnum, Dsize(1)) + } +} + +pub trait LWESwitchingKeyDecompress +where + Self: GLWESwitchingKeyDecompress, +{ + fn decompress_lwe_switching_key<R, O>(&self, res: &mut R, other: &O) + where + R: GGLWEToMut + GLWESwitchingKeyDegreesMut, + O: GGLWECompressedToRef + GLWESwitchingKeyDegrees, + { + self.decompress_glwe_switching_key(res, other); + } +} + +impl<B: Backend> LWESwitchingKeyDecompress for Module<B> where Self: GLWESwitchingKeyDecompress {} + +impl<D: DataMut> LWESwitchingKey<D> { + pub fn decompress<O, M>(&mut self, module: &M, other: &O) + where + O: GGLWECompressedToRef + GLWESwitchingKeyDegrees, + M: LWESwitchingKeyDecompress, + { + module.decompress_lwe_switching_key(self, other); + } +} + +impl<D: DataRef> GGLWECompressedToRef for LWESwitchingKeyCompressed<D> { + fn to_ref(&self) -> GGLWECompressed<&[u8]> { + self.0.to_ref() + } +} + +impl<D: DataMut> GGLWECompressedToMut for LWESwitchingKeyCompressed<D> { + fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]> { + self.0.to_mut() + } +}
@@ -1,145 +0,0 @@
-use poulpy_hal::{ - api::{VecZnxCopy, VecZnxFillUniform}, - layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, - source::Source, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWEToGLWESwitchingKey, Rank, TorusPrecision, - compressed::{Decompress, GGLWESwitchingKeyCompressed}, -}; -use std::fmt; - -#[derive(PartialEq, Eq, Clone)] -pub struct LWEToGLWESwitchingKeyCompressed<D: Data>(pub(crate) GGLWESwitchingKeyCompressed<D>); - -impl<D: Data> LWEInfos for LWEToGLWESwitchingKeyCompressed<D> { - fn n(&self) -> Degree { - self.0.n() - } - - fn base2k(&self) -> Base2K { - self.0.base2k() - } - - fn k(&self) -> TorusPrecision { - self.0.k() - } - fn size(&self) -> usize { - self.0.size() - } -} -impl<D: Data> GLWEInfos for LWEToGLWESwitchingKeyCompressed<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data> GGLWEInfos for LWEToGLWESwitchingKeyCompressed<D> { - fn dsize(&self) -> Dsize { - self.0.dsize() - } - - fn rank_in(&self) -> Rank { - self.0.rank_in() - } - - fn rank_out(&self) -> Rank { - self.0.rank_out() - } - - fn dnum(&self) -> Dnum { - self.0.dnum() - } -} - -impl<D: DataRef> fmt::Debug for LWEToGLWESwitchingKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for LWEToGLWESwitchingKeyCompressed<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.0.fill_uniform(log_bound, source); - } -} - -impl<D: DataRef> fmt::Display for LWEToGLWESwitchingKeyCompressed<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "(LWEToGLWESwitchingKeyCompressed) {}", self.0) - } -} - -impl<D: DataMut> ReaderFrom for LWEToGLWESwitchingKeyCompressed<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.0.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for LWEToGLWESwitchingKeyCompressed<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - self.0.write_to(writer) - } -} - -impl LWEToGLWESwitchingKeyCompressed<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for LWEToGLWESwitchingKeyCompressed" - ); - debug_assert_eq!( - infos.rank_in().0, - 1, - "rank_in > 1 is not supported for LWEToGLWESwitchingKeyCompressed" - ); - Self(GGLWESwitchingKeyCompressed::alloc(infos)) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self { - Self(GGLWESwitchingKeyCompressed::alloc_with( - n, - base2k, - k, - Rank(1), - rank_out, - dnum, - Dsize(1), - )) - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - debug_assert_eq!( - infos.rank_in().0, - 1, - "rank_in > 1 is not supported for LWEToGLWESwitchingKey" - ); - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for LWEToGLWESwitchingKey" - ); - GGLWESwitchingKeyCompressed::alloc_bytes(infos) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize { - GGLWESwitchingKeyCompressed::alloc_bytes_with(n, base2k, k, Rank(1), dnum, Dsize(1)) - } -} - -impl<D: DataMut, DR: DataRef, B: Backend> Decompress<B, LWEToGLWESwitchingKeyCompressed<DR>> for LWEToGLWESwitchingKey<D> -where - Module<B>: VecZnxFillUniform + VecZnxCopy, -{ - fn decompress(&mut self, module: &Module<B>, other: &LWEToGLWESwitchingKeyCompressed<DR>) { - self.0.decompress(module, &other.0); - } -}
@@ -0,0 +1,179 @@
+use poulpy_hal::{ + layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, WriterTo}, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWECompressed, GGLWECompressedToMut, GGLWECompressedToRef, GGLWEInfos, GGLWEToMut, GLWEInfos, + GLWESwitchingKeyDegrees, GLWESwitchingKeyDegreesMut, LWEInfos, LWEToGLWESwitchingKey, Rank, TorusPrecision, + compressed::{GLWESwitchingKeyCompressed, GLWESwitchingKeyDecompress}, +}; +use std::fmt; + +#[derive(PartialEq, Eq, Clone)] +pub struct LWEToGLWESwitchingKeyCompressed<D: Data>(pub(crate) GLWESwitchingKeyCompressed<D>); + +impl<D: Data> LWEInfos for LWEToGLWESwitchingKeyCompressed<D> { + fn n(&self) -> Degree { + self.0.n() + } + + fn base2k(&self) -> Base2K { + self.0.base2k() + } + + fn k(&self) -> TorusPrecision { + self.0.k() + } + fn size(&self) -> usize { + self.0.size() + } +} +impl<D: Data> GLWEInfos for LWEToGLWESwitchingKeyCompressed<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data> GGLWEInfos for LWEToGLWESwitchingKeyCompressed<D> { + fn dsize(&self) -> Dsize { + self.0.dsize() + } + + fn rank_in(&self) -> Rank { + self.0.rank_in() + } + + fn rank_out(&self) -> Rank { + self.0.rank_out() + } + + fn dnum(&self) -> Dnum { + self.0.dnum() + } +} + +impl<D: DataRef> fmt::Debug for LWEToGLWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for LWEToGLWESwitchingKeyCompressed<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.0.fill_uniform(log_bound, source); + } +} + +impl<D: DataRef> fmt::Display for LWEToGLWESwitchingKeyCompressed<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(LWEToGLWESwitchingKeyCompressed) {}", self.0) + } +} + +impl<D: DataMut> ReaderFrom for LWEToGLWESwitchingKeyCompressed<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.0.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for LWEToGLWESwitchingKeyCompressed<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + self.0.write_to(writer) + } +} + +impl LWEToGLWESwitchingKeyCompressed<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for LWEToGLWESwitchingKeyCompressed" + ); + assert_eq!( + infos.rank_in().0, + 1, + "rank_in > 1 is not supported for LWEToGLWESwitchingKeyCompressed" + ); + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_out(), + infos.dnum(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self { + LWEToGLWESwitchingKeyCompressed(GLWESwitchingKeyCompressed::alloc( + n, + base2k, + k, + Rank(1), + rank_out, + dnum, + Dsize(1), + )) + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for LWEToGLWESwitchingKeyCompressed" + ); + assert_eq!( + infos.rank_in().0, + 1, + "rank_in > 1 is not supported for LWEToGLWESwitchingKeyCompressed" + ); + GLWESwitchingKeyCompressed::bytes_of_from_infos(infos) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize { + GLWESwitchingKeyCompressed::bytes_of(n, base2k, k, Rank(1), dnum, Dsize(1)) + } +} + +pub trait LWEToGLWESwitchingKeyDecompress +where + Self: GLWESwitchingKeyDecompress, +{ + fn decompress_lwe_to_glwe_switching_key<R, O>(&self, res: &mut R, other: &O) + where + R: GGLWEToMut + GLWESwitchingKeyDegreesMut, + O: GGLWECompressedToRef + GLWESwitchingKeyDegrees, + { + self.decompress_glwe_switching_key(res, other); + } +} + +impl<B: Backend> LWEToGLWESwitchingKeyDecompress for Module<B> where Self: GLWESwitchingKeyDecompress {} + +impl<D: DataMut> LWEToGLWESwitchingKey<D> { + pub fn decompress<O, M>(&mut self, module: &M, other: &O) + where + O: GGLWECompressedToRef + GLWESwitchingKeyDegrees, + M: LWEToGLWESwitchingKeyDecompress, + { + module.decompress_lwe_to_glwe_switching_key(self, other); + } +} + +impl<D: DataRef> GGLWECompressedToRef for LWEToGLWESwitchingKeyCompressed<D> { + fn to_ref(&self) -> GGLWECompressed<&[u8]> { + self.0.to_ref() + } +} + +impl<D: DataMut> GGLWECompressedToMut for LWEToGLWESwitchingKeyCompressed<D> { + fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]> { + self.0.to_mut() + } +}
@@ -1,27 +1,21 @@
-mod gglwe_atk; -mod gglwe_ct; -mod gglwe_ksk; -mod gglwe_tsk; -mod ggsw_ct; -mod glwe_ct; -mod glwe_to_lwe_ksk; -mod lwe_ct; -mod lwe_ksk; -mod lwe_to_glwe_ksk; - -pub use gglwe_atk::*; -pub use gglwe_ct::*; -pub use gglwe_ksk::*; -pub use gglwe_tsk::*; -pub use ggsw_ct::*; -pub use glwe_ct::*; -pub use glwe_to_lwe_ksk::*; -pub use lwe_ct::*; -pub use lwe_ksk::*; -pub use lwe_to_glwe_ksk::*; - -use poulpy_hal::layouts::{Backend, Module}; +mod gglwe; +mod ggsw; +mod glwe; +mod glwe_automorphism_key; +mod glwe_switching_key; +mod glwe_tensor_key; +mod glwe_to_lwe_switching_key; +mod lwe; +mod lwe_switching_key; +mod lwe_to_glwe_switching_key; -pub trait Decompress<B: Backend, C> { - fn decompress(&mut self, module: &Module<B>, other: &C); -} +pub use gglwe::*; +pub use ggsw::*; +pub use glwe::*; +pub use glwe_automorphism_key::*; +pub use glwe_switching_key::*; +pub use glwe_tensor_key::*; +pub use glwe_to_lwe_switching_key::*; +pub use lwe::*; +pub use lwe_switching_key::*; +pub use lwe_to_glwe_switching_key::*;
@@ -0,0 +1,331 @@
+use poulpy_hal::{ + layouts::{Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, ReaderFrom, WriterTo, ZnxInfos}, + source::Source, +}; + +use crate::layouts::{Base2K, Degree, Dnum, Dsize, GLWE, GLWEInfos, LWEInfos, Rank, TorusPrecision}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +use std::fmt; + +pub trait GGLWEInfos +where + Self: GLWEInfos, +{ + fn dnum(&self) -> Dnum; + fn dsize(&self) -> Dsize; + fn rank_in(&self) -> Rank; + fn rank_out(&self) -> Rank; + fn gglwe_layout(&self) -> GGLWELayout { + GGLWELayout { + n: self.n(), + base2k: self.base2k(), + k: self.k(), + rank_in: self.rank_in(), + rank_out: self.rank_out(), + dsize: self.dsize(), + dnum: self.dnum(), + } + } +} + +pub trait SetGGLWEInfos { + fn set_dsize(&mut self, dsize: usize); +} + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub struct GGLWELayout { + pub n: Degree, + pub base2k: Base2K, + pub k: TorusPrecision, + pub rank_in: Rank, + pub rank_out: Rank, + pub dnum: Dnum, + pub dsize: Dsize, +} + +impl LWEInfos for GGLWELayout { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn n(&self) -> Degree { + self.n + } +} + +impl GLWEInfos for GGLWELayout { + fn rank(&self) -> Rank { + self.rank_out + } +} + +impl GGLWEInfos for GGLWELayout { + fn rank_in(&self) -> Rank { + self.rank_in + } + + fn dsize(&self) -> Dsize { + self.dsize + } + + fn rank_out(&self) -> Rank { + self.rank_out + } + + fn dnum(&self) -> Dnum { + self.dnum + } +} + +#[derive(PartialEq, Eq, Clone)] +pub struct GGLWE<D: Data> { + pub(crate) data: MatZnx<D>, + pub(crate) k: TorusPrecision, + pub(crate) base2k: Base2K, + pub(crate) dsize: Dsize, +} + +impl<D: Data> LWEInfos for GGLWE<D> { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } + + fn size(&self) -> usize { + self.data.size() + } +} + +impl<D: Data> GLWEInfos for GGLWE<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data> GGLWEInfos for GGLWE<D> { + fn rank_in(&self) -> Rank { + Rank(self.data.cols_in() as u32) + } + + fn rank_out(&self) -> Rank { + Rank(self.data.cols_out() as u32 - 1) + } + + fn dsize(&self) -> Dsize { + self.dsize + } + + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) + } +} + +impl<D: DataRef> GGLWE<D> { + pub fn data(&self) -> &MatZnx<D> { + &self.data + } +} + +impl<D: DataMut> GGLWE<D> { + pub fn data_mut(&mut self) -> &mut MatZnx<D> { + &mut self.data + } +} + +impl<D: DataRef> fmt::Debug for GGLWE<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for GGLWE<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.data.fill_uniform(log_bound, source); + } +} + +impl<D: DataRef> fmt::Display for GGLWE<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "(GGLWE: k={} base2k={} dsize={}) {}", + self.k().0, + self.base2k().0, + self.dsize().0, + self.data + ) + } +} + +impl<D: DataRef> GGLWE<D> { + pub fn at(&self, row: usize, col: usize) -> GLWE<&[u8]> { + GLWE { + k: self.k, + base2k: self.base2k, + data: self.data.at(row, col), + } + } +} + +impl<D: DataMut> GGLWE<D> { + pub fn at_mut(&mut self, row: usize, col: usize) -> GLWE<&mut [u8]> { + GLWE { + k: self.k, + base2k: self.base2k, + data: self.data.at_mut(row, col), + } + } +} + +impl GGLWE<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.rank_out(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, rank_out: Rank, dnum: Dnum, dsize: Dsize) -> Self { + let size: usize = k.0.div_ceil(base2k.0) as usize; + debug_assert!( + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + GGLWE { + data: MatZnx::alloc( + n.into(), + dnum.into(), + rank_in.into(), + (rank_out + 1).into(), + k.0.div_ceil(base2k.0) as usize, + ), + k, + base2k, + dsize, + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.rank_out(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn bytes_of( + n: Degree, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> usize { + let size: usize = k.0.div_ceil(base2k.0) as usize; + debug_assert!( + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + MatZnx::bytes_of( + n.into(), + dnum.into(), + rank_in.into(), + (rank_out + 1).into(), + k.0.div_ceil(base2k.0) as usize, + ) + } +} + +pub trait GGLWEToMut { + fn to_mut(&mut self) -> GGLWE<&mut [u8]>; +} + +impl<D: DataMut> GGLWEToMut for GGLWE<D> { + fn to_mut(&mut self) -> GGLWE<&mut [u8]> { + GGLWE { + k: self.k(), + base2k: self.base2k(), + dsize: self.dsize(), + data: self.data.to_mut(), + } + } +} + +pub trait GGLWEToRef { + fn to_ref(&self) -> GGLWE<&[u8]>; +} + +impl<D: DataRef> GGLWEToRef for GGLWE<D> { + fn to_ref(&self) -> GGLWE<&[u8]> { + GGLWE { + k: self.k(), + base2k: self.base2k(), + dsize: self.dsize(), + data: self.data.to_ref(), + } + } +} + +impl<D: DataMut> ReaderFrom for GGLWE<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); + self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); + self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); + self.data.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GGLWE<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u32::<LittleEndian>(self.k.0)?; + writer.write_u32::<LittleEndian>(self.base2k.0)?; + writer.write_u32::<LittleEndian>(self.dsize.0)?; + self.data.write_to(writer) + } +}
@@ -1,197 +0,0 @@
-use poulpy_hal::{ - layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo}, - source::Source, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision, -}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -use std::fmt; - -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct GGLWEAutomorphismKeyLayout { - pub n: Degree, - pub base2k: Base2K, - pub k: TorusPrecision, - pub rank: Rank, - pub dnum: Dnum, - pub dsize: Dsize, -} - -#[derive(PartialEq, Eq, Clone)] -pub struct GGLWEAutomorphismKey<D: Data> { - pub(crate) key: GGLWESwitchingKey<D>, - pub(crate) p: i64, -} - -impl<D: Data> GGLWEAutomorphismKey<D> { - pub fn p(&self) -> i64 { - self.p - } -} - -impl<D: Data> LWEInfos for GGLWEAutomorphismKey<D> { - fn n(&self) -> Degree { - self.key.n() - } - - fn base2k(&self) -> Base2K { - self.key.base2k() - } - - fn k(&self) -> TorusPrecision { - self.key.k() - } - - fn size(&self) -> usize { - self.key.size() - } -} - -impl<D: Data> GLWEInfos for GGLWEAutomorphismKey<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data> GGLWEInfos for GGLWEAutomorphismKey<D> { - fn rank_in(&self) -> Rank { - self.key.rank_in() - } - - fn rank_out(&self) -> Rank { - self.key.rank_out() - } - - fn dsize(&self) -> Dsize { - self.key.dsize() - } - - fn dnum(&self) -> Dnum { - self.key.dnum() - } -} - -impl LWEInfos for GGLWEAutomorphismKeyLayout { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn n(&self) -> Degree { - self.n - } -} - -impl GLWEInfos for GGLWEAutomorphismKeyLayout { - fn rank(&self) -> Rank { - self.rank - } -} - -impl GGLWEInfos for GGLWEAutomorphismKeyLayout { - fn rank_in(&self) -> Rank { - self.rank - } - - fn dsize(&self) -> Dsize { - self.dsize - } - - fn rank_out(&self) -> Rank { - self.rank - } - - fn dnum(&self) -> Dnum { - self.dnum - } -} - -impl<D: DataRef> fmt::Debug for GGLWEAutomorphismKey<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for GGLWEAutomorphismKey<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.key.fill_uniform(log_bound, source); - } -} - -impl<D: DataRef> fmt::Display for GGLWEAutomorphismKey<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "(AutomorphismKey: p={}) {}", self.p, self.key) - } -} - -impl GGLWEAutomorphismKey<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWEAutomorphismKey" - ); - GGLWEAutomorphismKey { - key: GGLWESwitchingKey::alloc(infos), - p: 0, - } - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { - GGLWEAutomorphismKey { - key: GGLWESwitchingKey::alloc_with(n, base2k, k, rank, rank, dnum, dsize), - p: 0, - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWEAutomorphismKey" - ); - GGLWESwitchingKey::alloc_bytes(infos) - } - - pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { - GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rank, rank, dnum, dsize) - } -} - -impl<D: DataRef> GGLWEAutomorphismKey<D> { - pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> { - self.key.at(row, col) - } -} - -impl<D: DataMut> GGLWEAutomorphismKey<D> { - pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> { - self.key.at_mut(row, col) - } -} - -impl<D: DataMut> ReaderFrom for GGLWEAutomorphismKey<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.p = reader.read_u64::<LittleEndian>()? as i64; - self.key.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GGLWEAutomorphismKey<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u64::<LittleEndian>(self.p as u64)?; - self.key.write_to(writer) - } -}
@@ -1,408 +0,0 @@
-use poulpy_hal::{ - layouts::{Data, DataMut, DataRef, FillUniform, MatZnx, ReaderFrom, WriterTo, ZnxInfos}, - source::Source, -}; - -use crate::layouts::{Base2K, BuildError, Degree, Dnum, Dsize, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -use std::fmt; - -pub trait GGLWEInfos -where - Self: GLWEInfos, -{ - fn dnum(&self) -> Dnum; - fn dsize(&self) -> Dsize; - fn rank_in(&self) -> Rank; - fn rank_out(&self) -> Rank; - fn layout(&self) -> GGLWECiphertextLayout { - GGLWECiphertextLayout { - n: self.n(), - base2k: self.base2k(), - k: self.k(), - rank_in: self.rank_in(), - rank_out: self.rank_out(), - dsize: self.dsize(), - dnum: self.dnum(), - } - } -} - -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct GGLWECiphertextLayout { - pub n: Degree, - pub base2k: Base2K, - pub k: TorusPrecision, - pub rank_in: Rank, - pub rank_out: Rank, - pub dnum: Dnum, - pub dsize: Dsize, -} - -impl LWEInfos for GGLWECiphertextLayout { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn n(&self) -> Degree { - self.n - } -} - -impl GLWEInfos for GGLWECiphertextLayout { - fn rank(&self) -> Rank { - self.rank_out - } -} - -impl GGLWEInfos for GGLWECiphertextLayout { - fn rank_in(&self) -> Rank { - self.rank_in - } - - fn dsize(&self) -> Dsize { - self.dsize - } - - fn rank_out(&self) -> Rank { - self.rank_out - } - - fn dnum(&self) -> Dnum { - self.dnum - } -} - -#[derive(PartialEq, Eq, Clone)] -pub struct GGLWECiphertext<D: Data> { - pub(crate) data: MatZnx<D>, - pub(crate) k: TorusPrecision, - pub(crate) base2k: Base2K, - pub(crate) dsize: Dsize, -} - -impl<D: Data> LWEInfos for GGLWECiphertext<D> { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - fn size(&self) -> usize { - self.data.size() - } -} - -impl<D: Data> GLWEInfos for GGLWECiphertext<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data> GGLWEInfos for GGLWECiphertext<D> { - fn rank_in(&self) -> Rank { - Rank(self.data.cols_in() as u32) - } - - fn rank_out(&self) -> Rank { - Rank(self.data.cols_out() as u32 - 1) - } - - fn dsize(&self) -> Dsize { - self.dsize - } - - fn dnum(&self) -> Dnum { - Dnum(self.data.rows() as u32) - } -} - -pub struct GGLWECiphertextBuilder<D: Data> { - data: Option<MatZnx<D>>, - base2k: Option<Base2K>, - k: Option<TorusPrecision>, - dsize: Option<Dsize>, -} - -impl<D: Data> GGLWECiphertext<D> { - #[inline] - pub fn builder() -> GGLWECiphertextBuilder<D> { - GGLWECiphertextBuilder { - data: None, - base2k: None, - k: None, - dsize: None, - } - } -} - -impl GGLWECiphertextBuilder<Vec<u8>> { - #[inline] - pub fn layout<A>(mut self, infos: &A) -> Self - where - A: GGLWEInfos, - { - self.data = Some(MatZnx::alloc( - infos.n().into(), - infos.dnum().into(), - infos.rank_in().into(), - (infos.rank_out() + 1).into(), - infos.size(), - )); - self.base2k = Some(infos.base2k()); - self.k = Some(infos.k()); - self.dsize = Some(infos.dsize()); - self - } -} - -impl<D: Data> GGLWECiphertextBuilder<D> { - #[inline] - pub fn data(mut self, data: MatZnx<D>) -> Self { - self.data = Some(data); - self - } - #[inline] - pub fn base2k(mut self, base2k: Base2K) -> Self { - self.base2k = Some(base2k); - self - } - #[inline] - pub fn k(mut self, k: TorusPrecision) -> Self { - self.k = Some(k); - self - } - - #[inline] - pub fn dsize(mut self, dsize: Dsize) -> Self { - self.dsize = Some(dsize); - self - } - - pub fn build(self) -> Result<GGLWECiphertext<D>, BuildError> { - let data: MatZnx<D> = self.data.ok_or(BuildError::MissingData)?; - let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; - let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?; - - if base2k == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if dsize == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if k == 0_u32 { - return Err(BuildError::ZeroTorusPrecision); - } - - if data.n() == 0 { - return Err(BuildError::ZeroDegree); - } - - if data.cols() == 0 { - return Err(BuildError::ZeroCols); - } - - if data.size() == 0 { - return Err(BuildError::ZeroLimbs); - } - - Ok(GGLWECiphertext { - data, - base2k, - k, - dsize, - }) - } -} - -impl<D: DataRef> GGLWECiphertext<D> { - pub fn data(&self) -> &MatZnx<D> { - &self.data - } -} - -impl<D: DataMut> GGLWECiphertext<D> { - pub fn data_mut(&mut self) -> &mut MatZnx<D> { - &mut self.data - } -} - -impl<D: DataRef> fmt::Debug for GGLWECiphertext<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for GGLWECiphertext<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.data.fill_uniform(log_bound, source); - } -} - -impl<D: DataRef> fmt::Display for GGLWECiphertext<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "(GGLWECiphertext: k={} base2k={} dsize={}) {}", - self.k().0, - self.base2k().0, - self.dsize().0, - self.data - ) - } -} - -impl<D: DataRef> GGLWECiphertext<D> { - pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> { - GLWECiphertext::builder() - .data(self.data.at(row, col)) - .base2k(self.base2k()) - .k(self.k()) - .build() - .unwrap() - } -} - -impl<D: DataMut> GGLWECiphertext<D> { - pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> { - GLWECiphertext::builder() - .base2k(self.base2k()) - .k(self.k()) - .data(self.data.at_mut(row, col)) - .build() - .unwrap() - } -} - -impl GGLWECiphertext<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - Self::alloc_with( - infos.n(), - infos.base2k(), - infos.k(), - infos.rank_in(), - infos.rank_out(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_with( - n: Degree, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - rank_out: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> Self { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - Self { - data: MatZnx::alloc( - n.into(), - dnum.into(), - rank_in.into(), - (rank_out + 1).into(), - k.0.div_ceil(base2k.0) as usize, - ), - k, - base2k, - dsize, - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - Self::alloc_bytes_with( - infos.n(), - infos.base2k(), - infos.k(), - infos.rank_in(), - infos.rank_out(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_bytes_with( - n: Degree, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - rank_out: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> usize { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - MatZnx::alloc_bytes( - n.into(), - dnum.into(), - rank_in.into(), - (rank_out + 1).into(), - k.0.div_ceil(base2k.0) as usize, - ) - } -} - -impl<D: DataMut> ReaderFrom for GGLWECiphertext<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); - self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); - self.data.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GGLWECiphertext<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u32::<LittleEndian>(self.k.0)?; - writer.write_u32::<LittleEndian>(self.base2k.0)?; - writer.write_u32::<LittleEndian>(self.dsize.0)?; - self.data.write_to(writer) - } -}
@@ -1,209 +0,0 @@
-use poulpy_hal::{ - layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo}, - source::Source, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWECiphertext, GGLWEInfos, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision, -}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -use std::fmt; - -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct GGLWESwitchingKeyLayout { - pub n: Degree, - pub base2k: Base2K, - pub k: TorusPrecision, - pub rank_in: Rank, - pub rank_out: Rank, - pub dnum: Dnum, - pub dsize: Dsize, -} - -impl LWEInfos for GGLWESwitchingKeyLayout { - fn n(&self) -> Degree { - self.n - } - - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } -} - -impl GLWEInfos for GGLWESwitchingKeyLayout { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl GGLWEInfos for GGLWESwitchingKeyLayout { - fn rank_in(&self) -> Rank { - self.rank_in - } - - fn rank_out(&self) -> Rank { - self.rank_out - } - - fn dsize(&self) -> Dsize { - self.dsize - } - - fn dnum(&self) -> Dnum { - self.dnum - } -} - -#[derive(PartialEq, Eq, Clone)] -pub struct GGLWESwitchingKey<D: Data> { - pub(crate) key: GGLWECiphertext<D>, - pub(crate) sk_in_n: usize, // Degree of sk_in - pub(crate) sk_out_n: usize, // Degree of sk_out -} - -impl<D: Data> LWEInfos for GGLWESwitchingKey<D> { - fn n(&self) -> Degree { - self.key.n() - } - - fn base2k(&self) -> Base2K { - self.key.base2k() - } - - fn k(&self) -> TorusPrecision { - self.key.k() - } - - fn size(&self) -> usize { - self.key.size() - } -} - -impl<D: Data> GLWEInfos for GGLWESwitchingKey<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data> GGLWEInfos for GGLWESwitchingKey<D> { - fn rank_in(&self) -> Rank { - self.key.rank_in() - } - - fn rank_out(&self) -> Rank { - self.key.rank_out() - } - - fn dsize(&self) -> Dsize { - self.key.dsize() - } - - fn dnum(&self) -> Dnum { - self.key.dnum() - } -} - -impl<D: DataRef> fmt::Debug for GGLWESwitchingKey<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataRef> fmt::Display for GGLWESwitchingKey<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "(GLWESwitchingKey: sk_in_n={} sk_out_n={}) {}", - self.sk_in_n, - self.sk_out_n, - self.key.data() - ) - } -} - -impl<D: DataMut> FillUniform for GGLWESwitchingKey<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.key.fill_uniform(log_bound, source); - } -} - -impl GGLWESwitchingKey<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - GGLWESwitchingKey { - key: GGLWECiphertext::alloc(infos), - sk_in_n: 0, - sk_out_n: 0, - } - } - - pub fn alloc_with( - n: Degree, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - rank_out: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> Self { - GGLWESwitchingKey { - key: GGLWECiphertext::alloc_with(n, base2k, k, rank_in, rank_out, dnum, dsize), - sk_in_n: 0, - sk_out_n: 0, - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - GGLWECiphertext::alloc_bytes(infos) - } - - pub fn alloc_bytes_with( - n: Degree, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - rank_out: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> usize { - GGLWECiphertext::alloc_bytes_with(n, base2k, k, rank_in, rank_out, dnum, dsize) - } -} - -impl<D: DataRef> GGLWESwitchingKey<D> { - pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> { - self.key.at(row, col) - } -} - -impl<D: DataMut> GGLWESwitchingKey<D> { - pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> { - self.key.at_mut(row, col) - } -} - -impl<D: DataMut> ReaderFrom for GGLWESwitchingKey<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.sk_in_n = reader.read_u64::<LittleEndian>()? as usize; - self.sk_out_n = reader.read_u64::<LittleEndian>()? as usize; - self.key.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GGLWESwitchingKey<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u64::<LittleEndian>(self.sk_in_n as u64)?; - writer.write_u64::<LittleEndian>(self.sk_out_n as u64)?; - self.key.write_to(writer) - } -}
@@ -1,242 +0,0 @@
-use poulpy_hal::{ - layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo}, - source::Source, -}; - -use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -use std::fmt; - -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct GGLWETensorKeyLayout { - pub n: Degree, - pub base2k: Base2K, - pub k: TorusPrecision, - pub rank: Rank, - pub dnum: Dnum, - pub dsize: Dsize, -} - -#[derive(PartialEq, Eq, Clone)] -pub struct GGLWETensorKey<D: Data> { - pub(crate) keys: Vec<GGLWESwitchingKey<D>>, -} - -impl<D: Data> LWEInfos for GGLWETensorKey<D> { - fn n(&self) -> Degree { - self.keys[0].n() - } - - fn base2k(&self) -> Base2K { - self.keys[0].base2k() - } - - fn k(&self) -> TorusPrecision { - self.keys[0].k() - } - - fn size(&self) -> usize { - self.keys[0].size() - } -} - -impl<D: Data> GLWEInfos for GGLWETensorKey<D> { - fn rank(&self) -> Rank { - self.keys[0].rank_out() - } -} - -impl<D: Data> GGLWEInfos for GGLWETensorKey<D> { - fn rank_in(&self) -> Rank { - self.rank_out() - } - - fn rank_out(&self) -> Rank { - self.keys[0].rank_out() - } - - fn dsize(&self) -> Dsize { - self.keys[0].dsize() - } - - fn dnum(&self) -> Dnum { - self.keys[0].dnum() - } -} - -impl LWEInfos for GGLWETensorKeyLayout { - fn n(&self) -> Degree { - self.n - } - - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } -} - -impl GLWEInfos for GGLWETensorKeyLayout { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl GGLWEInfos for GGLWETensorKeyLayout { - fn rank_in(&self) -> Rank { - self.rank - } - - fn dsize(&self) -> Dsize { - self.dsize - } - - fn rank_out(&self) -> Rank { - self.rank - } - - fn dnum(&self) -> Dnum { - self.dnum - } -} - -impl<D: DataRef> fmt::Debug for GGLWETensorKey<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for GGLWETensorKey<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.keys - .iter_mut() - .for_each(|key: &mut GGLWESwitchingKey<D>| key.fill_uniform(log_bound, source)) - } -} - -impl<D: DataRef> fmt::Display for GGLWETensorKey<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "(GLWETensorKey)",)?; - for (i, key) in self.keys.iter().enumerate() { - write!(f, "{i}: {key}")?; - } - Ok(()) - } -} - -impl GGLWETensorKey<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWETensorKey" - ); - Self::alloc_with( - infos.n(), - infos.base2k(), - infos.k(), - infos.rank_out(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { - let mut keys: Vec<GGLWESwitchingKey<Vec<u8>>> = Vec::new(); - let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1); - (0..pairs).for_each(|_| { - keys.push(GGLWESwitchingKey::alloc_with( - n, - base2k, - k, - Rank(1), - rank, - dnum, - dsize, - )); - }); - Self { keys } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWETensorKey" - ); - let rank_out: usize = infos.rank_out().into(); - let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1); - pairs - * GGLWESwitchingKey::alloc_bytes_with( - infos.n(), - infos.base2k(), - infos.k(), - Rank(1), - infos.rank_out(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { - let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize; - pairs * GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, Rank(1), rank, dnum, dsize) - } -} - -impl<D: DataMut> GGLWETensorKey<D> { - // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j]) - pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKey<D> { - if i > j { - std::mem::swap(&mut i, &mut j); - }; - let rank: usize = self.rank_out().into(); - &mut self.keys[i * rank + j - (i * (i + 1) / 2)] - } -} - -impl<D: DataRef> GGLWETensorKey<D> { - // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j]) - pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWESwitchingKey<D> { - if i > j { - std::mem::swap(&mut i, &mut j); - }; - let rank: usize = self.rank_out().into(); - &self.keys[i * rank + j - (i * (i + 1) / 2)] - } -} - -impl<D: DataMut> ReaderFrom for GGLWETensorKey<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - let len: usize = reader.read_u64::<LittleEndian>()? as usize; - if self.keys.len() != len { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("self.keys.len()={} != read len={}", self.keys.len(), len), - )); - } - for key in &mut self.keys { - key.read_from(reader)?; - } - Ok(()) - } -} - -impl<D: DataRef> WriterTo for GGLWETensorKey<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u64::<LittleEndian>(self.keys.len() as u64)?; - for key in &self.keys { - key.write_to(writer)?; - } - Ok(()) - } -}
@@ -0,0 +1,284 @@
+use poulpy_hal::{ + layouts::{Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, ReaderFrom, WriterTo, ZnxInfos}, + source::Source, +}; +use std::fmt; + +use crate::layouts::{Base2K, Degree, Dnum, Dsize, GLWE, GLWEInfos, LWEInfos, Rank, TorusPrecision}; + +pub trait GGSWInfos +where + Self: GLWEInfos, +{ + fn dnum(&self) -> Dnum; + fn dsize(&self) -> Dsize; + fn ggsw_layout(&self) -> GGSWLayout { + GGSWLayout { + n: self.n(), + base2k: self.base2k(), + k: self.k(), + rank: self.rank(), + dnum: self.dnum(), + dsize: self.dsize(), + } + } +} + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub struct GGSWLayout { + pub n: Degree, + pub base2k: Base2K, + pub k: TorusPrecision, + pub rank: Rank, + pub dnum: Dnum, + pub dsize: Dsize, +} + +impl LWEInfos for GGSWLayout { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn n(&self) -> Degree { + self.n + } +} +impl GLWEInfos for GGSWLayout { + fn rank(&self) -> Rank { + self.rank + } +} + +impl GGSWInfos for GGSWLayout { + fn dsize(&self) -> Dsize { + self.dsize + } + + fn dnum(&self) -> Dnum { + self.dnum + } +} + +#[derive(PartialEq, Eq, Clone)] +pub struct GGSW<D: Data> { + pub(crate) data: MatZnx<D>, + pub(crate) k: TorusPrecision, + pub(crate) base2k: Base2K, + pub(crate) dsize: Dsize, +} + +impl<D: Data> LWEInfos for GGSW<D> { + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } + + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn size(&self) -> usize { + self.data.size() + } +} + +impl<D: Data> GLWEInfos for GGSW<D> { + fn rank(&self) -> Rank { + Rank(self.data.cols_out() as u32 - 1) + } +} + +impl<D: Data> GGSWInfos for GGSW<D> { + fn dsize(&self) -> Dsize { + self.dsize + } + + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) + } +} + +impl<D: DataRef> fmt::Debug for GGSW<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.data) + } +} + +impl<D: DataRef> fmt::Display for GGSW<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "(GGSW: k: {} base2k: {} dsize: {}) {}", + self.k().0, + self.base2k().0, + self.dsize().0, + self.data + ) + } +} + +impl<D: DataMut> FillUniform for GGSW<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.data.fill_uniform(log_bound, source); + } +} + +impl<D: DataRef> GGSW<D> { + pub fn at(&self, row: usize, col: usize) -> GLWE<&[u8]> { + GLWE { + k: self.k, + base2k: self.base2k, + data: self.data.at(row, col), + } + } +} + +impl<D: DataMut> GGSW<D> { + pub fn at_mut(&mut self, row: usize, col: usize) -> GLWE<&mut [u8]> { + GLWE { + k: self.k, + base2k: self.base2k, + data: self.data.at_mut(row, col), + } + } +} + +impl GGSW<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGSWInfos, + { + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { + let size: usize = k.0.div_ceil(base2k.0) as usize; + debug_assert!( + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + GGSW { + data: MatZnx::alloc( + n.into(), + dnum.into(), + (rank + 1).into(), + (rank + 1).into(), + k.0.div_ceil(base2k.0) as usize, + ), + k, + base2k, + dsize, + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGSWInfos, + { + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { + let size: usize = k.0.div_ceil(base2k.0) as usize; + debug_assert!( + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + MatZnx::bytes_of( + n.into(), + dnum.into(), + (rank + 1).into(), + (rank + 1).into(), + k.0.div_ceil(base2k.0) as usize, + ) + } +} + +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +impl<D: DataMut> ReaderFrom for GGSW<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); + self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); + self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); + self.data.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GGSW<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u32::<LittleEndian>(self.k.into())?; + writer.write_u32::<LittleEndian>(self.base2k.into())?; + writer.write_u32::<LittleEndian>(self.dsize.into())?; + self.data.write_to(writer) + } +} + +pub trait GGSWToMut { + fn to_mut(&mut self) -> GGSW<&mut [u8]>; +} + +impl<D: DataMut> GGSWToMut for GGSW<D> { + fn to_mut(&mut self) -> GGSW<&mut [u8]> { + GGSW { + dsize: self.dsize, + k: self.k, + base2k: self.base2k, + data: self.data.to_mut(), + } + } +} + +pub trait GGSWToRef { + fn to_ref(&self) -> GGSW<&[u8]>; +} + +impl<D: DataRef> GGSWToRef for GGSW<D> { + fn to_ref(&self) -> GGSW<&[u8]> { + GGSW { + dsize: self.dsize, + k: self.k, + base2k: self.base2k, + data: self.data.to_ref(), + } + } +}
@@ -1,372 +0,0 @@
-use poulpy_hal::{ - layouts::{Data, DataMut, DataRef, FillUniform, MatZnx, ReaderFrom, WriterTo, ZnxInfos}, - source::Source, -}; -use std::fmt; - -use crate::layouts::{Base2K, BuildError, Degree, Dnum, Dsize, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision}; - -pub trait GGSWInfos -where - Self: GLWEInfos, -{ - fn dnum(&self) -> Dnum; - fn dsize(&self) -> Dsize; - fn ggsw_layout(&self) -> GGSWCiphertextLayout { - GGSWCiphertextLayout { - n: self.n(), - base2k: self.base2k(), - k: self.k(), - rank: self.rank(), - dnum: self.dnum(), - dsize: self.dsize(), - } - } -} - -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct GGSWCiphertextLayout { - pub n: Degree, - pub base2k: Base2K, - pub k: TorusPrecision, - pub rank: Rank, - pub dnum: Dnum, - pub dsize: Dsize, -} - -impl LWEInfos for GGSWCiphertextLayout { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn n(&self) -> Degree { - self.n - } -} -impl GLWEInfos for GGSWCiphertextLayout { - fn rank(&self) -> Rank { - self.rank - } -} - -impl GGSWInfos for GGSWCiphertextLayout { - fn dsize(&self) -> Dsize { - self.dsize - } - - fn dnum(&self) -> Dnum { - self.dnum - } -} - -#[derive(PartialEq, Eq, Clone)] -pub struct GGSWCiphertext<D: Data> { - pub(crate) data: MatZnx<D>, - pub(crate) k: TorusPrecision, - pub(crate) base2k: Base2K, - pub(crate) dsize: Dsize, -} - -impl<D: Data> LWEInfos for GGSWCiphertext<D> { - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn size(&self) -> usize { - self.data.size() - } -} - -impl<D: Data> GLWEInfos for GGSWCiphertext<D> { - fn rank(&self) -> Rank { - Rank(self.data.cols_out() as u32 - 1) - } -} - -impl<D: Data> GGSWInfos for GGSWCiphertext<D> { - fn dsize(&self) -> Dsize { - self.dsize - } - - fn dnum(&self) -> Dnum { - Dnum(self.data.rows() as u32) - } -} - -pub struct GGSWCiphertextBuilder<D: Data> { - data: Option<MatZnx<D>>, - base2k: Option<Base2K>, - k: Option<TorusPrecision>, - dsize: Option<Dsize>, -} - -impl<D: Data> GGSWCiphertext<D> { - #[inline] - pub fn builder() -> GGSWCiphertextBuilder<D> { - GGSWCiphertextBuilder { - data: None, - base2k: None, - k: None, - dsize: None, - } - } -} - -impl GGSWCiphertextBuilder<Vec<u8>> { - #[inline] - pub fn layout<A>(mut self, infos: &A) -> Self - where - A: GGSWInfos, - { - debug_assert!( - infos.size() as u32 > infos.dsize().0, - "invalid ggsw: ceil(k/base2k): {} <= dsize: {}", - infos.size(), - infos.dsize() - ); - - assert!( - infos.dnum().0 * infos.dsize().0 <= infos.size() as u32, - "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {}", - infos.dnum(), - infos.dsize(), - infos.size(), - ); - - self.data = Some(MatZnx::alloc( - infos.n().into(), - infos.dnum().into(), - (infos.rank() + 1).into(), - (infos.rank() + 1).into(), - infos.size(), - )); - self.base2k = Some(infos.base2k()); - self.k = Some(infos.k()); - self.dsize = Some(infos.dsize()); - self - } -} - -impl<D: Data> GGSWCiphertextBuilder<D> { - #[inline] - pub fn data(mut self, data: MatZnx<D>) -> Self { - self.data = Some(data); - self - } - #[inline] - pub fn base2k(mut self, base2k: Base2K) -> Self { - self.base2k = Some(base2k); - self - } - #[inline] - pub fn k(mut self, k: TorusPrecision) -> Self { - self.k = Some(k); - self - } - - #[inline] - pub fn dsize(mut self, dsize: Dsize) -> Self { - self.dsize = Some(dsize); - self - } - - pub fn build(self) -> Result<GGSWCiphertext<D>, BuildError> { - let data: MatZnx<D> = self.data.ok_or(BuildError::MissingData)?; - let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; - let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?; - - if base2k == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if dsize == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if k == 0_u32 { - return Err(BuildError::ZeroTorusPrecision); - } - - if data.n() == 0 { - return Err(BuildError::ZeroDegree); - } - - if data.cols() == 0 { - return Err(BuildError::ZeroCols); - } - - if data.size() == 0 { - return Err(BuildError::ZeroLimbs); - } - - Ok(GGSWCiphertext { - data, - base2k, - k, - dsize, - }) - } -} - -impl<D: DataRef> fmt::Debug for GGSWCiphertext<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.data) - } -} - -impl<D: DataRef> fmt::Display for GGSWCiphertext<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "(GGSWCiphertext: k: {} base2k: {} dsize: {}) {}", - self.k().0, - self.base2k().0, - self.dsize().0, - self.data - ) - } -} - -impl<D: DataMut> FillUniform for GGSWCiphertext<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.data.fill_uniform(log_bound, source); - } -} - -impl<D: DataRef> GGSWCiphertext<D> { - pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> { - GLWECiphertext::builder() - .data(self.data.at(row, col)) - .base2k(self.base2k()) - .k(self.k()) - .build() - .unwrap() - } -} - -impl<D: DataMut> GGSWCiphertext<D> { - pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> { - GLWECiphertext::builder() - .base2k(self.base2k()) - .k(self.k()) - .data(self.data.at_mut(row, col)) - .build() - .unwrap() - } -} - -impl GGSWCiphertext<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGSWInfos, - { - Self::alloc_with( - infos.n(), - infos.base2k(), - infos.k(), - infos.rank(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - Self { - data: MatZnx::alloc( - n.into(), - dnum.into(), - (rank + 1).into(), - (rank + 1).into(), - k.0.div_ceil(base2k.0) as usize, - ), - k, - base2k, - dsize, - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGSWInfos, - { - Self::alloc_bytes_with( - infos.n(), - infos.base2k(), - infos.k(), - infos.rank(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - MatZnx::alloc_bytes( - n.into(), - dnum.into(), - (rank + 1).into(), - (rank + 1).into(), - k.0.div_ceil(base2k.0) as usize, - ) - } -} - -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -impl<D: DataMut> ReaderFrom for GGSWCiphertext<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); - self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.dsize = Dsize(reader.read_u32::<LittleEndian>()?); - self.data.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GGSWCiphertext<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u32::<LittleEndian>(self.k.into())?; - writer.write_u32::<LittleEndian>(self.base2k.into())?; - writer.write_u32::<LittleEndian>(self.dsize.into())?; - self.data.write_to(writer) - } -}
@@ -0,0 +1,218 @@
+use poulpy_hal::{ + layouts::{ + Data, DataMut, DataRef, FillUniform, ReaderFrom, ToOwnedDeep, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo, ZnxInfos, + }, + source::Source, +}; + +use crate::layouts::{Base2K, Degree, LWEInfos, Rank, TorusPrecision}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::fmt; + +pub trait GLWEInfos +where + Self: LWEInfos, +{ + fn rank(&self) -> Rank; + fn glwe_layout(&self) -> GLWELayout { + GLWELayout { + n: self.n(), + base2k: self.base2k(), + k: self.k(), + rank: self.rank(), + } + } +} + +pub trait SetGLWEInfos { + fn set_k(&mut self, k: TorusPrecision); + fn set_base2k(&mut self, base2k: Base2K); +} + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub struct GLWELayout { + pub n: Degree, + pub base2k: Base2K, + pub k: TorusPrecision, + pub rank: Rank, +} + +impl LWEInfos for GLWELayout { + fn n(&self) -> Degree { + self.n + } + + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } +} + +impl GLWEInfos for GLWELayout { + fn rank(&self) -> Rank { + self.rank + } +} + +#[derive(PartialEq, Eq, Clone)] +pub struct GLWE<D: Data> { + pub(crate) data: VecZnx<D>, + pub(crate) base2k: Base2K, + pub(crate) k: TorusPrecision, +} + +impl<D: DataMut> SetGLWEInfos for GLWE<D> { + fn set_base2k(&mut self, base2k: Base2K) { + self.base2k = base2k + } + + fn set_k(&mut self, k: TorusPrecision) { + self.k = k + } +} + +impl<D: DataRef> GLWE<D> { + pub fn data(&self) -> &VecZnx<D> { + &self.data + } +} + +impl<D: DataMut> GLWE<D> { + pub fn data_mut(&mut self) -> &mut VecZnx<D> { + &mut self.data + } +} + +impl<D: Data> LWEInfos for GLWE<D> { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } + + fn size(&self) -> usize { + self.data.size() + } +} + +impl<D: Data> GLWEInfos for GLWE<D> { + fn rank(&self) -> Rank { + Rank(self.data.cols() as u32 - 1) + } +} + +impl<D: DataRef> ToOwnedDeep for GLWE<D> { + type Owned = GLWE<Vec<u8>>; + fn to_owned_deep(&self) -> Self::Owned { + GLWE { + data: self.data.to_owned_deep(), + k: self.k, + base2k: self.base2k, + } + } +} + +impl<D: DataRef> fmt::Debug for GLWE<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataRef> fmt::Display for GLWE<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "GLWE: base2k={} k={}: {}", + self.base2k().0, + self.k().0, + self.data + ) + } +} + +impl<D: DataMut> FillUniform for GLWE<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.data.fill_uniform(log_bound, source); + } +} + +impl GLWE<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GLWEInfos, + { + Self::alloc(infos.n(), infos.base2k(), infos.k(), infos.rank()) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self { + GLWE { + data: VecZnx::alloc(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize), + base2k, + k, + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GLWEInfos, + { + Self::bytes_of(infos.n(), infos.base2k(), infos.k(), infos.rank()) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize { + VecZnx::bytes_of(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize) + } +} + +impl<D: DataMut> ReaderFrom for GLWE<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); + self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); + self.data.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GLWE<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u32::<LittleEndian>(self.k.0)?; + writer.write_u32::<LittleEndian>(self.base2k.0)?; + self.data.write_to(writer) + } +} + +pub trait GLWEToRef { + fn to_ref(&self) -> GLWE<&[u8]>; +} + +impl<D: DataRef> GLWEToRef for GLWE<D> { + fn to_ref(&self) -> GLWE<&[u8]> { + GLWE { + k: self.k, + base2k: self.base2k, + data: self.data.to_ref(), + } + } +} + +pub trait GLWEToMut { + fn to_mut(&mut self) -> GLWE<&mut [u8]>; +} + +impl<D: DataMut> GLWEToMut for GLWE<D> { + fn to_mut(&mut self) -> GLWE<&mut [u8]> { + GLWE { + k: self.k, + base2k: self.base2k, + data: self.data.to_mut(), + } + } +}
@@ -0,0 +1,235 @@
+use poulpy_hal::{ + layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo}, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToMut, GGLWEToRef, GLWE, GLWEInfos, LWEInfos, Rank, TorusPrecision, +}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +use std::fmt; + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub struct GLWEAutomorphismKeyLayout { + pub n: Degree, + pub base2k: Base2K, + pub k: TorusPrecision, + pub rank: Rank, + pub dnum: Dnum, + pub dsize: Dsize, +} + +#[derive(PartialEq, Eq, Clone)] +pub struct GLWEAutomorphismKey<D: Data> { + pub(crate) key: GGLWE<D>, + pub(crate) p: i64, +} + +pub trait GetGaloisElement { + fn p(&self) -> i64; +} + +pub trait SetGaloisElement { + fn set_p(&mut self, p: i64); +} + +impl<D: DataMut> SetGaloisElement for GLWEAutomorphismKey<D> { + fn set_p(&mut self, p: i64) { + self.p = p + } +} + +impl<D: DataRef> GetGaloisElement for GLWEAutomorphismKey<D> { + fn p(&self) -> i64 { + self.p + } +} + +impl<D: Data> GLWEAutomorphismKey<D> { + pub fn p(&self) -> i64 { + self.p + } +} + +impl<D: Data> LWEInfos for GLWEAutomorphismKey<D> { + fn n(&self) -> Degree { + self.key.n() + } + + fn base2k(&self) -> Base2K { + self.key.base2k() + } + + fn k(&self) -> TorusPrecision { + self.key.k() + } + + fn size(&self) -> usize { + self.key.size() + } +} + +impl<D: Data> GLWEInfos for GLWEAutomorphismKey<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data> GGLWEInfos for GLWEAutomorphismKey<D> { + fn rank_in(&self) -> Rank { + self.key.rank_in() + } + + fn rank_out(&self) -> Rank { + self.key.rank_out() + } + + fn dsize(&self) -> Dsize { + self.key.dsize() + } + + fn dnum(&self) -> Dnum { + self.key.dnum() + } +} + +impl LWEInfos for GLWEAutomorphismKeyLayout { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn n(&self) -> Degree { + self.n + } +} + +impl GLWEInfos for GLWEAutomorphismKeyLayout { + fn rank(&self) -> Rank { + self.rank + } +} + +impl GGLWEInfos for GLWEAutomorphismKeyLayout { + fn rank_in(&self) -> Rank { + self.rank + } + + fn dsize(&self) -> Dsize { + self.dsize + } + + fn rank_out(&self) -> Rank { + self.rank + } + + fn dnum(&self) -> Dnum { + self.dnum + } +} + +impl<D: DataRef> fmt::Debug for GLWEAutomorphismKey<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for GLWEAutomorphismKey<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.key.fill_uniform(log_bound, source); + } +} + +impl<D: DataRef> fmt::Display for GLWEAutomorphismKey<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(AutomorphismKey: p={}) {}", self.p, self.key) + } +} + +impl GLWEAutomorphismKey<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { + GLWEAutomorphismKey { + key: GGLWE::alloc(n, base2k, k, rank, rank, dnum, dsize), + p: 0, + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_in(), + infos.rank_out(), + "rank_in != rank_out is not supported for AutomorphismKey" + ); + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { + GGLWE::bytes_of(n, base2k, k, rank, rank, dnum, dsize) + } +} + +impl<D: DataMut> GGLWEToMut for GLWEAutomorphismKey<D> { + fn to_mut(&mut self) -> GGLWE<&mut [u8]> { + self.key.to_mut() + } +} + +impl<D: DataMut> GGLWEToRef for GLWEAutomorphismKey<D> { + fn to_ref(&self) -> GGLWE<&[u8]> { + self.key.to_ref() + } +} + +impl<D: DataRef> GLWEAutomorphismKey<D> { + pub fn at(&self, row: usize, col: usize) -> GLWE<&[u8]> { + self.key.at(row, col) + } +} + +impl<D: DataMut> GLWEAutomorphismKey<D> { + pub fn at_mut(&mut self, row: usize, col: usize) -> GLWE<&mut [u8]> { + self.key.at_mut(row, col) + } +} + +impl<D: DataMut> ReaderFrom for GLWEAutomorphismKey<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.p = reader.read_u64::<LittleEndian>()? as i64; + self.key.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GLWEAutomorphismKey<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u64::<LittleEndian>(self.p as u64)?; + self.key.write_to(writer) + } +}
@@ -1,300 +0,0 @@
-use poulpy_hal::{ - layouts::{ - Data, DataMut, DataRef, FillUniform, ReaderFrom, ToOwnedDeep, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo, ZnxInfos, - }, - source::Source, -}; - -use crate::layouts::{Base2K, BuildError, Degree, LWEInfos, Rank, TorusPrecision}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::fmt; - -pub trait GLWEInfos -where - Self: LWEInfos, -{ - fn rank(&self) -> Rank; - fn glwe_layout(&self) -> GLWECiphertextLayout { - GLWECiphertextLayout { - n: self.n(), - base2k: self.base2k(), - k: self.k(), - rank: self.rank(), - } - } -} - -pub trait GLWELayoutSet { - fn set_k(&mut self, k: TorusPrecision); - fn set_basek(&mut self, base2k: Base2K); -} - -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct GLWECiphertextLayout { - pub n: Degree, - pub base2k: Base2K, - pub k: TorusPrecision, - pub rank: Rank, -} - -impl LWEInfos for GLWECiphertextLayout { - fn n(&self) -> Degree { - self.n - } - - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } -} - -impl GLWEInfos for GLWECiphertextLayout { - fn rank(&self) -> Rank { - self.rank - } -} - -#[derive(PartialEq, Eq, Clone)] -pub struct GLWECiphertext<D: Data> { - pub(crate) data: VecZnx<D>, - pub(crate) base2k: Base2K, - pub(crate) k: TorusPrecision, -} - -impl<D: DataMut> GLWELayoutSet for GLWECiphertext<D> { - fn set_basek(&mut self, base2k: Base2K) { - self.base2k = base2k - } - - fn set_k(&mut self, k: TorusPrecision) { - self.k = k - } -} - -impl<D: DataRef> GLWECiphertext<D> { - pub fn data(&self) -> &VecZnx<D> { - &self.data - } -} - -impl<D: DataMut> GLWECiphertext<D> { - pub fn data_mut(&mut self) -> &mut VecZnx<D> { - &mut self.data - } -} - -pub struct GLWECiphertextBuilder<D: Data> { - data: Option<VecZnx<D>>, - base2k: Option<Base2K>, - k: Option<TorusPrecision>, -} - -impl<D: Data> GLWECiphertext<D> { - #[inline] - pub fn builder() -> GLWECiphertextBuilder<D> { - GLWECiphertextBuilder { - data: None, - base2k: None, - k: None, - } - } -} - -impl GLWECiphertextBuilder<Vec<u8>> { - #[inline] - pub fn layout<A>(mut self, layout: &A) -> Self - where - A: GLWEInfos, - { - self.data = Some(VecZnx::alloc( - layout.n().into(), - (layout.rank() + 1).into(), - layout.size(), - )); - self.base2k = Some(layout.base2k()); - self.k = Some(layout.k()); - self - } -} - -impl<D: Data> GLWECiphertextBuilder<D> { - #[inline] - pub fn data(mut self, data: VecZnx<D>) -> Self { - self.data = Some(data); - self - } - #[inline] - pub fn base2k(mut self, base2k: Base2K) -> Self { - self.base2k = Some(base2k); - self - } - #[inline] - pub fn k(mut self, k: TorusPrecision) -> Self { - self.k = Some(k); - self - } - - pub fn build(self) -> Result<GLWECiphertext<D>, BuildError> { - let data: VecZnx<D> = self.data.ok_or(BuildError::MissingData)?; - let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; - let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - - if base2k == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if k == 0_u32 { - return Err(BuildError::ZeroTorusPrecision); - } - - if data.n() == 0 { - return Err(BuildError::ZeroDegree); - } - - if data.cols() == 0 { - return Err(BuildError::ZeroCols); - } - - if data.size() == 0 { - return Err(BuildError::ZeroLimbs); - } - - Ok(GLWECiphertext { data, base2k, k }) - } -} - -impl<D: Data> LWEInfos for GLWECiphertext<D> { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - fn size(&self) -> usize { - self.data.size() - } -} - -impl<D: Data> GLWEInfos for GLWECiphertext<D> { - fn rank(&self) -> Rank { - Rank(self.data.cols() as u32 - 1) - } -} - -impl<D: DataRef> ToOwnedDeep for GLWECiphertext<D> { - type Owned = GLWECiphertext<Vec<u8>>; - fn to_owned_deep(&self) -> Self::Owned { - GLWECiphertext { - data: self.data.to_owned_deep(), - k: self.k, - base2k: self.base2k, - } - } -} - -impl<D: DataRef> fmt::Debug for GLWECiphertext<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataRef> fmt::Display for GLWECiphertext<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GLWECiphertext: base2k={} k={}: {}", - self.base2k().0, - self.k().0, - self.data - ) - } -} - -impl<D: DataMut> FillUniform for GLWECiphertext<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.data.fill_uniform(log_bound, source); - } -} - -impl GLWECiphertext<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GLWEInfos, - { - Self::alloc_with(infos.n(), infos.base2k(), infos.k(), infos.rank()) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self { - Self { - data: VecZnx::alloc(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize), - base2k, - k, - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GLWEInfos, - { - Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k(), infos.rank()) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize { - VecZnx::alloc_bytes(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize) - } -} - -pub trait GLWECiphertextToRef { - fn to_ref(&self) -> GLWECiphertext<&[u8]>; -} - -impl<D: DataRef> GLWECiphertextToRef for GLWECiphertext<D> { - fn to_ref(&self) -> GLWECiphertext<&[u8]> { - GLWECiphertext::builder() - .k(self.k()) - .base2k(self.base2k()) - .data(self.data.to_ref()) - .build() - .unwrap() - } -} - -pub trait GLWECiphertextToMut { - fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]>; -} - -impl<D: DataMut> GLWECiphertextToMut for GLWECiphertext<D> { - fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]> { - GLWECiphertext::builder() - .k(self.k()) - .base2k(self.base2k()) - .data(self.data.to_mut()) - .build() - .unwrap() - } -} - -impl<D: DataMut> ReaderFrom for GLWECiphertext<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); - self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.data.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GLWECiphertext<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u32::<LittleEndian>(self.k.0)?; - writer.write_u32::<LittleEndian>(self.base2k.0)?; - self.data.write_to(writer) - } -}
@@ -1,209 +0,0 @@
-use poulpy_hal::layouts::{Data, DataMut, DataRef, ReaderFrom, VecZnx, WriterTo, ZnxInfos}; - -use crate::{ - dist::Distribution, - layouts::{Base2K, BuildError, Degree, GLWEInfos, LWEInfos, Rank, TorusPrecision}, -}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -#[derive(PartialEq, Eq)] -pub struct GLWEPublicKey<D: Data> { - pub(crate) data: VecZnx<D>, - pub(crate) base2k: Base2K, - pub(crate) k: TorusPrecision, - pub(crate) dist: Distribution, -} - -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct GLWEPublicKeyLayout { - pub n: Degree, - pub base2k: Base2K, - pub k: TorusPrecision, - pub rank: Rank, -} - -impl<D: Data> LWEInfos for GLWEPublicKey<D> { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - fn size(&self) -> usize { - self.data.size() - } -} - -impl<D: Data> GLWEInfos for GLWEPublicKey<D> { - fn rank(&self) -> Rank { - Rank(self.data.cols() as u32 - 1) - } -} - -impl LWEInfos for GLWEPublicKeyLayout { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn n(&self) -> Degree { - self.n - } - - fn size(&self) -> usize { - self.k.0.div_ceil(self.base2k.0) as usize - } -} - -impl GLWEInfos for GLWEPublicKeyLayout { - fn rank(&self) -> Rank { - self.rank - } -} - -pub struct GLWEPublicKeyBuilder<D: Data> { - data: Option<VecZnx<D>>, - base2k: Option<Base2K>, - k: Option<TorusPrecision>, -} - -impl<D: Data> GLWEPublicKey<D> { - #[inline] - pub fn builder() -> GLWEPublicKeyBuilder<D> { - GLWEPublicKeyBuilder { - data: None, - base2k: None, - k: None, - } - } -} - -impl GLWEPublicKeyBuilder<Vec<u8>> { - #[inline] - pub fn layout<A>(mut self, layout: &A) -> Self - where - A: GLWEInfos, - { - self.data = Some(VecZnx::alloc( - layout.n().into(), - (layout.rank() + 1).into(), - layout.size(), - )); - self.base2k = Some(layout.base2k()); - self.k = Some(layout.k()); - self - } -} - -impl<D: Data> GLWEPublicKeyBuilder<D> { - #[inline] - pub fn data(mut self, data: VecZnx<D>) -> Self { - self.data = Some(data); - self - } - #[inline] - pub fn base2k(mut self, base2k: Base2K) -> Self { - self.base2k = Some(base2k); - self - } - #[inline] - pub fn k(mut self, k: TorusPrecision) -> Self { - self.k = Some(k); - self - } - - pub fn build(self) -> Result<GLWEPublicKey<D>, BuildError> { - let data: VecZnx<D> = self.data.ok_or(BuildError::MissingData)?; - let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; - let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - - if base2k == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if k == 0_u32 { - return Err(BuildError::ZeroTorusPrecision); - } - - if data.n() == 0 { - return Err(BuildError::ZeroDegree); - } - - if data.cols() == 0 { - return Err(BuildError::ZeroCols); - } - - if data.size() == 0 { - return Err(BuildError::ZeroLimbs); - } - - Ok(GLWEPublicKey { - data, - base2k, - k, - dist: Distribution::NONE, - }) - } -} - -impl GLWEPublicKey<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GLWEInfos, - { - Self::alloc_with(infos.n(), infos.base2k(), infos.k(), infos.rank()) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self { - Self { - data: VecZnx::alloc(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize), - base2k, - k, - dist: Distribution::NONE, - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GLWEInfos, - { - Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k(), infos.rank()) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize { - VecZnx::alloc_bytes(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize) - } -} - -impl<D: DataMut> ReaderFrom for GLWEPublicKey<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); - self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - match Distribution::read_from(reader) { - Ok(dist) => self.dist = dist, - Err(e) => return Err(e), - } - self.data.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GLWEPublicKey<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u32::<LittleEndian>(self.k.0)?; - writer.write_u32::<LittleEndian>(self.base2k.0)?; - match self.dist.write_to(writer) { - Ok(()) => {} - Err(e) => return Err(e), - } - self.data.write_to(writer) - } -}
@@ -0,0 +1,160 @@
+use std::fmt; + +use poulpy_hal::layouts::{Data, DataMut, DataRef, VecZnx, VecZnxToMut, VecZnxToRef, ZnxInfos}; + +use crate::layouts::{Base2K, Degree, GLWE, GLWEInfos, GLWEToMut, GLWEToRef, LWEInfos, Rank, SetGLWEInfos, TorusPrecision}; + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub struct GLWEPlaintextLayout { + pub n: Degree, + pub base2k: Base2K, + pub k: TorusPrecision, +} + +impl LWEInfos for GLWEPlaintextLayout { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn n(&self) -> Degree { + self.n + } +} + +impl GLWEInfos for GLWEPlaintextLayout { + fn rank(&self) -> Rank { + Rank(0) + } +} + +pub struct GLWEPlaintext<D: Data> { + pub data: VecZnx<D>, + pub base2k: Base2K, + pub k: TorusPrecision, +} + +impl<D: DataMut> SetGLWEInfos for GLWEPlaintext<D> { + fn set_base2k(&mut self, base2k: Base2K) { + self.base2k = base2k + } + + fn set_k(&mut self, k: TorusPrecision) { + self.k = k + } +} + +impl<D: Data> LWEInfos for GLWEPlaintext<D> { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn size(&self) -> usize { + self.data.size() + } + + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } +} + +impl<D: Data> GLWEInfos for GLWEPlaintext<D> { + fn rank(&self) -> Rank { + Rank(self.data.cols() as u32 - 1) + } +} + +impl<D: DataRef> fmt::Display for GLWEPlaintext<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "GLWEPlaintext: base2k={} k={}: {}", + self.base2k().0, + self.k().0, + self.data + ) + } +} + +impl GLWEPlaintext<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GLWEInfos, + { + Self::alloc(infos.n(), infos.base2k(), infos.k()) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision) -> Self { + GLWEPlaintext { + data: VecZnx::alloc(n.into(), 1, k.0.div_ceil(base2k.0) as usize), + base2k, + k, + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GLWEInfos, + { + Self::bytes_of(infos.n(), infos.base2k(), infos.k()) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision) -> usize { + VecZnx::bytes_of(n.into(), 1, k.0.div_ceil(base2k.0) as usize) + } +} + +impl<D: DataRef> GLWEToRef for GLWEPlaintext<D> { + fn to_ref(&self) -> GLWE<&[u8]> { + GLWE { + k: self.k, + base2k: self.base2k, + data: self.data.to_ref(), + } + } +} + +impl<D: DataMut> GLWEToMut for GLWEPlaintext<D> { + fn to_mut(&mut self) -> GLWE<&mut [u8]> { + GLWE { + k: self.k, + base2k: self.base2k, + data: self.data.to_mut(), + } + } +} + +pub trait GLWEPlaintextToRef { + fn to_ref(&self) -> GLWEPlaintext<&[u8]>; +} + +impl<D: DataRef> GLWEPlaintextToRef for GLWEPlaintext<D> { + fn to_ref(&self) -> GLWEPlaintext<&[u8]> { + GLWEPlaintext { + data: self.data.to_ref(), + base2k: self.base2k, + k: self.k, + } + } +} + +pub trait GLWEPlaintextToMut { + fn to_ref(&mut self) -> GLWEPlaintext<&mut [u8]>; +} + +impl<D: DataMut> GLWEPlaintextToMut for GLWEPlaintext<D> { + fn to_ref(&mut self) -> GLWEPlaintext<&mut [u8]> { + GLWEPlaintext { + base2k: self.base2k, + k: self.k, + data: self.data.to_mut(), + } + } +}
@@ -1,202 +0,0 @@
-use std::fmt; - -use poulpy_hal::layouts::{Data, DataMut, DataRef, VecZnx, VecZnxToMut, VecZnxToRef, ZnxInfos}; - -use crate::layouts::{ - Base2K, BuildError, Degree, GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, GLWEInfos, GLWELayoutSet, LWEInfos, - Rank, TorusPrecision, -}; - -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct GLWEPlaintextLayout { - pub n: Degree, - pub base2k: Base2K, - pub k: TorusPrecision, -} - -impl LWEInfos for GLWEPlaintextLayout { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn n(&self) -> Degree { - self.n - } -} - -impl GLWEInfos for GLWEPlaintextLayout { - fn rank(&self) -> Rank { - Rank(0) - } -} - -pub struct GLWEPlaintext<D: Data> { - pub data: VecZnx<D>, - pub base2k: Base2K, - pub k: TorusPrecision, -} - -impl<D: DataMut> GLWELayoutSet for GLWEPlaintext<D> { - fn set_basek(&mut self, base2k: Base2K) { - self.base2k = base2k - } - - fn set_k(&mut self, k: TorusPrecision) { - self.k = k - } -} - -impl<D: Data> LWEInfos for GLWEPlaintext<D> { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn size(&self) -> usize { - self.data.size() - } - - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } -} - -impl<D: Data> GLWEInfos for GLWEPlaintext<D> { - fn rank(&self) -> Rank { - Rank(self.data.cols() as u32 - 1) - } -} - -pub struct GLWEPlaintextBuilder<D: Data> { - data: Option<VecZnx<D>>, - base2k: Option<Base2K>, - k: Option<TorusPrecision>, -} - -impl<D: Data> GLWEPlaintext<D> { - #[inline] - pub fn builder() -> GLWEPlaintextBuilder<D> { - GLWEPlaintextBuilder { - data: None, - base2k: None, - k: None, - } - } -} - -impl<D: Data> GLWEPlaintextBuilder<D> { - #[inline] - pub fn data(mut self, data: VecZnx<D>) -> Self { - self.data = Some(data); - self - } - #[inline] - pub fn base2k(mut self, base2k: Base2K) -> Self { - self.base2k = Some(base2k); - self - } - #[inline] - pub fn k(mut self, k: TorusPrecision) -> Self { - self.k = Some(k); - self - } - - pub fn build(self) -> Result<GLWEPlaintext<D>, BuildError> { - let data: VecZnx<D> = self.data.ok_or(BuildError::MissingData)?; - let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; - let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - - if base2k.0 == 0 { - return Err(BuildError::ZeroBase2K); - } - - if k.0 == 0 { - return Err(BuildError::ZeroTorusPrecision); - } - - if data.n() == 0 { - return Err(BuildError::ZeroDegree); - } - - if data.cols() != 1 { - return Err(BuildError::ZeroCols); - } - - if data.size() == 0 { - return Err(BuildError::ZeroLimbs); - } - - Ok(GLWEPlaintext { data, base2k, k }) - } -} - -impl<D: DataRef> fmt::Display for GLWEPlaintext<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GLWEPlaintext: base2k={} k={}: {}", - self.base2k().0, - self.k().0, - self.data - ) - } -} - -impl GLWEPlaintext<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GLWEInfos, - { - Self::alloc_with(infos.n(), infos.base2k(), infos.k(), Rank(0)) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self { - debug_assert!(rank.0 == 0); - Self { - data: VecZnx::alloc(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize), - base2k, - k, - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GLWEInfos, - { - Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k(), Rank(0)) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize { - debug_assert!(rank.0 == 0); - VecZnx::alloc_bytes(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize) - } -} - -impl<D: DataRef> GLWECiphertextToRef for GLWEPlaintext<D> { - fn to_ref(&self) -> GLWECiphertext<&[u8]> { - GLWECiphertext::builder() - .data(self.data.to_ref()) - .k(self.k()) - .base2k(self.base2k()) - .build() - .unwrap() - } -} - -impl<D: DataMut> GLWECiphertextToMut for GLWEPlaintext<D> { - fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]> { - GLWECiphertext::builder() - .k(self.k()) - .base2k(self.base2k()) - .data(self.data.to_mut()) - .build() - .unwrap() - } -}
@@ -0,0 +1,140 @@
+use poulpy_hal::layouts::{Data, DataMut, DataRef, ReaderFrom, VecZnx, WriterTo}; + +use crate::{ + GetDistribution, GetDistributionMut, + dist::Distribution, + layouts::{Base2K, Degree, GLWE, GLWEInfos, GLWEToMut, GLWEToRef, LWEInfos, Rank, TorusPrecision}, +}; + +#[derive(PartialEq, Eq)] +pub struct GLWEPublicKey<D: Data> { + pub(crate) key: GLWE<D>, + pub(crate) dist: Distribution, +} + +impl<D: DataMut> GetDistributionMut for GLWEPublicKey<D> { + fn dist_mut(&mut self) -> &mut Distribution { + &mut self.dist + } +} + +impl<D: DataRef> GetDistribution for GLWEPublicKey<D> { + fn dist(&self) -> &Distribution { + &self.dist + } +} + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub struct GLWEPublicKeyLayout { + pub n: Degree, + pub base2k: Base2K, + pub k: TorusPrecision, + pub rank: Rank, +} + +impl<D: Data> LWEInfos for GLWEPublicKey<D> { + fn base2k(&self) -> Base2K { + self.key.base2k() + } + + fn k(&self) -> TorusPrecision { + self.key.k() + } + + fn n(&self) -> Degree { + self.key.n() + } + + fn size(&self) -> usize { + self.key.size() + } +} + +impl<D: Data> GLWEInfos for GLWEPublicKey<D> { + fn rank(&self) -> Rank { + self.key.rank() + } +} + +impl LWEInfos for GLWEPublicKeyLayout { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn n(&self) -> Degree { + self.n + } + + fn size(&self) -> usize { + self.k.0.div_ceil(self.base2k.0) as usize + } +} + +impl GLWEInfos for GLWEPublicKeyLayout { + fn rank(&self) -> Rank { + self.rank + } +} + +impl GLWEPublicKey<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GLWEInfos, + { + Self::alloc(infos.n(), infos.base2k(), infos.k(), infos.rank()) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self { + GLWEPublicKey { + key: GLWE::alloc(n, base2k, k, rank), + dist: Distribution::NONE, + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GLWEInfos, + { + Self::bytes_of(infos.n(), infos.base2k(), infos.k(), infos.rank()) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize { + VecZnx::bytes_of(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize) + } +} + +impl<D: DataMut> ReaderFrom for GLWEPublicKey<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + match Distribution::read_from(reader) { + Ok(dist) => self.dist = dist, + Err(e) => return Err(e), + } + self.key.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GLWEPublicKey<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + match self.dist.write_to(writer) { + Ok(()) => {} + Err(e) => return Err(e), + } + self.key.write_to(writer) + } +} + +impl<D: DataRef> GLWEToRef for GLWEPublicKey<D> { + fn to_ref(&self) -> GLWE<&[u8]> { + self.key.to_ref() + } +} + +impl<D: DataMut> GLWEToMut for GLWEPublicKey<D> { + fn to_mut(&mut self) -> GLWE<&mut [u8]> { + self.key.to_mut() + } +}
@@ -1,9 +1,10 @@
use poulpy_hal::{ - layouts::{Data, DataMut, DataRef, ReaderFrom, ScalarZnx, WriterTo, ZnxInfos, ZnxZero}, + layouts::{Data, DataMut, DataRef, ReaderFrom, ScalarZnx, ScalarZnxToMut, ScalarZnxToRef, WriterTo, ZnxInfos, ZnxZero}, source::Source, }; use crate::{ + GetDistribution, dist::Distribution, layouts::{Base2K, Degree, GLWEInfos, LWEInfos, Rank, TorusPrecision}, };@@ -61,6 +62,12 @@ 1
} } +impl<D: Data> GetDistribution for GLWESecret<D> { + fn dist(&self) -> &Distribution { + &self.dist + } +} + impl<D: Data> GLWEInfos for GLWESecret<D> { fn rank(&self) -> Rank { Rank(self.data.cols() as u32)@@ -68,29 +75,29 @@ }
} impl GLWESecret<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self + pub fn alloc_from_infos<A>(infos: &A) -> Self where A: GLWEInfos, { - Self::alloc_with(infos.n(), infos.rank()) + Self::alloc(infos.n(), infos.rank()) } - pub fn alloc_with(n: Degree, rank: Rank) -> Self { - Self { + pub fn alloc(n: Degree, rank: Rank) -> Self { + GLWESecret { data: ScalarZnx::alloc(n.into(), rank.into()), dist: Distribution::NONE, } } - pub fn alloc_bytes<A>(infos: &A) -> usize + pub fn bytes_of_from_infos<A>(infos: &A) -> usize where A: GLWEInfos, { - Self::alloc_bytes_with(infos.n(), infos.rank()) + Self::bytes_of(infos.n(), infos.rank()) } - pub fn alloc_bytes_with(n: Degree, rank: Rank) -> usize { - ScalarZnx::alloc_bytes(n.into(), rank.into()) + pub fn bytes_of(n: Degree, rank: Rank) -> usize { + ScalarZnx::bytes_of(n.into(), rank.into()) } }@@ -133,6 +140,32 @@
pub fn fill_zero(&mut self) { self.data.zero(); self.dist = Distribution::ZERO; + } +} + +pub trait GLWESecretToMut { + fn to_mut(&mut self) -> GLWESecret<&mut [u8]>; +} + +impl<D: DataMut> GLWESecretToMut for GLWESecret<D> { + fn to_mut(&mut self) -> GLWESecret<&mut [u8]> { + GLWESecret { + dist: self.dist, + data: self.data.to_mut(), + } + } +} + +pub trait GLWESecretToRef { + fn to_ref(&self) -> GLWESecret<&[u8]>; +} + +impl<D: DataRef> GLWESecretToRef for GLWESecret<D> { + fn to_ref(&self) -> GLWESecret<&[u8]> { + GLWESecret { + data: self.data.to_ref(), + dist: self.dist, + } } }
@@ -0,0 +1,255 @@
+use poulpy_hal::{ + layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo}, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToMut, GGLWEToRef, GLWE, GLWEInfos, LWEInfos, Rank, TorusPrecision, +}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +use std::fmt; + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub struct GLWESwitchingKeyLayout { + pub n: Degree, + pub base2k: Base2K, + pub k: TorusPrecision, + pub rank_in: Rank, + pub rank_out: Rank, + pub dnum: Dnum, + pub dsize: Dsize, +} + +impl LWEInfos for GLWESwitchingKeyLayout { + fn n(&self) -> Degree { + self.n + } + + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } +} + +impl GLWEInfos for GLWESwitchingKeyLayout { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl GGLWEInfos for GLWESwitchingKeyLayout { + fn rank_in(&self) -> Rank { + self.rank_in + } + + fn rank_out(&self) -> Rank { + self.rank_out + } + + fn dsize(&self) -> Dsize { + self.dsize + } + + fn dnum(&self) -> Dnum { + self.dnum + } +} + +#[derive(PartialEq, Eq, Clone)] +pub struct GLWESwitchingKey<D: Data> { + pub(crate) key: GGLWE<D>, + pub(crate) input_degree: Degree, // Degree of sk_in + pub(crate) output_degree: Degree, // Degree of sk_out +} + +pub trait GLWESwitchingKeyDegrees { + fn input_degree(&self) -> &Degree; + fn output_degree(&self) -> &Degree; +} + +impl<D: DataRef> GLWESwitchingKeyDegrees for GLWESwitchingKey<D> { + fn output_degree(&self) -> &Degree { + &self.output_degree + } + + fn input_degree(&self) -> &Degree { + &self.input_degree + } +} + +pub trait GLWESwitchingKeyDegreesMut { + fn input_degree(&mut self) -> &mut Degree; + fn output_degree(&mut self) -> &mut Degree; +} + +impl<D: DataMut> GLWESwitchingKeyDegreesMut for GLWESwitchingKey<D> { + fn output_degree(&mut self) -> &mut Degree { + &mut self.output_degree + } + + fn input_degree(&mut self) -> &mut Degree { + &mut self.input_degree + } +} + +impl<D: Data> LWEInfos for GLWESwitchingKey<D> { + fn n(&self) -> Degree { + self.key.n() + } + + fn base2k(&self) -> Base2K { + self.key.base2k() + } + + fn k(&self) -> TorusPrecision { + self.key.k() + } + + fn size(&self) -> usize { + self.key.size() + } +} + +impl<D: Data> GLWEInfos for GLWESwitchingKey<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data> GGLWEInfos for GLWESwitchingKey<D> { + fn rank_in(&self) -> Rank { + self.key.rank_in() + } + + fn rank_out(&self) -> Rank { + self.key.rank_out() + } + + fn dsize(&self) -> Dsize { + self.key.dsize() + } + + fn dnum(&self) -> Dnum { + self.key.dnum() + } +} + +impl<D: DataRef> fmt::Debug for GLWESwitchingKey<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataRef> fmt::Display for GLWESwitchingKey<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "(GLWESwitchingKey: sk_in_n={} sk_out_n={}) {}", + self.input_degree, + self.output_degree, + self.key.data() + ) + } +} + +impl<D: DataMut> FillUniform for GLWESwitchingKey<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.key.fill_uniform(log_bound, source); + } +} + +impl GLWESwitchingKey<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.rank_out(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, rank_out: Rank, dnum: Dnum, dsize: Dsize) -> Self { + GLWESwitchingKey { + key: GGLWE::alloc(n, base2k, k, rank_in, rank_out, dnum, dsize), + input_degree: Degree(0), + output_degree: Degree(0), + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.rank_out(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn bytes_of( + n: Degree, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> usize { + GGLWE::bytes_of(n, base2k, k, rank_in, rank_out, dnum, dsize) + } +} + +impl<D: DataMut> GGLWEToMut for GLWESwitchingKey<D> { + fn to_mut(&mut self) -> GGLWE<&mut [u8]> { + self.key.to_mut() + } +} + +impl<D: DataRef> GGLWEToRef for GLWESwitchingKey<D> { + fn to_ref(&self) -> GGLWE<&[u8]> { + self.key.to_ref() + } +} + +impl<D: DataRef> GLWESwitchingKey<D> { + pub fn at(&self, row: usize, col: usize) -> GLWE<&[u8]> { + self.key.at(row, col) + } +} + +impl<D: DataMut> GLWESwitchingKey<D> { + pub fn at_mut(&mut self, row: usize, col: usize) -> GLWE<&mut [u8]> { + self.key.at_mut(row, col) + } +} + +impl<D: DataMut> ReaderFrom for GLWESwitchingKey<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.input_degree = Degree(reader.read_u32::<LittleEndian>()?); + self.output_degree = Degree(reader.read_u32::<LittleEndian>()?); + self.key.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GLWESwitchingKey<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u32::<LittleEndian>(self.input_degree.into())?; + writer.write_u32::<LittleEndian>(self.output_degree.into())?; + self.key.write_to(writer) + } +}
@@ -0,0 +1,262 @@
+use poulpy_hal::{ + layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo}, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToMut, GGLWEToRef, GLWEInfos, LWEInfos, Rank, TorusPrecision, +}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +use std::fmt; + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub struct GLWETensorKeyLayout { + pub n: Degree, + pub base2k: Base2K, + pub k: TorusPrecision, + pub rank: Rank, + pub dnum: Dnum, + pub dsize: Dsize, +} + +#[derive(PartialEq, Eq, Clone)] +pub struct GLWETensorKey<D: Data> { + pub(crate) keys: Vec<GGLWE<D>>, +} + +impl<D: Data> LWEInfos for GLWETensorKey<D> { + fn n(&self) -> Degree { + self.keys[0].n() + } + + fn base2k(&self) -> Base2K { + self.keys[0].base2k() + } + + fn k(&self) -> TorusPrecision { + self.keys[0].k() + } + + fn size(&self) -> usize { + self.keys[0].size() + } +} + +impl<D: Data> GLWEInfos for GLWETensorKey<D> { + fn rank(&self) -> Rank { + self.keys[0].rank_out() + } +} + +impl<D: Data> GGLWEInfos for GLWETensorKey<D> { + fn rank_in(&self) -> Rank { + self.rank_out() + } + + fn rank_out(&self) -> Rank { + self.keys[0].rank_out() + } + + fn dsize(&self) -> Dsize { + self.keys[0].dsize() + } + + fn dnum(&self) -> Dnum { + self.keys[0].dnum() + } +} + +impl LWEInfos for GLWETensorKeyLayout { + fn n(&self) -> Degree { + self.n + } + + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } +} + +impl GLWEInfos for GLWETensorKeyLayout { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl GGLWEInfos for GLWETensorKeyLayout { + fn rank_in(&self) -> Rank { + self.rank + } + + fn dsize(&self) -> Dsize { + self.dsize + } + + fn rank_out(&self) -> Rank { + self.rank + } + + fn dnum(&self) -> Dnum { + self.dnum + } +} + +impl<D: DataRef> fmt::Debug for GLWETensorKey<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for GLWETensorKey<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.keys + .iter_mut() + .for_each(|key: &mut GGLWE<D>| key.fill_uniform(log_bound, source)) + } +} + +impl<D: DataRef> fmt::Display for GLWETensorKey<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "(GLWETensorKey)",)?; + for (i, key) in self.keys.iter().enumerate() { + write!(f, "{i}: {key}")?; + } + Ok(()) + } +} + +impl GLWETensorKey<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_in(), + infos.rank_out(), + "rank_in != rank_out is not supported for GGLWETensorKey" + ); + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self { + let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1); + GLWETensorKey { + keys: (0..pairs) + .map(|_| GGLWE::alloc(n, base2k, k, Rank(1), rank, dnum, dsize)) + .collect(), + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_in(), + infos.rank_out(), + "rank_in != rank_out is not supported for GGLWETensorKey" + ); + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { + let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize; + pairs * GGLWE::bytes_of(n, base2k, k, Rank(1), rank, dnum, dsize) + } +} + +impl<D: DataMut> GLWETensorKey<D> { + // Returns a mutable reference to GGLWE_{s}(s[i] * s[j]) + pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWE<D> { + if i > j { + std::mem::swap(&mut i, &mut j); + }; + let rank: usize = self.rank_out().into(); + &mut self.keys[i * rank + j - (i * (i + 1) / 2)] + } +} + +impl<D: DataRef> GLWETensorKey<D> { + // Returns a reference to GGLWE_{s}(s[i] * s[j]) + pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWE<D> { + if i > j { + std::mem::swap(&mut i, &mut j); + }; + let rank: usize = self.rank_out().into(); + &self.keys[i * rank + j - (i * (i + 1) / 2)] + } +} + +impl<D: DataMut> ReaderFrom for GLWETensorKey<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + let len: usize = reader.read_u64::<LittleEndian>()? as usize; + if self.keys.len() != len { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("self.keys.len()={} != read len={}", self.keys.len(), len), + )); + } + for key in &mut self.keys { + key.read_from(reader)?; + } + Ok(()) + } +} + +impl<D: DataRef> WriterTo for GLWETensorKey<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u64::<LittleEndian>(self.keys.len() as u64)?; + for key in &self.keys { + key.write_to(writer)?; + } + Ok(()) + } +} + +pub trait GLWETensorKeyToRef { + fn to_ref(&self) -> GLWETensorKey<&[u8]>; +} + +impl<D: DataRef> GLWETensorKeyToRef for GLWETensorKey<D> +where + GGLWE<D>: GGLWEToRef, +{ + fn to_ref(&self) -> GLWETensorKey<&[u8]> { + GLWETensorKey { + keys: self.keys.iter().map(|c| c.to_ref()).collect(), + } + } +} + +pub trait GLWETensorKeyToMut { + fn to_mut(&mut self) -> GLWETensorKey<&mut [u8]>; +} + +impl<D: DataMut> GLWETensorKeyToMut for GLWETensorKey<D> +where + GGLWE<D>: GGLWEToMut, +{ + fn to_mut(&mut self) -> GLWETensorKey<&mut [u8]> { + GLWETensorKey { + keys: self.keys.iter_mut().map(|c| c.to_mut()).collect(), + } + } +}
@@ -1,182 +0,0 @@
-use poulpy_hal::{ - layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo}, - source::Source, -}; - -use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision}; - -use std::fmt; - -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct GLWEToLWEKeyLayout { - pub n: Degree, - pub base2k: Base2K, - pub k: TorusPrecision, - pub rank_in: Rank, - pub dnum: Dnum, -} - -impl LWEInfos for GLWEToLWEKeyLayout { - fn n(&self) -> Degree { - self.n - } - - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } -} - -impl GLWEInfos for GLWEToLWEKeyLayout { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl GGLWEInfos for GLWEToLWEKeyLayout { - fn rank_in(&self) -> Rank { - self.rank_in - } - - fn dsize(&self) -> Dsize { - Dsize(1) - } - - fn rank_out(&self) -> Rank { - Rank(1) - } - - fn dnum(&self) -> Dnum { - self.dnum - } -} - -/// A special [GLWESwitchingKey] required to for the conversion from [GLWECiphertext] to [LWECiphertext]. -#[derive(PartialEq, Eq, Clone)] -pub struct GLWEToLWEKey<D: Data>(pub(crate) GGLWESwitchingKey<D>); - -impl<D: Data> LWEInfos for GLWEToLWEKey<D> { - fn base2k(&self) -> Base2K { - self.0.base2k() - } - - fn k(&self) -> TorusPrecision { - self.0.k() - } - - fn n(&self) -> Degree { - self.0.n() - } - - fn size(&self) -> usize { - self.0.size() - } -} - -impl<D: Data> GLWEInfos for GLWEToLWEKey<D> { - fn rank(&self) -> Rank { - self.rank_out() - } -} -impl<D: Data> GGLWEInfos for GLWEToLWEKey<D> { - fn rank_in(&self) -> Rank { - self.0.rank_in() - } - - fn dsize(&self) -> Dsize { - self.0.dsize() - } - - fn rank_out(&self) -> Rank { - self.0.rank_out() - } - - fn dnum(&self) -> Dnum { - self.0.dnum() - } -} - -impl<D: DataRef> fmt::Debug for GLWEToLWEKey<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataMut> FillUniform for GLWEToLWEKey<D> { - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.0.fill_uniform(log_bound, source); - } -} - -impl<D: DataRef> fmt::Display for GLWEToLWEKey<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "(GLWEToLWESwitchingKey) {}", self.0) - } -} - -impl<D: DataMut> ReaderFrom for GLWEToLWEKey<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.0.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for GLWEToLWEKey<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - self.0.write_to(writer) - } -} - -impl GLWEToLWEKey<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: GGLWEInfos, - { - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is not supported for GLWEToLWESwitchingKey" - ); - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for GLWEToLWESwitchingKey" - ); - Self(GGLWESwitchingKey::alloc(infos)) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self { - Self(GGLWESwitchingKey::alloc_with( - n, - base2k, - k, - rank_in, - Rank(1), - dnum, - Dsize(1), - )) - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: GGLWEInfos, - { - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is not supported for GLWEToLWESwitchingKey" - ); - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for GLWEToLWESwitchingKey" - ); - GGLWESwitchingKey::alloc_bytes(infos) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize { - GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, rank_in, Rank(1), dnum, Dsize(1)) - } -}
@@ -0,0 +1,229 @@
+use poulpy_hal::{ + layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo}, + source::Source, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToMut, GGLWEToRef, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeyDegrees, + GLWESwitchingKeyDegreesMut, LWEInfos, Rank, TorusPrecision, +}; + +use std::fmt; + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub struct GLWEToLWEKeyLayout { + pub n: Degree, + pub base2k: Base2K, + pub k: TorusPrecision, + pub rank_in: Rank, + pub dnum: Dnum, +} + +impl LWEInfos for GLWEToLWEKeyLayout { + fn n(&self) -> Degree { + self.n + } + + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } +} + +impl GLWEInfos for GLWEToLWEKeyLayout { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl GGLWEInfos for GLWEToLWEKeyLayout { + fn rank_in(&self) -> Rank { + self.rank_in + } + + fn dsize(&self) -> Dsize { + Dsize(1) + } + + fn rank_out(&self) -> Rank { + Rank(1) + } + + fn dnum(&self) -> Dnum { + self.dnum + } +} + +/// A special [GLWESwitchingKey] required to for the conversion from [GLWE] to [LWE]. +#[derive(PartialEq, Eq, Clone)] +pub struct GLWEToLWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>); + +impl<D: Data> LWEInfos for GLWEToLWESwitchingKey<D> { + fn base2k(&self) -> Base2K { + self.0.base2k() + } + + fn k(&self) -> TorusPrecision { + self.0.k() + } + + fn n(&self) -> Degree { + self.0.n() + } + + fn size(&self) -> usize { + self.0.size() + } +} + +impl<D: Data> GLWEInfos for GLWEToLWESwitchingKey<D> { + fn rank(&self) -> Rank { + self.rank_out() + } +} +impl<D: Data> GGLWEInfos for GLWEToLWESwitchingKey<D> { + fn rank_in(&self) -> Rank { + self.0.rank_in() + } + + fn dsize(&self) -> Dsize { + self.0.dsize() + } + + fn rank_out(&self) -> Rank { + self.0.rank_out() + } + + fn dnum(&self) -> Dnum { + self.0.dnum() + } +} + +impl<D: DataRef> fmt::Debug for GLWEToLWESwitchingKey<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataMut> FillUniform for GLWEToLWESwitchingKey<D> { + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.0.fill_uniform(log_bound, source); + } +} + +impl<D: DataRef> fmt::Display for GLWEToLWESwitchingKey<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(GLWEToLWESwitchingKey) {}", self.0) + } +} + +impl<D: DataMut> ReaderFrom for GLWEToLWESwitchingKey<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.0.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for GLWEToLWESwitchingKey<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + self.0.write_to(writer) + } +} + +impl GLWEToLWESwitchingKey<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is not supported for GLWEToLWESwitchingKey" + ); + assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for GLWEToLWESwitchingKey" + ); + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.dnum(), + ) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self { + GLWEToLWESwitchingKey(GLWESwitchingKey::alloc( + n, + base2k, + k, + rank_in, + Rank(1), + dnum, + Dsize(1), + )) + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is not supported for GLWEToLWESwitchingKey" + ); + assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for GLWEToLWESwitchingKey" + ); + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.dnum(), + ) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize { + GLWESwitchingKey::bytes_of(n, base2k, k, rank_in, Rank(1), dnum, Dsize(1)) + } +} + +impl<D: DataRef> GGLWEToRef for GLWEToLWESwitchingKey<D> { + fn to_ref(&self) -> GGLWE<&[u8]> { + self.0.to_ref() + } +} + +impl<D: DataMut> GGLWEToMut for GLWEToLWESwitchingKey<D> { + fn to_mut(&mut self) -> GGLWE<&mut [u8]> { + self.0.to_mut() + } +} + +impl<D: DataMut> GLWESwitchingKeyDegreesMut for GLWEToLWESwitchingKey<D> { + fn input_degree(&mut self) -> &mut Degree { + &mut self.0.input_degree + } + + fn output_degree(&mut self) -> &mut Degree { + &mut self.0.output_degree + } +} + +impl<D: DataRef> GLWESwitchingKeyDegrees for GLWEToLWESwitchingKey<D> { + fn input_degree(&self) -> &Degree { + &self.0.input_degree + } + + fn output_degree(&self) -> &Degree { + &self.0.output_degree + } +}
@@ -0,0 +1,202 @@
+use std::fmt; + +use poulpy_hal::{ + layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo, Zn, ZnToMut, ZnToRef, ZnxInfos}, + source::Source, +}; + +use crate::layouts::{Base2K, Degree, TorusPrecision}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + +pub trait LWEInfos { + fn n(&self) -> Degree; + fn log_n(&self) -> usize { + (u64::BITS - (self.n().as_usize() as u64 - 1).leading_zeros()) as usize + } + fn k(&self) -> TorusPrecision; + fn max_k(&self) -> TorusPrecision { + TorusPrecision(self.k().0 * self.size() as u32) + } + fn base2k(&self) -> Base2K; + fn size(&self) -> usize { + self.k().0.div_ceil(self.base2k().0) as usize + } + fn lwe_layout(&self) -> LWELayout { + LWELayout { + n: self.n(), + k: self.k(), + base2k: self.base2k(), + } + } +} + +pub trait SetLWEInfos { + fn set_k(&mut self, k: TorusPrecision); + fn set_base2k(&mut self, base2k: Base2K); +} + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub struct LWELayout { + pub n: Degree, + pub k: TorusPrecision, + pub base2k: Base2K, +} + +impl LWEInfos for LWELayout { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn n(&self) -> Degree { + self.n + } +} +#[derive(PartialEq, Eq, Clone)] +pub struct LWE<D: Data> { + pub(crate) data: Zn<D>, + pub(crate) k: TorusPrecision, + pub(crate) base2k: Base2K, +} + +impl<D: Data> LWEInfos for LWE<D> { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + fn n(&self) -> Degree { + Degree(self.data.n() as u32 - 1) + } + + fn size(&self) -> usize { + self.data.size() + } +} + +impl<D: Data> SetLWEInfos for LWE<D> { + fn set_base2k(&mut self, base2k: Base2K) { + self.base2k = base2k + } + + fn set_k(&mut self, k: TorusPrecision) { + self.k = k + } +} + +impl<D: DataRef> LWE<D> { + pub fn data(&self) -> &Zn<D> { + &self.data + } +} + +impl<D: DataMut> LWE<D> { + pub fn data_mut(&mut self) -> &Zn<D> { + &mut self.data + } +} + +impl<D: DataRef> fmt::Debug for LWE<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{self}") + } +} + +impl<D: DataRef> fmt::Display for LWE<D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "LWE: base2k={} k={}: {}", + self.base2k().0, + self.k().0, + self.data + ) + } +} + +impl<D: DataMut> FillUniform for LWE<D> +where + Zn<D>: FillUniform, +{ + fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { + self.data.fill_uniform(log_bound, source); + } +} + +impl LWE<Vec<u8>> { + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: LWEInfos, + { + Self::alloc(infos.n(), infos.base2k(), infos.k()) + } + + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision) -> Self { + LWE { + data: Zn::alloc((n + 1).into(), 1, k.0.div_ceil(base2k.0) as usize), + k, + base2k, + } + } + + pub fn bytes_of_from_infos<A>(infos: &A) -> usize + where + A: LWEInfos, + { + Self::bytes_of(infos.n(), infos.base2k(), infos.k()) + } + + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision) -> usize { + Zn::bytes_of((n + 1).into(), 1, k.0.div_ceil(base2k.0) as usize) + } +} + +pub trait LWEToRef { + fn to_ref(&self) -> LWE<&[u8]>; +} + +impl<D: DataRef> LWEToRef for LWE<D> { + fn to_ref(&self) -> LWE<&[u8]> { + LWE { + k: self.k, + base2k: self.base2k, + data: self.data.to_ref(), + } + } +} + +pub trait LWEToMut { + #[allow(dead_code)] + fn to_mut(&mut self) -> LWE<&mut [u8]>; +} + +impl<D: DataMut> LWEToMut for LWE<D> { + fn to_mut(&mut self) -> LWE<&mut [u8]> { + LWE { + k: self.k, + base2k: self.base2k, + data: self.data.to_mut(), + } + } +} + +impl<D: DataMut> ReaderFrom for LWE<D> { + fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { + self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); + self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); + self.data.read_from(reader) + } +} + +impl<D: DataRef> WriterTo for LWE<D> { + fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_u32::<LittleEndian>(self.k.into())?; + writer.write_u32::<LittleEndian>(self.base2k.into())?; + self.data.write_to(writer) + } +}
@@ -1,263 +0,0 @@
-use std::fmt; - -use poulpy_hal::{ - layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo, Zn, ZnToMut, ZnToRef, ZnxInfos}, - source::Source, -}; - -use crate::layouts::{Base2K, BuildError, Degree, TorusPrecision}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -pub trait LWEInfos { - fn n(&self) -> Degree; - fn k(&self) -> TorusPrecision; - fn max_k(&self) -> TorusPrecision { - TorusPrecision(self.k().0 * self.size() as u32) - } - fn base2k(&self) -> Base2K; - fn size(&self) -> usize { - self.k().0.div_ceil(self.base2k().0) as usize - } - fn lwe_layout(&self) -> LWECiphertextLayout { - LWECiphertextLayout { - n: self.n(), - k: self.k(), - base2k: self.base2k(), - } - } -} - -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub struct LWECiphertextLayout { - pub n: Degree, - pub k: TorusPrecision, - pub base2k: Base2K, -} - -impl LWEInfos for LWECiphertextLayout { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn n(&self) -> Degree { - self.n - } -} - -#[derive(PartialEq, Eq, Clone)] -pub struct LWECiphertext<D: Data> { - pub(crate) data: Zn<D>, - pub(crate) k: TorusPrecision, - pub(crate) base2k: Base2K, -} - -impl<D: Data> LWEInfos for LWECiphertext<D> { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - fn n(&self) -> Degree { - Degree(self.data.n() as u32 - 1) - } - - fn size(&self) -> usize { - self.data.size() - } -} - -impl<D: DataRef> LWECiphertext<D> { - pub fn data(&self) -> &Zn<D> { - &self.data - } -} - -impl<D: DataMut> LWECiphertext<D> { - pub fn data_mut(&mut self) -> &Zn<D> { - &mut self.data - } -} - -impl<D: DataRef> fmt::Debug for LWECiphertext<D> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - -impl<D: DataRef> fmt::Display for LWECiphertext<D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "LWECiphertext: base2k={} k={}: {}", - self.base2k().0, - self.k().0, - self.data - ) - } -} - -impl<D: DataMut> FillUniform for LWECiphertext<D> -where - Zn<D>: FillUniform, -{ - fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) { - self.data.fill_uniform(log_bound, source); - } -} - -impl LWECiphertext<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self - where - A: LWEInfos, - { - Self::alloc_with(infos.n(), infos.base2k(), infos.k()) - } - - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision) -> Self { - Self { - data: Zn::alloc((n + 1).into(), 1, k.0.div_ceil(base2k.0) as usize), - k, - base2k, - } - } - - pub fn alloc_bytes<A>(infos: &A) -> usize - where - A: LWEInfos, - { - Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k()) - } - - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision) -> usize { - Zn::alloc_bytes((n + 1).into(), 1, k.0.div_ceil(base2k.0) as usize) - } -} - -impl LWECiphertextBuilder<Vec<u8>> { - #[inline] - pub fn layout<A>(mut self, layout: A) -> Self - where - A: LWEInfos, - { - self.data = Some(Zn::alloc((layout.n() + 1).into(), 1, layout.size())); - self.base2k = Some(layout.base2k()); - self.k = Some(layout.k()); - self - } -} - -pub struct LWECiphertextBuilder<D: Data> { - data: Option<Zn<D>>, - base2k: Option<Base2K>, - k: Option<TorusPrecision>, -} - -impl<D: Data> LWECiphertext<D> { - #[inline] - pub fn builder() -> LWECiphertextBuilder<D> { - LWECiphertextBuilder { - data: None, - base2k: None, - k: None, - } - } -} - -impl<D: Data> LWECiphertextBuilder<D> { - #[inline] - pub fn data(mut self, data: Zn<D>) -> Self { - self.data = Some(data); - self - } - #[inline] - pub fn base2k(mut self, base2k: Base2K) -> Self { - self.base2k = Some(base2k); - self - } - #[inline] - pub fn k(mut self, k: TorusPrecision) -> Self { - self.k = Some(k); - self - } - - pub fn build(self) -> Result<LWECiphertext<D>, BuildError> { - let data: Zn<D> = self.data.ok_or(BuildError::MissingData)?; - let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; - let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - - if base2k.0 == 0 { - return Err(BuildError::ZeroBase2K); - } - - if k.0 == 0 { - return Err(BuildError::ZeroTorusPrecision); - } - - if data.n() == 0 { - return Err(BuildError::ZeroDegree); - } - - if data.cols() == 0 { - return Err(BuildError::ZeroCols); - } - - if data.size() == 0 { - return Err(BuildError::ZeroLimbs); - } - - Ok(LWECiphertext { data, base2k, k }) - } -} - -pub trait LWECiphertextToRef { - fn to_ref(&self) -> LWECiphertext<&[u8]>; -} - -impl<D: DataRef> LWECiphertextToRef for LWECiphertext<D> { - fn to_ref(&self) -> LWECiphertext<&[u8]> { - LWECiphertext::builder() - .base2k(self.base2k()) - .k(self.k()) - .data(self.data.to_ref()) - .build() - .unwrap() - } -} - -pub trait LWECiphertextToMut { - #[allow(dead_code)] - fn to_mut(&mut self) -> LWECiphertext<&mut [u8]>; -} - -impl<D: DataMut> LWECiphertextToMut for LWECiphertext<D> { - fn to_mut(&mut self) -> LWECiphertext<&mut [u8]> { - LWECiphertext::builder() - .base2k(self.base2k()) - .k(self.k()) - .data(self.data.to_mut()) - .build() - .unwrap() - } -} - -impl<D: DataMut> ReaderFrom for LWECiphertext<D> { - fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> { - self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?); - self.base2k = Base2K(reader.read_u32::<LittleEndian>()?); - self.data.read_from(reader) - } -} - -impl<D: DataRef> WriterTo for LWECiphertext<D> { - fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_u32::<LittleEndian>(self.k.into())?; - writer.write_u32::<LittleEndian>(self.base2k.into())?; - self.data.write_to(writer) - } -}
@@ -5,7 +5,10 @@ layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
source::Source, }; -use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision}; +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToMut, GGLWEToRef, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeyDegrees, + GLWESwitchingKeyDegreesMut, LWEInfos, Rank, TorusPrecision, +}; #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub struct LWESwitchingKeyLayout {@@ -54,7 +57,7 @@ }
} #[derive(PartialEq, Eq, Clone)] -pub struct LWESwitchingKey<D: Data>(pub(crate) GGLWESwitchingKey<D>); +pub struct LWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>); impl<D: Data> LWEInfos for LWESwitchingKey<D> { fn base2k(&self) -> Base2K {@@ -99,30 +102,30 @@ }
} impl LWESwitchingKey<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self + pub fn alloc_from_infos<A>(infos: &A) -> Self where A: GGLWEInfos, { - debug_assert_eq!( + assert_eq!( infos.dsize().0, 1, "dsize > 1 is not supported for LWESwitchingKey" ); - debug_assert_eq!( + assert_eq!( infos.rank_in().0, 1, "rank_in > 1 is not supported for LWESwitchingKey" ); - debug_assert_eq!( + assert_eq!( infos.rank_out().0, 1, "rank_out > 1 is not supported for LWESwitchingKey" ); - Self(GGLWESwitchingKey::alloc(infos)) + Self::alloc(infos.n(), infos.base2k(), infos.k(), infos.dnum()) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self { - Self(GGLWESwitchingKey::alloc_with( + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self { + LWESwitchingKey(GLWESwitchingKey::alloc( n, base2k, k,@@ -133,30 +136,30 @@ Dsize(1),
)) } - pub fn alloc_bytes<A>(infos: &A) -> usize + pub fn bytes_of_from_infos<A>(infos: &A) -> usize where A: GGLWEInfos, { - debug_assert_eq!( + assert_eq!( infos.dsize().0, 1, "dsize > 1 is not supported for LWESwitchingKey" ); - debug_assert_eq!( + assert_eq!( infos.rank_in().0, 1, "rank_in > 1 is not supported for LWESwitchingKey" ); - debug_assert_eq!( + assert_eq!( infos.rank_out().0, 1, "rank_out > 1 is not supported for LWESwitchingKey" ); - GGLWESwitchingKey::alloc_bytes(infos) + Self::bytes_of(infos.n(), infos.base2k(), infos.k(), infos.dnum()) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize { - GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, Rank(1), Rank(1), dnum, Dsize(1)) + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize { + GLWESwitchingKey::bytes_of(n, base2k, k, Rank(1), Rank(1), dnum, Dsize(1)) } }@@ -189,3 +192,35 @@ fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
self.0.write_to(writer) } } + +impl<D: DataRef> GGLWEToRef for LWESwitchingKey<D> { + fn to_ref(&self) -> GGLWE<&[u8]> { + self.0.to_ref() + } +} + +impl<D: DataMut> GGLWEToMut for LWESwitchingKey<D> { + fn to_mut(&mut self) -> GGLWE<&mut [u8]> { + self.0.to_mut() + } +} + +impl<D: DataMut> GLWESwitchingKeyDegreesMut for LWESwitchingKey<D> { + fn input_degree(&mut self) -> &mut Degree { + &mut self.0.input_degree + } + + fn output_degree(&mut self) -> &mut Degree { + &mut self.0.output_degree + } +} + +impl<D: DataRef> GLWESwitchingKeyDegrees for LWESwitchingKey<D> { + fn input_degree(&self) -> &Degree { + &self.0.input_degree + } + + fn output_degree(&self) -> &Degree { + &self.0.output_degree + } +}
@@ -53,15 +53,15 @@ }
} impl LWEPlaintext<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self + pub fn alloc_from_infos<A>(infos: &A) -> Self where A: LWEInfos, { - Self::alloc_with(infos.base2k(), infos.k()) + Self::alloc(infos.base2k(), infos.k()) } - pub fn alloc_with(base2k: Base2K, k: TorusPrecision) -> Self { - Self { + pub fn alloc(base2k: Base2K, k: TorusPrecision) -> Self { + LWEPlaintext { data: Zn::alloc(1, 1, k.0.div_ceil(base2k.0) as usize), k, base2k,
@@ -1,9 +1,10 @@
use poulpy_hal::{ - layouts::{Data, DataMut, DataRef, ScalarZnx, ZnxInfos, ZnxView, ZnxZero}, + layouts::{Data, DataMut, DataRef, ScalarZnx, ScalarZnxToMut, ScalarZnxToRef, ZnxInfos, ZnxView, ZnxZero}, source::Source, }; use crate::{ + GetDistribution, dist::Distribution, layouts::{Base2K, Degree, LWEInfos, TorusPrecision}, };@@ -15,10 +16,16 @@ }
impl LWESecret<Vec<u8>> { pub fn alloc(n: Degree) -> Self { - Self { + LWESecret { data: ScalarZnx::alloc(n.into(), 1), dist: Distribution::NONE, } + } +} + +impl<D: DataRef> GetDistribution for LWESecret<D> { + fn dist(&self) -> &Distribution { + &self.dist } }@@ -84,3 +91,29 @@ self.data.zero();
self.dist = Distribution::ZERO; } } + +pub trait LWESecretToRef { + fn to_ref(&self) -> LWESecret<&[u8]>; +} + +impl<D: DataRef> LWESecretToRef for LWESecret<D> { + fn to_ref(&self) -> LWESecret<&[u8]> { + LWESecret { + dist: self.dist, + data: self.data.to_ref(), + } + } +} + +pub trait LWESecretToMut { + fn to_mut(&mut self) -> LWESecret<&mut [u8]>; +} + +impl<D: DataMut> LWESecretToMut for LWESecret<D> { + fn to_mut(&mut self) -> LWESecret<&mut [u8]> { + LWESecret { + dist: self.dist, + data: self.data.to_mut(), + } + } +}
@@ -5,7 +5,10 @@ layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
source::Source, }; -use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision}; +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToMut, GGLWEToRef, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeyDegrees, + GLWESwitchingKeyDegreesMut, LWEInfos, Rank, TorusPrecision, +}; #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub struct LWEToGLWESwitchingKeyLayout {@@ -55,7 +58,7 @@ }
} #[derive(PartialEq, Eq, Clone)] -pub struct LWEToGLWESwitchingKey<D: Data>(pub(crate) GGLWESwitchingKey<D>); +pub struct LWEToGLWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>); impl<D: Data> LWEInfos for LWEToGLWESwitchingKey<D> { fn base2k(&self) -> Base2K {@@ -129,25 +132,32 @@ }
} impl LWEToGLWESwitchingKey<Vec<u8>> { - pub fn alloc<A>(infos: &A) -> Self + pub fn alloc_from_infos<A>(infos: &A) -> Self where A: GGLWEInfos, { - debug_assert_eq!( + assert_eq!( infos.rank_in().0, 1, "rank_in > 1 is not supported for LWEToGLWESwitchingKey" ); - debug_assert_eq!( + assert_eq!( infos.dsize().0, 1, "dsize > 1 is not supported for LWEToGLWESwitchingKey" ); - Self(GGLWESwitchingKey::alloc(infos)) + + Self::alloc( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_out(), + infos.dnum(), + ) } - pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self { - Self(GGLWESwitchingKey::alloc_with( + pub fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self { + LWEToGLWESwitchingKey(GLWESwitchingKey::alloc( n, base2k, k,@@ -158,24 +168,62 @@ Dsize(1),
)) } - pub fn alloc_bytes<A>(infos: &A) -> usize + pub fn bytes_of_from_infos<A>(infos: &A) -> usize where A: GGLWEInfos, { - debug_assert_eq!( + assert_eq!( infos.rank_in().0, 1, "rank_in > 1 is not supported for LWEToGLWESwitchingKey" ); - debug_assert_eq!( + assert_eq!( infos.dsize().0, 1, "dsize > 1 is not supported for LWEToGLWESwitchingKey" ); - GGLWESwitchingKey::alloc_bytes(infos) + Self::bytes_of( + infos.n(), + infos.base2k(), + infos.k(), + infos.rank_out(), + infos.dnum(), + ) } - pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_out: Rank) -> usize { - GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, Rank(1), rank_out, dnum, Dsize(1)) + pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> usize { + GLWESwitchingKey::bytes_of(n, base2k, k, Rank(1), rank_out, dnum, Dsize(1)) + } +} + +impl<D: DataRef> GGLWEToRef for LWEToGLWESwitchingKey<D> { + fn to_ref(&self) -> GGLWE<&[u8]> { + self.0.to_ref() + } +} + +impl<D: DataMut> GGLWEToMut for LWEToGLWESwitchingKey<D> { + fn to_mut(&mut self) -> GGLWE<&mut [u8]> { + self.0.to_mut() + } +} + +impl<D: DataMut> GLWESwitchingKeyDegreesMut for LWEToGLWESwitchingKey<D> { + fn input_degree(&mut self) -> &mut Degree { + &mut self.0.input_degree + } + + fn output_degree(&mut self) -> &mut Degree { + &mut self.0.output_degree + } +} + +impl<D: DataRef> GLWESwitchingKeyDegrees for LWEToGLWESwitchingKey<D> { + fn input_degree(&self) -> &Degree { + &self.0.input_degree + } + + fn output_degree(&self) -> &Degree { + &self.0.output_degree } }
@@ -1,52 +1,50 @@
-mod gglwe_atk; -mod gglwe_ct; -mod gglwe_ksk; -mod gglwe_tsk; -mod ggsw_ct; -mod glwe_ct; -mod glwe_pk; -mod glwe_pt; -mod glwe_sk; -mod glwe_to_lwe_ksk; -mod lwe_ct; -mod lwe_ksk; -mod lwe_pt; -mod lwe_sk; -mod lwe_to_glwe_ksk; +mod gglwe; +mod ggsw; +mod glwe; +mod glwe_automorphism_key; +mod glwe_plaintext; +mod glwe_public_key; +mod glwe_secret; +mod glwe_switching_key; +mod glwe_tensor_key; +mod glwe_to_lwe_switching_key; +mod lwe; +mod lwe_plaintext; +mod lwe_secret; +mod lwe_switching_key; +mod lwe_to_glwe_switching_key; pub mod compressed; pub mod prepared; -pub use gglwe_atk::*; -pub use gglwe_ct::*; -pub use gglwe_ksk::*; -pub use gglwe_tsk::*; -pub use ggsw_ct::*; -pub use glwe_ct::*; -pub use glwe_pk::*; -pub use glwe_pt::*; -pub use glwe_sk::*; -pub use glwe_to_lwe_ksk::*; -pub use lwe_ct::*; -pub use lwe_ksk::*; -pub use lwe_pt::*; -pub use lwe_sk::*; -pub use lwe_to_glwe_ksk::*; +pub use compressed::*; +pub use gglwe::*; +pub use ggsw::*; +pub use glwe::*; +pub use glwe_automorphism_key::*; +pub use glwe_plaintext::*; +pub use glwe_public_key::*; +pub use glwe_secret::*; +pub use glwe_switching_key::*; +pub use glwe_tensor_key::*; +pub use glwe_to_lwe_switching_key::*; +pub use lwe::*; +pub use lwe_plaintext::*; +pub use lwe_secret::*; +pub use lwe_switching_key::*; +pub use lwe_to_glwe_switching_key::*; +pub use prepared::*; + +use poulpy_hal::layouts::{Backend, Module}; + +pub trait GetDegree { + fn ring_degree(&self) -> Degree; +} -#[derive(Debug)] -pub enum BuildError { - MissingData, - MissingBase2K, - MissingK, - MissingDigits, - ZeroDegree, - NonPowerOfTwoDegree, - ZeroBase2K, - ZeroTorusPrecision, - ZeroCols, - ZeroLimbs, - ZeroRank, - ZeroDigits, +impl<B: Backend> GetDegree for Module<B> { + fn ring_degree(&self) -> Degree { + Self::n(self).into() + } } /// Newtype over `u32` with arithmetic and comparisons against same type and `u32`.
@@ -0,0 +1,281 @@
+use poulpy_hal::{ + api::{VmpPMatAlloc, VmpPMatBytesOf, VmpPrepare, VmpPrepareTmpBytes}, + layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, VmpPMatToMut, VmpPMatToRef, ZnxInfos}, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToRef, GLWEInfos, GetDegree, LWEInfos, Rank, TorusPrecision, +}; + +#[derive(PartialEq, Eq)] +pub struct GGLWEPrepared<D: Data, B: Backend> { + pub(crate) data: VmpPMat<D, B>, + pub(crate) k: TorusPrecision, + pub(crate) base2k: Base2K, + pub(crate) dsize: Dsize, +} + +impl<D: Data, B: Backend> LWEInfos for GGLWEPrepared<D, B> { + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } + + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn size(&self) -> usize { + self.data.size() + } +} + +impl<D: Data, B: Backend> GLWEInfos for GGLWEPrepared<D, B> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data, B: Backend> GGLWEInfos for GGLWEPrepared<D, B> { + fn rank_in(&self) -> Rank { + Rank(self.data.cols_in() as u32) + } + + fn rank_out(&self) -> Rank { + Rank(self.data.cols_out() as u32 - 1) + } + + fn dsize(&self) -> Dsize { + self.dsize + } + + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) + } +} + +pub trait GGLWEPreparedFactory<BE: Backend> +where + Self: GetDegree + VmpPMatAlloc<BE> + VmpPMatBytesOf + VmpPrepare<BE> + VmpPrepareTmpBytes, +{ + fn alloc_gglwe_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> GGLWEPrepared<Vec<u8>, BE> { + let size: usize = k.0.div_ceil(base2k.0) as usize; + debug_assert!( + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + GGLWEPrepared { + data: self.vmp_pmat_alloc(dnum.into(), rank_in.into(), (rank_out + 1).into(), size), + k, + base2k, + dsize, + } + } + + fn alloc_gglwe_prepared_from_infos<A>(&self, infos: &A) -> GGLWEPrepared<Vec<u8>, BE> + where + A: GGLWEInfos, + { + assert_eq!(self.ring_degree(), infos.n()); + self.alloc_gglwe_prepared( + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.rank_out(), + infos.dnum(), + infos.dsize(), + ) + } + + fn bytes_of_gglwe_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> usize { + let size: usize = k.0.div_ceil(base2k.0) as usize; + debug_assert!( + size as u32 > dsize.0, + "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + self.bytes_of_vmp_pmat(dnum.into(), rank_in.into(), (rank_out + 1).into(), size) + } + + fn bytes_of_gglwe_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!(self.ring_degree(), infos.n()); + self.bytes_of_gglwe_prepared( + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.rank_out(), + infos.dnum(), + infos.dsize(), + ) + } + + fn prepare_gglwe_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.vmp_prepare_tmp_bytes( + infos.dnum().into(), + infos.rank_in().into(), + (infos.rank() + 1).into(), + infos.size(), + ) + } + + fn prepare_gglwe<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<BE>) + where + R: GGLWEPreparedToMut<BE>, + O: GGLWEToRef, + { + let mut res: GGLWEPrepared<&mut [u8], BE> = res.to_mut(); + let other: GGLWE<&[u8]> = other.to_ref(); + + assert_eq!(res.n(), self.ring_degree()); + assert_eq!(other.n(), self.ring_degree()); + assert_eq!(res.base2k, other.base2k); + assert_eq!(res.k, other.k); + assert_eq!(res.dsize, other.dsize); + + self.vmp_prepare(&mut res.data, &other.data, scratch); + } +} + +impl<BE: Backend> GGLWEPreparedFactory<BE> for Module<BE> where + Module<BE>: GetDegree + VmpPMatAlloc<BE> + VmpPMatBytesOf + VmpPrepare<BE> + VmpPrepareTmpBytes +{ +} + +impl<B: Backend> GGLWEPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GGLWEInfos, + M: GGLWEPreparedFactory<B>, + { + module.alloc_gglwe_prepared_from_infos(infos) + } + + pub fn alloc<M>( + module: &M, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> Self + where + M: GGLWEPreparedFactory<B>, + { + module.alloc_gglwe_prepared(base2k, k, rank_in, rank_out, dnum, dsize) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GGLWEPreparedFactory<B>, + { + module.bytes_of_gglwe_prepared_from_infos(infos) + } + + pub fn bytes_of<M>( + module: &M, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> usize + where + M: GGLWEPreparedFactory<B>, + { + module.bytes_of_gglwe_prepared(base2k, k, rank_in, rank_out, dnum, dsize) + } +} + +impl<D: DataMut, B: Backend> GGLWEPrepared<D, B> { + pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>) + where + O: GGLWEToRef, + M: GGLWEPreparedFactory<B>, + { + module.prepare_gglwe(self, other, scratch); + } +} + +impl<B: Backend> GGLWEPrepared<Vec<u8>, B> { + pub fn prepare_tmp_bytes<M>(&self, module: &M) -> usize + where + M: GGLWEPreparedFactory<B>, + { + module.prepare_gglwe_tmp_bytes(self) + } +} + +pub trait GGLWEPreparedToMut<B: Backend> { + fn to_mut(&mut self) -> GGLWEPrepared<&mut [u8], B>; +} + +impl<D: DataMut, B: Backend> GGLWEPreparedToMut<B> for GGLWEPrepared<D, B> { + fn to_mut(&mut self) -> GGLWEPrepared<&mut [u8], B> { + GGLWEPrepared { + k: self.k, + base2k: self.base2k, + dsize: self.dsize, + data: self.data.to_mut(), + } + } +} + +pub trait GGLWEPreparedToRef<B: Backend> { + fn to_ref(&self) -> GGLWEPrepared<&[u8], B>; +} + +impl<D: DataRef, B: Backend> GGLWEPreparedToRef<B> for GGLWEPrepared<D, B> { + fn to_ref(&self) -> GGLWEPrepared<&[u8], B> { + GGLWEPrepared { + k: self.k, + base2k: self.base2k, + dsize: self.dsize, + data: self.data.to_ref(), + } + } +}
@@ -1,141 +0,0 @@
-use poulpy_hal::{ - api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKey, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, - prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace}, -}; - -#[derive(PartialEq, Eq)] -pub struct GGLWEAutomorphismKeyPrepared<D: Data, B: Backend> { - pub(crate) key: GGLWESwitchingKeyPrepared<D, B>, - pub(crate) p: i64, -} - -impl<D: Data, B: Backend> GGLWEAutomorphismKeyPrepared<D, B> { - pub fn p(&self) -> i64 { - self.p - } -} - -impl<D: Data, B: Backend> LWEInfos for GGLWEAutomorphismKeyPrepared<D, B> { - fn n(&self) -> Degree { - self.key.n() - } - - fn base2k(&self) -> Base2K { - self.key.base2k() - } - - fn k(&self) -> TorusPrecision { - self.key.k() - } - - fn size(&self) -> usize { - self.key.size() - } -} - -impl<D: Data, B: Backend> GLWEInfos for GGLWEAutomorphismKeyPrepared<D, B> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data, B: Backend> GGLWEInfos for GGLWEAutomorphismKeyPrepared<D, B> { - fn rank_in(&self) -> Rank { - self.key.rank_in() - } - - fn rank_out(&self) -> Rank { - self.key.rank_out() - } - - fn dsize(&self) -> Dsize { - self.key.dsize() - } - - fn dnum(&self) -> Dnum { - self.key.dnum() - } -} - -impl<B: Backend> GGLWEAutomorphismKeyPrepared<Vec<u8>, B> { - pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: GGLWEInfos, - Module<B>: VmpPMatAlloc<B>, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWEAutomorphismKeyPrepared" - ); - GGLWEAutomorphismKeyPrepared::<Vec<u8>, B> { - key: GGLWESwitchingKeyPrepared::alloc(module, infos), - p: 0, - } - } - - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self - where - Module<B>: VmpPMatAlloc<B>, - { - GGLWEAutomorphismKeyPrepared { - key: GGLWESwitchingKeyPrepared::alloc_with(module, base2k, k, rank, rank, dnum, dsize), - p: 0, - } - } - - pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VmpPMatAllocBytes, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWEAutomorphismKeyPrepared" - ); - GGLWESwitchingKeyPrepared::alloc_bytes(module, infos) - } - - pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize - where - Module<B>: VmpPMatAllocBytes, - { - GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rank, rank, dnum, dsize) - } -} - -impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GGLWEAutomorphismKeyPrepared<Vec<u8>, B> -where - GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>, -{ - fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize { - GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos) - } -} - -impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGLWEAutomorphismKey<DR>> for GGLWEAutomorphismKeyPrepared<D, B> -where - Module<B>: VmpPrepare<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &GGLWEAutomorphismKey<DR>, scratch: &mut Scratch<B>) { - self.key.prepare(module, &other.key, scratch); - self.p = other.p; - } -} - -impl<D: DataRef, B: Backend> PrepareAlloc<B, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> for GGLWEAutomorphismKey<D> -where - Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGLWEAutomorphismKeyPrepared<Vec<u8>, B> { - let mut atk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = GGLWEAutomorphismKeyPrepared::alloc(module, self); - atk_prepared.prepare(module, self, scratch); - atk_prepared - } -}
@@ -1,298 +0,0 @@
-use poulpy_hal::{ - api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare, VmpPrepareTmpBytes}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, ZnxInfos}, - oep::VmpPMatAllocBytesImpl, -}; - -use crate::layouts::{ - Base2K, BuildError, Degree, Dnum, Dsize, GGLWECiphertext, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, - prepared::{Prepare, PrepareAlloc, PrepareScratchSpace}, -}; - -#[derive(PartialEq, Eq)] -pub struct GGLWECiphertextPrepared<D: Data, B: Backend> { - pub(crate) data: VmpPMat<D, B>, - pub(crate) k: TorusPrecision, - pub(crate) base2k: Base2K, - pub(crate) dsize: Dsize, -} - -impl<D: Data, B: Backend> LWEInfos for GGLWECiphertextPrepared<D, B> { - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn size(&self) -> usize { - self.data.size() - } -} - -impl<D: Data, B: Backend> GLWEInfos for GGLWECiphertextPrepared<D, B> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data, B: Backend> GGLWEInfos for GGLWECiphertextPrepared<D, B> { - fn rank_in(&self) -> Rank { - Rank(self.data.cols_in() as u32) - } - - fn rank_out(&self) -> Rank { - Rank(self.data.cols_out() as u32 - 1) - } - - fn dsize(&self) -> Dsize { - self.dsize - } - - fn dnum(&self) -> Dnum { - Dnum(self.data.rows() as u32) - } -} - -pub struct GGLWECiphertextPreparedBuilder<D: Data, B: Backend> { - data: Option<VmpPMat<D, B>>, - base2k: Option<Base2K>, - k: Option<TorusPrecision>, - dsize: Option<Dsize>, -} - -impl<D: Data, B: Backend> GGLWECiphertextPrepared<D, B> { - #[inline] - pub fn builder() -> GGLWECiphertextPreparedBuilder<D, B> { - GGLWECiphertextPreparedBuilder { - data: None, - base2k: None, - k: None, - dsize: None, - } - } -} - -impl<B: Backend> GGLWECiphertextPreparedBuilder<Vec<u8>, B> { - #[inline] - pub fn layout<A>(mut self, infos: &A) -> Self - where - A: GGLWEInfos, - B: VmpPMatAllocBytesImpl<B>, - { - self.data = Some(VmpPMat::alloc( - infos.n().into(), - infos.dnum().into(), - infos.rank_in().into(), - (infos.rank_out() + 1).into(), - infos.size(), - )); - self.base2k = Some(infos.base2k()); - self.k = Some(infos.k()); - self.dsize = Some(infos.dsize()); - self - } -} - -impl<D: Data, B: Backend> GGLWECiphertextPreparedBuilder<D, B> { - #[inline] - pub fn data(mut self, data: VmpPMat<D, B>) -> Self { - self.data = Some(data); - self - } - #[inline] - pub fn base2k(mut self, base2k: Base2K) -> Self { - self.base2k = Some(base2k); - self - } - #[inline] - pub fn k(mut self, k: TorusPrecision) -> Self { - self.k = Some(k); - self - } - - #[inline] - pub fn dsize(mut self, dsize: Dsize) -> Self { - self.dsize = Some(dsize); - self - } - - pub fn build(self) -> Result<GGLWECiphertextPrepared<D, B>, BuildError> { - let data: VmpPMat<D, B> = self.data.ok_or(BuildError::MissingData)?; - let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; - let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?; - - if base2k == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if dsize == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if k == 0_u32 { - return Err(BuildError::ZeroTorusPrecision); - } - - if data.n() == 0 { - return Err(BuildError::ZeroDegree); - } - - if data.cols() == 0 { - return Err(BuildError::ZeroCols); - } - - if data.size() == 0 { - return Err(BuildError::ZeroLimbs); - } - - Ok(GGLWECiphertextPrepared { - data, - base2k, - k, - dsize, - }) - } -} - -impl<B: Backend> GGLWECiphertextPrepared<Vec<u8>, B> { - pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: GGLWEInfos, - Module<B>: VmpPMatAlloc<B>, - { - debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()"); - Self::alloc_with( - module, - infos.base2k(), - infos.k(), - infos.rank_in(), - infos.rank_out(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_with( - module: &Module<B>, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - rank_out: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> Self - where - Module<B>: VmpPMatAlloc<B>, - { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - Self { - data: module.vmp_pmat_alloc(dnum.into(), rank_in.into(), (rank_out + 1).into(), size), - k, - base2k, - dsize, - } - } - - pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VmpPMatAllocBytes, - { - debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()"); - Self::alloc_bytes_with( - module, - infos.base2k(), - infos.k(), - infos.rank_in(), - infos.rank_out(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_bytes_with( - module: &Module<B>, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - rank_out: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> usize - where - Module<B>: VmpPMatAllocBytes, - { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - module.vmp_pmat_alloc_bytes(dnum.into(), rank_in.into(), (rank_out + 1).into(), size) - } -} - -impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GGLWECiphertextPrepared<Vec<u8>, B> -where - Module<B>: VmpPrepareTmpBytes, -{ - fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize { - module.vmp_prepare_tmp_bytes( - infos.dnum().into(), - infos.rank_in().into(), - (infos.rank() + 1).into(), - infos.size(), - ) - } -} - -impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGLWECiphertext<DR>> for GGLWECiphertextPrepared<D, B> -where - Module<B>: VmpPrepare<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &GGLWECiphertext<DR>, scratch: &mut Scratch<B>) { - module.vmp_prepare(&mut self.data, &other.data, scratch); - self.k = other.k; - self.base2k = other.base2k; - self.dsize = other.dsize; - } -} - -impl<D: DataRef, B: Backend> PrepareAlloc<B, GGLWECiphertextPrepared<Vec<u8>, B>> for GGLWECiphertext<D> -where - Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGLWECiphertextPrepared<Vec<u8>, B> { - let mut atk_prepared: GGLWECiphertextPrepared<Vec<u8>, B> = GGLWECiphertextPrepared::alloc(module, self); - atk_prepared.prepare(module, self, scratch); - atk_prepared - } -}
@@ -1,147 +0,0 @@
-use poulpy_hal::{ - api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision, - prepared::{GGLWECiphertextPrepared, Prepare, PrepareAlloc, PrepareScratchSpace}, -}; - -#[derive(PartialEq, Eq)] -pub struct GGLWESwitchingKeyPrepared<D: Data, B: Backend> { - pub(crate) key: GGLWECiphertextPrepared<D, B>, - pub(crate) sk_in_n: usize, // Degree of sk_in - pub(crate) sk_out_n: usize, // Degree of sk_out -} - -impl<D: Data, B: Backend> LWEInfos for GGLWESwitchingKeyPrepared<D, B> { - fn n(&self) -> Degree { - self.key.n() - } - - fn base2k(&self) -> Base2K { - self.key.base2k() - } - - fn k(&self) -> TorusPrecision { - self.key.k() - } - - fn size(&self) -> usize { - self.key.size() - } -} - -impl<D: Data, B: Backend> GLWEInfos for GGLWESwitchingKeyPrepared<D, B> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data, B: Backend> GGLWEInfos for GGLWESwitchingKeyPrepared<D, B> { - fn rank_in(&self) -> Rank { - self.key.rank_in() - } - - fn rank_out(&self) -> Rank { - self.key.rank_out() - } - - fn dsize(&self) -> Dsize { - self.key.dsize() - } - - fn dnum(&self) -> Dnum { - self.key.dnum() - } -} - -impl<B: Backend> GGLWESwitchingKeyPrepared<Vec<u8>, B> { - pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: GGLWEInfos, - Module<B>: VmpPMatAlloc<B>, - { - debug_assert_eq!(module.n() as u32, infos.n(), "module.n() != infos.n()"); - GGLWESwitchingKeyPrepared::<Vec<u8>, B> { - key: GGLWECiphertextPrepared::alloc(module, infos), - sk_in_n: 0, - sk_out_n: 0, - } - } - - pub fn alloc_with( - module: &Module<B>, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - rank_out: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> Self - where - Module<B>: VmpPMatAlloc<B>, - { - GGLWESwitchingKeyPrepared::<Vec<u8>, B> { - key: GGLWECiphertextPrepared::alloc_with(module, base2k, k, rank_in, rank_out, dnum, dsize), - sk_in_n: 0, - sk_out_n: 0, - } - } - - pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VmpPMatAllocBytes, - { - debug_assert_eq!(module.n() as u32, infos.n(), "module.n() != infos.n()"); - GGLWECiphertextPrepared::alloc_bytes(module, infos) - } - - pub fn alloc_bytes_with( - module: &Module<B>, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - rank_out: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> usize - where - Module<B>: VmpPMatAllocBytes, - { - GGLWECiphertextPrepared::alloc_bytes_with(module, base2k, k, rank_in, rank_out, dnum, dsize) - } -} - -impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GGLWESwitchingKeyPrepared<Vec<u8>, B> -where - GGLWECiphertextPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>, -{ - fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize { - GGLWECiphertextPrepared::prepare_scratch_space(module, infos) - } -} - -impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGLWESwitchingKey<DR>> for GGLWESwitchingKeyPrepared<D, B> -where - Module<B>: VmpPrepare<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &GGLWESwitchingKey<DR>, scratch: &mut Scratch<B>) { - self.key.prepare(module, &other.key, scratch); - self.sk_in_n = other.sk_in_n; - self.sk_out_n = other.sk_out_n; - } -} - -impl<D: DataRef, B: Backend> PrepareAlloc<B, GGLWESwitchingKeyPrepared<Vec<u8>, B>> for GGLWESwitchingKey<D> -where - Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGLWESwitchingKeyPrepared<Vec<u8>, B> { - let mut atk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = GGLWESwitchingKeyPrepared::alloc(module, self); - atk_prepared.prepare(module, self, scratch); - atk_prepared - } -}
@@ -1,190 +0,0 @@
-use poulpy_hal::{ - api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWETensorKey, GLWEInfos, LWEInfos, Rank, TorusPrecision, - prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace}, -}; - -#[derive(PartialEq, Eq)] -pub struct GGLWETensorKeyPrepared<D: Data, B: Backend> { - pub(crate) keys: Vec<GGLWESwitchingKeyPrepared<D, B>>, -} - -impl<D: Data, B: Backend> LWEInfos for GGLWETensorKeyPrepared<D, B> { - fn n(&self) -> Degree { - self.keys[0].n() - } - - fn base2k(&self) -> Base2K { - self.keys[0].base2k() - } - - fn k(&self) -> TorusPrecision { - self.keys[0].k() - } - - fn size(&self) -> usize { - self.keys[0].size() - } -} - -impl<D: Data, B: Backend> GLWEInfos for GGLWETensorKeyPrepared<D, B> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data, B: Backend> GGLWEInfos for GGLWETensorKeyPrepared<D, B> { - fn rank_in(&self) -> Rank { - self.rank_out() - } - - fn rank_out(&self) -> Rank { - self.keys[0].rank_out() - } - - fn dsize(&self) -> Dsize { - self.keys[0].dsize() - } - - fn dnum(&self) -> Dnum { - self.keys[0].dnum() - } -} - -impl<B: Backend> GGLWETensorKeyPrepared<Vec<u8>, B> { - pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: GGLWEInfos, - Module<B>: VmpPMatAlloc<B>, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWETensorKeyPrepared" - ); - Self::alloc_with( - module, - infos.base2k(), - infos.k(), - infos.dnum(), - infos.dsize(), - infos.rank_out(), - ) - } - - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self - where - Module<B>: VmpPMatAlloc<B>, - { - let mut keys: Vec<GGLWESwitchingKeyPrepared<Vec<u8>, B>> = Vec::new(); - let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1); - (0..pairs).for_each(|_| { - keys.push(GGLWESwitchingKeyPrepared::alloc_with( - module, - base2k, - k, - Rank(1), - rank, - dnum, - dsize, - )); - }); - Self { keys } - } - - pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VmpPMatAllocBytes, - { - assert_eq!( - infos.rank_in(), - infos.rank_out(), - "rank_in != rank_out is not supported for GGLWETensorKey" - ); - let rank_out: usize = infos.rank_out().into(); - let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1); - pairs - * GGLWESwitchingKeyPrepared::alloc_bytes_with( - module, - infos.base2k(), - infos.k(), - Rank(1), - infos.rank_out(), - infos.dnum(), - infos.dsize(), - ) - } - - pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize - where - Module<B>: VmpPMatAllocBytes, - { - let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize; - pairs * GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, Rank(1), rank, dnum, dsize) - } -} - -impl<D: DataMut, B: Backend> GGLWETensorKeyPrepared<D, B> { - // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j]) - pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKeyPrepared<D, B> { - if i > j { - std::mem::swap(&mut i, &mut j); - }; - let rank: usize = self.rank_out().into(); - &mut self.keys[i * rank + j - (i * (i + 1) / 2)] - } -} - -impl<D: DataRef, B: Backend> GGLWETensorKeyPrepared<D, B> { - // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j]) - pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWESwitchingKeyPrepared<D, B> { - if i > j { - std::mem::swap(&mut i, &mut j); - }; - let rank: usize = self.rank_out().into(); - &self.keys[i * rank + j - (i * (i + 1) / 2)] - } -} - -impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GGLWETensorKeyPrepared<Vec<u8>, B> -where - GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>, -{ - fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize { - GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos) - } -} - -impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGLWETensorKey<DR>> for GGLWETensorKeyPrepared<D, B> -where - Module<B>: VmpPrepare<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &GGLWETensorKey<DR>, scratch: &mut Scratch<B>) { - #[cfg(debug_assertions)] - { - assert_eq!(self.keys.len(), other.keys.len()); - } - self.keys - .iter_mut() - .zip(other.keys.iter()) - .for_each(|(a, b)| { - a.prepare(module, b, scratch); - }); - } -} - -impl<D: DataRef, B: Backend> PrepareAlloc<B, GGLWETensorKeyPrepared<Vec<u8>, B>> for GGLWETensorKey<D> -where - Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGLWETensorKeyPrepared<Vec<u8>, B> { - let mut tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = GGLWETensorKeyPrepared::alloc(module, self); - tsk_prepared.prepare(module, self, scratch); - tsk_prepared - } -}
@@ -0,0 +1,256 @@
+use poulpy_hal::{ + api::{VmpPMatAlloc, VmpPMatBytesOf, VmpPrepare, VmpPrepareTmpBytes}, + layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, VmpPMatToMut, VmpPMatToRef, ZnxInfos}, +}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGSW, GGSWInfos, GGSWToRef, GLWEInfos, GetDegree, LWEInfos, Rank, TorusPrecision, +}; + +#[derive(PartialEq, Eq)] +pub struct GGSWPrepared<D: Data, B: Backend> { + pub(crate) data: VmpPMat<D, B>, + pub(crate) k: TorusPrecision, + pub(crate) base2k: Base2K, + pub(crate) dsize: Dsize, +} + +impl<D: Data, B: Backend> LWEInfos for GGSWPrepared<D, B> { + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } + + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn size(&self) -> usize { + self.data.size() + } +} + +impl<D: Data, B: Backend> GLWEInfos for GGSWPrepared<D, B> { + fn rank(&self) -> Rank { + Rank(self.data.cols_out() as u32 - 1) + } +} + +impl<D: Data, B: Backend> GGSWInfos for GGSWPrepared<D, B> { + fn dsize(&self) -> Dsize { + self.dsize + } + + fn dnum(&self) -> Dnum { + Dnum(self.data.rows() as u32) + } +} + +pub trait GGSWPreparedFactory<B: Backend> +where + Self: GetDegree + VmpPMatAlloc<B> + VmpPMatBytesOf + VmpPrepareTmpBytes + VmpPrepare<B>, +{ + fn alloc_ggsw_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + dnum: Dnum, + dsize: Dsize, + rank: Rank, + ) -> GGSWPrepared<Vec<u8>, B> { + let size: usize = k.0.div_ceil(base2k.0) as usize; + debug_assert!( + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + GGSWPrepared { + data: self.vmp_pmat_alloc( + dnum.into(), + (rank + 1).into(), + (rank + 1).into(), + k.0.div_ceil(base2k.0) as usize, + ), + k, + base2k, + dsize, + } + } + + fn alloc_ggsw_prepared_from_infos<A>(&self, infos: &A) -> GGSWPrepared<Vec<u8>, B> + where + A: GGSWInfos, + { + assert_eq!(self.ring_degree(), infos.n()); + self.alloc_ggsw_prepared( + infos.base2k(), + infos.k(), + infos.dnum(), + infos.dsize(), + infos.rank(), + ) + } + + fn bytes_of_ggsw_prepared(&self, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> usize { + let size: usize = k.0.div_ceil(base2k.0) as usize; + debug_assert!( + size as u32 > dsize.0, + "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", + dsize.0 + ); + + assert!( + dnum.0 * dsize.0 <= size as u32, + "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", + dnum.0, + dsize.0, + ); + + self.bytes_of_vmp_pmat(dnum.into(), (rank + 1).into(), (rank + 1).into(), size) + } + + fn bytes_of_ggsw_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GGSWInfos, + { + assert_eq!(self.ring_degree(), infos.n()); + self.bytes_of_ggsw_prepared( + infos.base2k(), + infos.k(), + infos.dnum(), + infos.dsize(), + infos.rank(), + ) + } + + fn ggsw_prepare_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGSWInfos, + { + assert_eq!(self.ring_degree(), infos.n()); + self.vmp_prepare_tmp_bytes( + infos.dnum().into(), + (infos.rank() + 1).into(), + (infos.rank() + 1).into(), + infos.size(), + ) + } + fn ggsw_prepare<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>) + where + R: GGSWPreparedToMut<B>, + O: GGSWToRef, + { + let mut res: GGSWPrepared<&mut [u8], B> = res.to_mut(); + let other: GGSW<&[u8]> = other.to_ref(); + assert_eq!(res.n(), self.ring_degree()); + assert_eq!(other.n(), self.ring_degree()); + assert_eq!(res.k, other.k); + assert_eq!(res.base2k, other.base2k); + assert_eq!(res.dsize, other.dsize); + self.vmp_prepare(&mut res.data, &other.data, scratch); + } +} + +impl<B: Backend> GGSWPreparedFactory<B> for Module<B> where + Self: GetDegree + VmpPMatAlloc<B> + VmpPMatBytesOf + VmpPrepareTmpBytes + VmpPrepare<B> +{ +} + +impl<B: Backend> GGSWPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GGSWInfos, + M: GGSWPreparedFactory<B>, + { + module.alloc_ggsw_prepared_from_infos(infos) + } + + pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self + where + M: GGSWPreparedFactory<B>, + { + module.alloc_ggsw_prepared(base2k, k, dnum, dsize, rank) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GGSWInfos, + M: GGSWPreparedFactory<B>, + { + module.bytes_of_ggsw_prepared_from_infos(infos) + } + + pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> usize + where + M: GGSWPreparedFactory<B>, + { + module.bytes_of_ggsw_prepared(base2k, k, dnum, dsize, rank) + } +} + +impl<D: DataRef, B: Backend> GGSWPrepared<D, B> { + pub fn data(&self) -> &VmpPMat<D, B> { + &self.data + } +} + +impl<B: Backend> GGSWPrepared<Vec<u8>, B> { + pub fn prepare_tmp_bytes<A, M>(&self, module: &M, infos: &A) -> usize + where + A: GGSWInfos, + M: GGSWPreparedFactory<B>, + { + module.ggsw_prepare_tmp_bytes(infos) + } +} + +impl<D: DataMut, B: Backend> GGSWPrepared<D, B> { + pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>) + where + O: GGSWToRef, + M: GGSWPreparedFactory<B>, + { + module.ggsw_prepare(self, other, scratch); + } +} + +pub trait GGSWPreparedToMut<B: Backend> { + fn to_mut(&mut self) -> GGSWPrepared<&mut [u8], B>; +} + +impl<D: DataMut, B: Backend> GGSWPreparedToMut<B> for GGSWPrepared<D, B> { + fn to_mut(&mut self) -> GGSWPrepared<&mut [u8], B> { + GGSWPrepared { + base2k: self.base2k, + k: self.k, + dsize: self.dsize, + data: self.data.to_mut(), + } + } +} + +pub trait GGSWPreparedToRef<B: Backend> { + fn to_ref(&self) -> GGSWPrepared<&[u8], B>; +} + +impl<D: DataRef, B: Backend> GGSWPreparedToRef<B> for GGSWPrepared<D, B> { + fn to_ref(&self) -> GGSWPrepared<&[u8], B> { + GGSWPrepared { + base2k: self.base2k, + k: self.k, + dsize: self.dsize, + data: self.data.to_ref(), + } + } +}
@@ -1,312 +0,0 @@
-use poulpy_hal::{ - api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare, VmpPrepareTmpBytes}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, VmpPMatToRef, ZnxInfos}, - oep::VmpPMatAllocBytesImpl, -}; - -use crate::layouts::{ - Base2K, BuildError, Degree, Dnum, Dsize, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, - prepared::{Prepare, PrepareAlloc, PrepareScratchSpace}, -}; - -#[derive(PartialEq, Eq)] -pub struct GGSWCiphertextPrepared<D: Data, B: Backend> { - pub(crate) data: VmpPMat<D, B>, - pub(crate) k: TorusPrecision, - pub(crate) base2k: Base2K, - pub(crate) dsize: Dsize, -} - -impl<D: Data, B: Backend> LWEInfos for GGSWCiphertextPrepared<D, B> { - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn size(&self) -> usize { - self.data.size() - } -} - -impl<D: Data, B: Backend> GLWEInfos for GGSWCiphertextPrepared<D, B> { - fn rank(&self) -> Rank { - Rank(self.data.cols_out() as u32 - 1) - } -} - -impl<D: Data, B: Backend> GGSWInfos for GGSWCiphertextPrepared<D, B> { - fn dsize(&self) -> Dsize { - self.dsize - } - - fn dnum(&self) -> Dnum { - Dnum(self.data.rows() as u32) - } -} - -pub struct GGSWCiphertextPreparedBuilder<D: Data, B: Backend> { - data: Option<VmpPMat<D, B>>, - base2k: Option<Base2K>, - k: Option<TorusPrecision>, - dsize: Option<Dsize>, -} - -impl<D: Data, B: Backend> GGSWCiphertextPrepared<D, B> { - #[inline] - pub fn builder() -> GGSWCiphertextPreparedBuilder<D, B> { - GGSWCiphertextPreparedBuilder { - data: None, - base2k: None, - k: None, - dsize: None, - } - } -} - -impl<B: Backend> GGSWCiphertextPreparedBuilder<Vec<u8>, B> { - #[inline] - pub fn layout<A>(mut self, infos: &A) -> Self - where - A: GGSWInfos, - B: VmpPMatAllocBytesImpl<B>, - { - debug_assert!( - infos.size() as u32 > infos.dsize().0, - "invalid ggsw: ceil(k/base2k): {} <= dsize: {}", - infos.size(), - infos.dsize() - ); - - assert!( - infos.dnum().0 * infos.dsize().0 <= infos.size() as u32, - "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {}", - infos.dnum(), - infos.dsize(), - infos.size(), - ); - - self.data = Some(VmpPMat::alloc( - infos.n().into(), - infos.dnum().into(), - (infos.rank() + 1).into(), - (infos.rank() + 1).into(), - infos.size(), - )); - self.base2k = Some(infos.base2k()); - self.k = Some(infos.k()); - self.dsize = Some(infos.dsize()); - self - } -} - -impl<D: Data, B: Backend> GGSWCiphertextPreparedBuilder<D, B> { - #[inline] - pub fn data(mut self, data: VmpPMat<D, B>) -> Self { - self.data = Some(data); - self - } - #[inline] - pub fn base2k(mut self, base2k: Base2K) -> Self { - self.base2k = Some(base2k); - self - } - #[inline] - pub fn k(mut self, k: TorusPrecision) -> Self { - self.k = Some(k); - self - } - - #[inline] - pub fn dsize(mut self, dsize: Dsize) -> Self { - self.dsize = Some(dsize); - self - } - - pub fn build(self) -> Result<GGSWCiphertextPrepared<D, B>, BuildError> { - let data: VmpPMat<D, B> = self.data.ok_or(BuildError::MissingData)?; - let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; - let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?; - - if base2k == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if dsize == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if k == 0_u32 { - return Err(BuildError::ZeroTorusPrecision); - } - - if data.n() == 0 { - return Err(BuildError::ZeroDegree); - } - - if data.cols() == 0 { - return Err(BuildError::ZeroCols); - } - - if data.size() == 0 { - return Err(BuildError::ZeroLimbs); - } - - Ok(GGSWCiphertextPrepared { - data, - base2k, - k, - dsize, - }) - } -} - -impl<B: Backend> GGSWCiphertextPrepared<Vec<u8>, B> { - pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: GGSWInfos, - Module<B>: VmpPMatAlloc<B>, - { - Self::alloc_with( - module, - infos.base2k(), - infos.k(), - infos.dnum(), - infos.dsize(), - infos.rank(), - ) - } - - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self - where - Module<B>: VmpPMatAlloc<B>, - { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - Self { - data: module.vmp_pmat_alloc( - dnum.into(), - (rank + 1).into(), - (rank + 1).into(), - k.0.div_ceil(base2k.0) as usize, - ), - k, - base2k, - dsize, - } - } - - pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize - where - A: GGSWInfos, - Module<B>: VmpPMatAllocBytes, - { - Self::alloc_bytes_with( - module, - infos.base2k(), - infos.k(), - infos.dnum(), - infos.dsize(), - infos.rank(), - ) - } - - pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> usize - where - Module<B>: VmpPMatAllocBytes, - { - let size: usize = k.0.div_ceil(base2k.0) as usize; - debug_assert!( - size as u32 > dsize.0, - "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}", - dsize.0 - ); - - assert!( - dnum.0 * dsize.0 <= size as u32, - "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}", - dnum.0, - dsize.0, - ); - - module.vmp_pmat_alloc_bytes(dnum.into(), (rank + 1).into(), (rank + 1).into(), size) - } -} - -impl<D: DataRef, B: Backend> GGSWCiphertextPrepared<D, B> { - pub fn data(&self) -> &VmpPMat<D, B> { - &self.data - } -} - -impl<B: Backend, A: GGSWInfos> PrepareScratchSpace<B, A> for GGSWCiphertextPrepared<Vec<u8>, B> -where - Module<B>: VmpPrepareTmpBytes, -{ - fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize { - module.vmp_prepare_tmp_bytes( - infos.dnum().into(), - (infos.rank() + 1).into(), - (infos.rank() + 1).into(), - infos.size(), - ) - } -} - -impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGSWCiphertext<DR>> for GGSWCiphertextPrepared<D, B> -where - Module<B>: VmpPrepare<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &GGSWCiphertext<DR>, scratch: &mut Scratch<B>) { - module.vmp_prepare(&mut self.data, &other.data, scratch); - self.k = other.k; - self.base2k = other.base2k; - self.dsize = other.dsize; - } -} - -impl<D: DataRef, B: Backend> PrepareAlloc<B, GGSWCiphertextPrepared<Vec<u8>, B>> for GGSWCiphertext<D> -where - Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGSWCiphertextPrepared<Vec<u8>, B> { - let mut ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = GGSWCiphertextPrepared::alloc(module, self); - ggsw_prepared.prepare(module, self, scratch); - ggsw_prepared - } -} - -pub trait GGSWCiphertextPreparedToRef<B: Backend> { - fn to_ref(&self) -> GGSWCiphertextPrepared<&[u8], B>; -} - -impl<D: DataRef, B: Backend> GGSWCiphertextPreparedToRef<B> for GGSWCiphertextPrepared<D, B> { - fn to_ref(&self) -> GGSWCiphertextPrepared<&[u8], B> { - GGSWCiphertextPrepared::builder() - .base2k(self.base2k()) - .dsize(self.dsize()) - .k(self.k()) - .data(self.data.to_ref()) - .build() - .unwrap() - } -}
@@ -0,0 +1,161 @@
+use poulpy_hal::{ + api::{VecZnxDftAlloc, VecZnxDftApply, VecZnxDftBytesOf}, + layouts::{Backend, Data, DataMut, DataRef, Module, VecZnxDft, VecZnxDftToMut, VecZnxDftToRef, ZnxInfos}, +}; + +use crate::layouts::{Base2K, Degree, GLWE, GLWEInfos, GLWEToRef, GetDegree, LWEInfos, Rank, TorusPrecision}; + +#[derive(PartialEq, Eq)] +pub struct GLWEPrepared<D: Data, B: Backend> { + pub(crate) data: VecZnxDft<D, B>, + pub(crate) base2k: Base2K, + pub(crate) k: TorusPrecision, +} + +impl<D: Data, B: Backend> LWEInfos for GLWEPrepared<D, B> { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn size(&self) -> usize { + self.data.size() + } + + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } +} + +impl<D: Data, B: Backend> GLWEInfos for GLWEPrepared<D, B> { + fn rank(&self) -> Rank { + Rank(self.data.cols() as u32 - 1) + } +} + +pub trait GLWEPreparedFactory<B: Backend> +where + Self: GetDegree + VecZnxDftAlloc<B> + VecZnxDftBytesOf + VecZnxDftApply<B>, +{ + fn alloc_glwe_prepared(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWEPrepared<Vec<u8>, B> { + GLWEPrepared { + data: self.vec_znx_dft_alloc((rank + 1).into(), k.0.div_ceil(base2k.0) as usize), + base2k, + k, + } + } + + fn alloc_glwe_prepared_from_infos<A>(&self, infos: &A) -> GLWEPrepared<Vec<u8>, B> + where + A: GLWEInfos, + { + self.alloc_glwe_prepared(infos.base2k(), infos.k(), infos.rank()) + } + + fn bytes_of_glwe_prepared(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize { + self.bytes_of_vec_znx_dft((rank + 1).into(), k.0.div_ceil(base2k.0) as usize) + } + + fn bytes_of_glwe_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GLWEInfos, + { + self.bytes_of_glwe_prepared(infos.base2k(), infos.k(), infos.rank()) + } + + fn prepare_glwe<R, O>(&self, res: &mut R, other: &O) + where + R: GLWEPreparedToMut<B>, + O: GLWEToRef, + { + { + let mut res: GLWEPrepared<&mut [u8], B> = res.to_mut(); + let other: GLWE<&[u8]> = other.to_ref(); + + assert_eq!(res.n(), self.ring_degree()); + assert_eq!(other.n(), self.ring_degree()); + assert_eq!(res.size(), other.size()); + assert_eq!(res.k(), other.k()); + assert_eq!(res.base2k(), other.base2k()); + + for i in 0..(res.rank() + 1).into() { + self.vec_znx_dft_apply(1, 0, &mut res.data, i, &other.data, i); + } + } + } +} + +impl<B: Backend> GLWEPreparedFactory<B> for Module<B> where Self: VecZnxDftAlloc<B> + VecZnxDftBytesOf + VecZnxDftApply<B> {} + +impl<B: Backend> GLWEPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GLWEInfos, + M: GLWEPreparedFactory<B>, + { + module.alloc_glwe_prepared_from_infos(infos) + } + + pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self + where + M: GLWEPreparedFactory<B>, + { + module.alloc_glwe_prepared(base2k, k, rank) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GLWEInfos, + M: GLWEPreparedFactory<B>, + { + module.bytes_of_glwe_prepared_from_infos(infos) + } + + pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize + where + M: GLWEPreparedFactory<B>, + { + module.bytes_of_glwe_prepared(base2k, k, rank) + } +} + +impl<D: DataMut, B: Backend> GLWEPrepared<D, B> { + pub fn prepare<O, M>(&mut self, module: &M, other: &O) + where + O: GLWEToRef, + M: GLWEPreparedFactory<B>, + { + module.prepare_glwe(self, other); + } +} + +pub trait GLWEPreparedToMut<B: Backend> { + fn to_mut(&mut self) -> GLWEPrepared<&mut [u8], B>; +} + +impl<D: DataMut, B: Backend> GLWEPreparedToMut<B> for GLWEPrepared<D, B> { + fn to_mut(&mut self) -> GLWEPrepared<&mut [u8], B> { + GLWEPrepared { + k: self.k, + base2k: self.base2k, + data: self.data.to_mut(), + } + } +} + +pub trait GLWEPreparedToRef<B: Backend> { + fn to_ref(&self) -> GLWEPrepared<&[u8], B>; +} + +impl<D: DataRef, B: Backend> GLWEPreparedToRef<B> for GLWEPrepared<D, B> { + fn to_ref(&self) -> GLWEPrepared<&[u8], B> { + GLWEPrepared { + data: self.data.to_ref(), + k: self.k, + base2k: self.base2k, + } + } +}
@@ -0,0 +1,213 @@
+use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWEPrepared, GGLWEPreparedFactory, GGLWEPreparedToMut, GGLWEPreparedToRef, + GGLWEToRef, GLWEInfos, GetGaloisElement, LWEInfos, Rank, SetGaloisElement, TorusPrecision, +}; + +#[derive(PartialEq, Eq)] +pub struct GLWEAutomorphismKeyPrepared<D: Data, B: Backend> { + pub(crate) key: GGLWEPrepared<D, B>, + pub(crate) p: i64, +} + +impl<D: Data, B: Backend> LWEInfos for GLWEAutomorphismKeyPrepared<D, B> { + fn n(&self) -> Degree { + self.key.n() + } + + fn base2k(&self) -> Base2K { + self.key.base2k() + } + + fn k(&self) -> TorusPrecision { + self.key.k() + } + + fn size(&self) -> usize { + self.key.size() + } +} + +impl<D: Data, B: Backend> GetGaloisElement for GLWEAutomorphismKeyPrepared<D, B> { + fn p(&self) -> i64 { + self.p + } +} + +impl<D: Data, B: Backend> SetGaloisElement for GLWEAutomorphismKeyPrepared<D, B> { + fn set_p(&mut self, p: i64) { + self.p = p + } +} + +impl<D: Data, B: Backend> GLWEInfos for GLWEAutomorphismKeyPrepared<D, B> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data, B: Backend> GGLWEInfos for GLWEAutomorphismKeyPrepared<D, B> { + fn rank_in(&self) -> Rank { + self.key.rank_in() + } + + fn rank_out(&self) -> Rank { + self.key.rank_out() + } + + fn dsize(&self) -> Dsize { + self.key.dsize() + } + + fn dnum(&self) -> Dnum { + self.key.dnum() + } +} + +pub trait GLWEAutomorphismKeyPreparedFactory<B: Backend> +where + Self: GGLWEPreparedFactory<B>, +{ + fn alloc_glwe_automorphism_key_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + rank: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> GLWEAutomorphismKeyPrepared<Vec<u8>, B> { + GLWEAutomorphismKeyPrepared::<Vec<u8>, B> { + key: self.alloc_gglwe_prepared(base2k, k, rank, rank, dnum, dsize), + p: 0, + } + } + + fn alloc_glwe_automorphism_key_prepared_from_infos<A>(&self, infos: &A) -> GLWEAutomorphismKeyPrepared<Vec<u8>, B> + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_in(), + infos.rank_out(), + "rank_in != rank_out is not supported for AutomorphismKeyPrepared" + ); + self.alloc_glwe_automorphism_key_prepared( + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + fn bytes_of_glwe_automorphism_key_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + rank: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> usize { + self.bytes_of_gglwe_prepared(base2k, k, rank, rank, dnum, dsize) + } + + fn bytes_of_glwe_automorphism_key_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_in(), + infos.rank_out(), + "rank_in != rank_out is not supported for AutomorphismKeyPrepared" + ); + self.bytes_of_glwe_automorphism_key_prepared( + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + fn prepare_glwe_automorphism_key_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.prepare_gglwe_tmp_bytes(infos) + } + + fn prepare_glwe_automorphism_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>) + where + R: GGLWEPreparedToMut<B> + SetGaloisElement, + O: GGLWEToRef + GetGaloisElement, + { + self.prepare_gglwe(res, other, scratch); + res.set_p(other.p()); + } +} + +impl<B: Backend> GLWEAutomorphismKeyPreparedFactory<B> for Module<B> where Module<B>: GGLWEPreparedFactory<B> {} + +impl<B: Backend> GLWEAutomorphismKeyPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GGLWEInfos, + M: GLWEAutomorphismKeyPreparedFactory<B>, + { + module.alloc_glwe_automorphism_key_prepared_from_infos(infos) + } + + pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self + where + M: GLWEAutomorphismKeyPreparedFactory<B>, + { + module.alloc_glwe_automorphism_key_prepared(base2k, k, rank, dnum, dsize) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWEAutomorphismKeyPreparedFactory<B>, + { + module.bytes_of_glwe_automorphism_key_prepared_from_infos(infos) + } + + pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize + where + M: GLWEAutomorphismKeyPreparedFactory<B>, + { + module.bytes_of_glwe_automorphism_key_prepared(base2k, k, rank, dnum, dsize) + } +} + +impl<B: Backend> GLWEAutomorphismKeyPrepared<Vec<u8>, B> { + pub fn prepare_tmp_bytes<M>(&self, module: &M) -> usize + where + M: GLWEAutomorphismKeyPreparedFactory<B>, + { + module.prepare_glwe_automorphism_key_tmp_bytes(self) + } +} + +impl<D: DataMut, B: Backend> GLWEAutomorphismKeyPrepared<D, B> { + pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>) + where + O: GGLWEToRef + GetGaloisElement, + M: GLWEAutomorphismKeyPreparedFactory<B>, + { + module.prepare_glwe_automorphism_key(self, other, scratch); + } +} + +impl<D: DataMut, B: Backend> GGLWEPreparedToMut<B> for GLWEAutomorphismKeyPrepared<D, B> { + fn to_mut(&mut self) -> GGLWEPrepared<&mut [u8], B> { + self.key.to_mut() + } +} + +impl<D: DataRef, BE: Backend> GGLWEPreparedToRef<BE> for GLWEAutomorphismKeyPrepared<D, BE> { + fn to_ref(&self) -> GGLWEPrepared<&[u8], BE> { + self.key.to_ref() + } +}
@@ -1,207 +0,0 @@
-use poulpy_hal::{ - api::{VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VecZnxDft, ZnxInfos}, - oep::VecZnxDftAllocBytesImpl, -}; - -use crate::{ - dist::Distribution, - layouts::{ - Base2K, BuildError, Degree, GLWEInfos, GLWEPublicKey, LWEInfos, Rank, TorusPrecision, - prepared::{Prepare, PrepareAlloc, PrepareScratchSpace}, - }, -}; - -#[derive(PartialEq, Eq)] -pub struct GLWEPublicKeyPrepared<D: Data, B: Backend> { - pub(crate) data: VecZnxDft<D, B>, - pub(crate) base2k: Base2K, - pub(crate) k: TorusPrecision, - pub(crate) dist: Distribution, -} - -impl<D: Data, B: Backend> LWEInfos for GLWEPublicKeyPrepared<D, B> { - fn base2k(&self) -> Base2K { - self.base2k - } - - fn k(&self) -> TorusPrecision { - self.k - } - - fn size(&self) -> usize { - self.data.size() - } - - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } -} - -impl<D: Data, B: Backend> GLWEInfos for GLWEPublicKeyPrepared<D, B> { - fn rank(&self) -> Rank { - Rank(self.data.cols() as u32 - 1) - } -} - -pub struct GLWEPublicKeyPreparedBuilder<D: Data, B: Backend> { - data: Option<VecZnxDft<D, B>>, - base2k: Option<Base2K>, - k: Option<TorusPrecision>, -} - -impl<D: Data, B: Backend> GLWEPublicKeyPrepared<D, B> { - #[inline] - pub fn builder() -> GLWEPublicKeyPreparedBuilder<D, B> { - GLWEPublicKeyPreparedBuilder { - data: None, - base2k: None, - k: None, - } - } -} - -impl<B: Backend> GLWEPublicKeyPreparedBuilder<Vec<u8>, B> { - #[inline] - pub fn layout<A>(mut self, layout: &A) -> Self - where - A: GLWEInfos, - B: VecZnxDftAllocBytesImpl<B>, - { - self.data = Some(VecZnxDft::alloc( - layout.n().into(), - (layout.rank() + 1).into(), - layout.size(), - )); - self.base2k = Some(layout.base2k()); - self.k = Some(layout.k()); - self - } -} - -impl<D: Data, B: Backend> GLWEPublicKeyPreparedBuilder<D, B> { - #[inline] - pub fn data(mut self, data: VecZnxDft<D, B>) -> Self { - self.data = Some(data); - self - } - #[inline] - pub fn base2k(mut self, base2k: Base2K) -> Self { - self.base2k = Some(base2k); - self - } - #[inline] - pub fn k(mut self, k: TorusPrecision) -> Self { - self.k = Some(k); - self - } - - pub fn build(self) -> Result<GLWEPublicKeyPrepared<D, B>, BuildError> { - let data: VecZnxDft<D, B> = self.data.ok_or(BuildError::MissingData)?; - let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?; - let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?; - - if base2k == 0_u32 { - return Err(BuildError::ZeroBase2K); - } - - if k == 0_u32 { - return Err(BuildError::ZeroTorusPrecision); - } - - if data.n() == 0 { - return Err(BuildError::ZeroDegree); - } - - if data.cols() == 0 { - return Err(BuildError::ZeroCols); - } - - if data.size() == 0 { - return Err(BuildError::ZeroLimbs); - } - - Ok(GLWEPublicKeyPrepared { - data, - base2k, - k, - dist: Distribution::NONE, - }) - } -} - -impl<B: Backend> GLWEPublicKeyPrepared<Vec<u8>, B> { - pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: GLWEInfos, - Module<B>: VecZnxDftAlloc<B>, - { - debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()"); - Self::alloc_with(module, infos.base2k(), infos.k(), infos.rank()) - } - - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self - where - Module<B>: VecZnxDftAlloc<B>, - { - Self { - data: module.vec_znx_dft_alloc((rank + 1).into(), k.0.div_ceil(base2k.0) as usize), - base2k, - k, - dist: Distribution::NONE, - } - } - - pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize - where - A: GLWEInfos, - Module<B>: VecZnxDftAllocBytes, - { - debug_assert_eq!(module.n(), infos.n().0 as usize, "module.n() != infos.n()"); - Self::alloc_bytes_with(module, infos.base2k(), infos.k(), infos.rank()) - } - - pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize - where - Module<B>: VecZnxDftAllocBytes, - { - module.vec_znx_dft_alloc_bytes((rank + 1).into(), k.0.div_ceil(base2k.0) as usize) - } -} - -impl<D: DataRef, B: Backend> PrepareAlloc<B, GLWEPublicKeyPrepared<Vec<u8>, B>> for GLWEPublicKey<D> -where - Module<B>: VecZnxDftAlloc<B> + VecZnxDftApply<B>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GLWEPublicKeyPrepared<Vec<u8>, B> { - let mut pk_prepared: GLWEPublicKeyPrepared<Vec<u8>, B> = GLWEPublicKeyPrepared::alloc(module, self); - pk_prepared.prepare(module, self, scratch); - pk_prepared - } -} - -impl<B: Backend, A: GLWEInfos> PrepareScratchSpace<B, A> for GLWEPublicKeyPrepared<Vec<u8>, B> { - fn prepare_scratch_space(_module: &Module<B>, _infos: &A) -> usize { - 0 - } -} - -impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, GLWEPublicKey<DR>> for GLWEPublicKeyPrepared<DM, B> -where - Module<B>: VecZnxDftApply<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &GLWEPublicKey<DR>, _scratch: &mut Scratch<B>) { - #[cfg(debug_assertions)] - { - assert_eq!(self.n(), other.n()); - assert_eq!(self.size(), other.size()); - } - - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_dft_apply(1, 0, &mut self.data, i, &other.data, i); - }); - self.k = other.k(); - self.base2k = other.base2k(); - self.dist = other.dist; - } -}
@@ -0,0 +1,157 @@
+use poulpy_hal::{ + api::{VecZnxDftAlloc, VecZnxDftApply, VecZnxDftBytesOf}, + layouts::{Backend, Data, DataMut, DataRef, Module}, +}; + +use crate::{ + GetDistribution, GetDistributionMut, + dist::Distribution, + layouts::{ + Base2K, Degree, GLWEInfos, GLWEPrepared, GLWEPreparedFactory, GLWEPreparedToMut, GLWEPreparedToRef, GLWEToRef, GetDegree, + LWEInfos, Rank, TorusPrecision, + }, +}; + +#[derive(PartialEq, Eq)] +pub struct GLWEPublicKeyPrepared<D: Data, B: Backend> { + pub(crate) key: GLWEPrepared<D, B>, + pub(crate) dist: Distribution, +} + +impl<D: DataRef, BE: Backend> GetDistribution for GLWEPublicKeyPrepared<D, BE> { + fn dist(&self) -> &Distribution { + &self.dist + } +} + +impl<D: DataMut, BE: Backend> GetDistributionMut for GLWEPublicKeyPrepared<D, BE> { + fn dist_mut(&mut self) -> &mut Distribution { + &mut self.dist + } +} + +impl<D: Data, B: Backend> LWEInfos for GLWEPublicKeyPrepared<D, B> { + fn base2k(&self) -> Base2K { + self.key.base2k() + } + + fn k(&self) -> TorusPrecision { + self.key.k() + } + + fn size(&self) -> usize { + self.key.size() + } + + fn n(&self) -> Degree { + self.key.n() + } +} + +impl<D: Data, B: Backend> GLWEInfos for GLWEPublicKeyPrepared<D, B> { + fn rank(&self) -> Rank { + self.key.rank() + } +} + +pub trait GLWEPublicKeyPreparedFactory<B: Backend> +where + Self: GetDegree + GLWEPreparedFactory<B>, +{ + fn alloc_glwe_public_key_prepared(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWEPublicKeyPrepared<Vec<u8>, B> { + GLWEPublicKeyPrepared { + key: self.alloc_glwe_prepared(base2k, k, rank), + dist: Distribution::NONE, + } + } + + fn alloc_glwe_public_key_prepared_from_infos<A>(&self, infos: &A) -> GLWEPublicKeyPrepared<Vec<u8>, B> + where + A: GLWEInfos, + { + self.alloc_glwe_public_key_prepared(infos.base2k(), infos.k(), infos.rank()) + } + + fn bytes_of_glwe_public_key_prepared(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize { + self.bytes_of_glwe_prepared(base2k, k, rank) + } + + fn bytes_of_glwe_public_key_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GLWEInfos, + { + self.bytes_of_glwe_public_key_prepared(infos.base2k(), infos.k(), infos.rank()) + } + + fn prepare_glwe_public_key<R, O>(&self, res: &mut R, other: &O) + where + R: GLWEPreparedToMut<B> + GetDistributionMut, + O: GLWEToRef + GetDistribution, + { + self.prepare_glwe(res, other); + *res.dist_mut() = *other.dist(); + } +} + +impl<B: Backend> GLWEPublicKeyPreparedFactory<B> for Module<B> where Self: VecZnxDftAlloc<B> + VecZnxDftBytesOf + VecZnxDftApply<B> +{} + +impl<B: Backend> GLWEPublicKeyPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GLWEInfos, + M: GLWEPublicKeyPreparedFactory<B>, + { + module.alloc_glwe_public_key_prepared_from_infos(infos) + } + + pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self + where + M: GLWEPublicKeyPreparedFactory<B>, + { + module.alloc_glwe_public_key_prepared(base2k, k, rank) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GLWEInfos, + M: GLWEPublicKeyPreparedFactory<B>, + { + module.bytes_of_glwe_public_key_prepared_from_infos(infos) + } + + pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize + where + M: GLWEPublicKeyPreparedFactory<B>, + { + module.bytes_of_glwe_public_key_prepared(base2k, k, rank) + } +} + +impl<D: DataMut, B: Backend> GLWEPublicKeyPrepared<D, B> { + pub fn prepare<O, M>(&mut self, module: &M, other: &O) + where + O: GLWEToRef + GetDistribution, + M: GLWEPublicKeyPreparedFactory<B>, + { + module.prepare_glwe_public_key(self, other); + } +} + +impl<D: DataMut, B: Backend> GLWEPreparedToMut<B> for GLWEPublicKeyPrepared<D, B> +where + GLWEPrepared<D, B>: GLWEPreparedToMut<B>, +{ + fn to_mut(&mut self) -> GLWEPrepared<&mut [u8], B> { + self.key.to_mut() + } +} + +impl<D: DataRef, B: Backend> GLWEPreparedToRef<B> for GLWEPublicKeyPrepared<D, B> +where + GLWEPrepared<D, B>: GLWEPreparedToRef<B>, +{ + fn to_ref(&self) -> GLWEPrepared<&[u8], B> { + self.key.to_ref() + } +}
@@ -0,0 +1,183 @@
+use poulpy_hal::{ + api::{SvpPPolAlloc, SvpPPolBytesOf, SvpPrepare}, + layouts::{Backend, Data, DataMut, DataRef, Module, SvpPPol, SvpPPolToMut, SvpPPolToRef, ZnxInfos}, +}; + +use crate::{ + GetDistribution, GetDistributionMut, + dist::Distribution, + layouts::{Base2K, Degree, GLWEInfos, GLWESecret, GLWESecretToRef, GetDegree, LWEInfos, Rank, TorusPrecision}, +}; + +pub struct GLWESecretPrepared<D: Data, B: Backend> { + pub(crate) data: SvpPPol<D, B>, + pub(crate) dist: Distribution, +} + +impl<D: DataRef, BE: Backend> GetDistribution for GLWESecretPrepared<D, BE> { + fn dist(&self) -> &Distribution { + &self.dist + } +} + +impl<D: DataMut, BE: Backend> GetDistributionMut for GLWESecretPrepared<D, BE> { + fn dist_mut(&mut self) -> &mut Distribution { + &mut self.dist + } +} + +impl<D: Data, B: Backend> LWEInfos for GLWESecretPrepared<D, B> { + fn base2k(&self) -> Base2K { + Base2K(0) + } + + fn k(&self) -> TorusPrecision { + TorusPrecision(0) + } + + fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } + + fn size(&self) -> usize { + self.data.size() + } +} +impl<D: Data, B: Backend> GLWEInfos for GLWESecretPrepared<D, B> { + fn rank(&self) -> Rank { + Rank(self.data.cols() as u32) + } +} + +pub trait GLWESecretPreparedFactory<B: Backend> +where + Self: GetDegree + SvpPPolBytesOf + SvpPPolAlloc<B> + SvpPrepare<B>, +{ + fn alloc_glwe_secret_prepared(&self, rank: Rank) -> GLWESecretPrepared<Vec<u8>, B> { + GLWESecretPrepared { + data: self.svp_ppol_alloc(rank.into()), + dist: Distribution::NONE, + } + } + fn alloc_glwe_secret_prepared_from_infos<A>(&self, infos: &A) -> GLWESecretPrepared<Vec<u8>, B> + where + A: GLWEInfos, + { + assert_eq!(self.ring_degree(), infos.n()); + self.alloc_glwe_secret_prepared(infos.rank()) + } + + fn bytes_of_glwe_secret_prepared(&self, rank: Rank) -> usize { + self.bytes_of_svp_ppol(rank.into()) + } + fn bytes_of_glwe_secret_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GLWEInfos, + { + assert_eq!(self.ring_degree(), infos.n()); + self.bytes_of_glwe_secret_prepared(infos.rank()) + } + + fn prepare_glwe_secret<R, O>(&self, res: &mut R, other: &O) + where + R: GLWESecretPreparedToMut<B> + GetDistributionMut, + O: GLWESecretToRef + GetDistribution, + { + { + let mut res: GLWESecretPrepared<&mut [u8], _> = res.to_mut(); + let other: GLWESecret<&[u8]> = other.to_ref(); + + for i in 0..res.rank().into() { + self.svp_prepare(&mut res.data, i, &other.data, i); + } + } + + *res.dist_mut() = *other.dist(); + } +} + +impl<B: Backend> GLWESecretPreparedFactory<B> for Module<B> where + Self: GetDegree + SvpPPolBytesOf + SvpPPolAlloc<B> + SvpPrepare<B> +{ +} + +impl<B: Backend> GLWESecretPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GLWEInfos, + M: GLWESecretPreparedFactory<B>, + { + module.alloc_glwe_secret_prepared_from_infos(infos) + } + + pub fn alloc<M>(module: &M, rank: Rank) -> Self + where + M: GLWESecretPreparedFactory<B>, + { + module.alloc_glwe_secret_prepared(rank) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GLWEInfos, + M: GLWESecretPreparedFactory<B>, + { + module.bytes_of_glwe_secret_prepared_from_infos(infos) + } + + pub fn bytes_of<M>(module: &M, rank: Rank) -> usize + where + M: GLWESecretPreparedFactory<B>, + { + module.bytes_of_glwe_secret_prepared(rank) + } +} + +impl<D: Data, B: Backend> GLWESecretPrepared<D, B> { + pub fn n(&self) -> Degree { + Degree(self.data.n() as u32) + } + + pub fn rank(&self) -> Rank { + Rank(self.data.cols() as u32) + } +} + +impl<D: DataMut, B: Backend> GLWESecretPrepared<D, B> { + pub fn prepare<M, O>(&mut self, module: &M, other: &O) + where + M: GLWESecretPreparedFactory<B>, + O: GLWESecretToRef + GetDistribution, + { + module.prepare_glwe_secret(self, other); + } +} + +pub trait GLWESecretPreparedToRef<B: Backend> { + fn to_ref(&self) -> GLWESecretPrepared<&[u8], B>; +} + +impl<D: DataRef, B: Backend> GLWESecretPreparedToRef<B> for GLWESecretPrepared<D, B> { + fn to_ref(&self) -> GLWESecretPrepared<&[u8], B> { + GLWESecretPrepared { + data: self.data.to_ref(), + dist: self.dist, + } + } +} + +pub trait GLWESecretPreparedToMut<B: Backend> +where + Self: GLWESecretPreparedToRef<B>, +{ + fn to_mut(&mut self) -> GLWESecretPrepared<&mut [u8], B>; +} + +impl<D: DataMut, B: Backend> GLWESecretPreparedToMut<B> for GLWESecretPrepared<D, B> { + fn to_mut(&mut self) -> GLWESecretPrepared<&mut [u8], B> { + GLWESecretPrepared { + dist: self.dist, + data: self.data.to_mut(), + } + } +}
@@ -1,115 +0,0 @@
-use poulpy_hal::{ - api::{SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, SvpPPol, ZnxInfos}, -}; - -use crate::{ - dist::Distribution, - layouts::{ - Base2K, Degree, GLWEInfos, GLWESecret, LWEInfos, Rank, TorusPrecision, - prepared::{Prepare, PrepareAlloc, PrepareScratchSpace}, - }, -}; - -pub struct GLWESecretPrepared<D: Data, B: Backend> { - pub(crate) data: SvpPPol<D, B>, - pub(crate) dist: Distribution, -} - -impl<D: Data, B: Backend> LWEInfos for GLWESecretPrepared<D, B> { - fn base2k(&self) -> Base2K { - Base2K(0) - } - - fn k(&self) -> TorusPrecision { - TorusPrecision(0) - } - - fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - fn size(&self) -> usize { - self.data.size() - } -} -impl<D: Data, B: Backend> GLWEInfos for GLWESecretPrepared<D, B> { - fn rank(&self) -> Rank { - Rank(self.data.cols() as u32) - } -} -impl<B: Backend> GLWESecretPrepared<Vec<u8>, B> { - pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: GLWEInfos, - Module<B>: SvpPPolAlloc<B>, - { - assert_eq!(module.n() as u32, infos.n()); - Self::alloc_with(module, infos.rank()) - } - - pub fn alloc_with(module: &Module<B>, rank: Rank) -> Self - where - Module<B>: SvpPPolAlloc<B>, - { - Self { - data: module.svp_ppol_alloc(rank.into()), - dist: Distribution::NONE, - } - } - - pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize - where - A: GLWEInfos, - Module<B>: SvpPPolAllocBytes, - { - assert_eq!(module.n() as u32, infos.n()); - Self::alloc_bytes_with(module, infos.rank()) - } - - pub fn alloc_bytes_with(module: &Module<B>, rank: Rank) -> usize - where - Module<B>: SvpPPolAllocBytes, - { - module.svp_ppol_alloc_bytes(rank.into()) - } -} - -impl<D: Data, B: Backend> GLWESecretPrepared<D, B> { - pub fn n(&self) -> Degree { - Degree(self.data.n() as u32) - } - - pub fn rank(&self) -> Rank { - Rank(self.data.cols() as u32) - } -} - -impl<B: Backend, A: GLWEInfos> PrepareScratchSpace<B, A> for GLWESecretPrepared<Vec<u8>, B> { - fn prepare_scratch_space(_module: &Module<B>, _infos: &A) -> usize { - 0 - } -} - -impl<D: DataRef, B: Backend> PrepareAlloc<B, GLWESecretPrepared<Vec<u8>, B>> for GLWESecret<D> -where - Module<B>: SvpPrepare<B> + SvpPPolAlloc<B>, -{ - fn prepare_alloc(&self, module: &Module<B>, _scratch: &mut Scratch<B>) -> GLWESecretPrepared<Vec<u8>, B> { - let mut sk_dft: GLWESecretPrepared<Vec<u8>, B> = GLWESecretPrepared::alloc(module, self); - sk_dft.prepare(module, self, _scratch); - sk_dft - } -} - -impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, GLWESecret<DR>> for GLWESecretPrepared<DM, B> -where - Module<B>: SvpPrepare<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &GLWESecret<DR>, _scratch: &mut Scratch<B>) { - (0..self.rank().into()).for_each(|i| { - module.svp_prepare(&mut self.data, i, &other.data, i); - }); - self.dist = other.dist - } -}
@@ -0,0 +1,241 @@
+use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWEToRef, GLWEInfos, GLWESwitchingKeyDegrees, GLWESwitchingKeyDegreesMut, + LWEInfos, Rank, TorusPrecision, + prepared::{GGLWEPrepared, GGLWEPreparedFactory, GGLWEPreparedToMut, GGLWEPreparedToRef}, +}; + +#[derive(PartialEq, Eq)] +pub struct GLWESwitchingKeyPrepared<D: Data, B: Backend> { + pub(crate) key: GGLWEPrepared<D, B>, + pub(crate) input_degree: Degree, // Degree of sk_in + pub(crate) output_degree: Degree, // Degree of sk_out +} + +impl<D: DataRef, BE: Backend> GLWESwitchingKeyDegrees for GLWESwitchingKeyPrepared<D, BE> { + fn output_degree(&self) -> &Degree { + &self.output_degree + } + + fn input_degree(&self) -> &Degree { + &self.input_degree + } +} + +impl<D: DataMut, BE: Backend> GLWESwitchingKeyDegreesMut for GLWESwitchingKeyPrepared<D, BE> { + fn output_degree(&mut self) -> &mut Degree { + &mut self.output_degree + } + + fn input_degree(&mut self) -> &mut Degree { + &mut self.input_degree + } +} + +impl<D: Data, B: Backend> LWEInfos for GLWESwitchingKeyPrepared<D, B> { + fn n(&self) -> Degree { + self.key.n() + } + + fn base2k(&self) -> Base2K { + self.key.base2k() + } + + fn k(&self) -> TorusPrecision { + self.key.k() + } + + fn size(&self) -> usize { + self.key.size() + } +} + +impl<D: Data, B: Backend> GLWEInfos for GLWESwitchingKeyPrepared<D, B> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data, B: Backend> GGLWEInfos for GLWESwitchingKeyPrepared<D, B> { + fn rank_in(&self) -> Rank { + self.key.rank_in() + } + + fn rank_out(&self) -> Rank { + self.key.rank_out() + } + + fn dsize(&self) -> Dsize { + self.key.dsize() + } + + fn dnum(&self) -> Dnum { + self.key.dnum() + } +} + +pub trait GLWESwitchingKeyPreparedFactory<B: Backend> +where + Self: GGLWEPreparedFactory<B>, +{ + fn alloc_glwe_switching_key_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> GLWESwitchingKeyPrepared<Vec<u8>, B> { + GLWESwitchingKeyPrepared::<Vec<u8>, B> { + key: self.alloc_gglwe_prepared(base2k, k, rank_in, rank_out, dnum, dsize), + input_degree: Degree(0), + output_degree: Degree(0), + } + } + + fn alloc_glwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> GLWESwitchingKeyPrepared<Vec<u8>, B> + where + A: GGLWEInfos, + { + self.alloc_glwe_switching_key_prepared( + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.rank_out(), + infos.dnum(), + infos.dsize(), + ) + } + + fn bytes_of_glwe_switching_key_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> usize { + self.bytes_of_gglwe_prepared(base2k, k, rank_in, rank_out, dnum, dsize) + } + + fn bytes_of_glwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.bytes_of_glwe_switching_key_prepared( + infos.base2k(), + infos.k(), + infos.rank_in(), + infos.rank_out(), + infos.dnum(), + infos.dsize(), + ) + } + + fn prepare_glwe_switching_key_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.prepare_gglwe_tmp_bytes(infos) + } + + fn prepare_glwe_switching<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>) + where + R: GGLWEPreparedToMut<B> + GLWESwitchingKeyDegreesMut, + O: GGLWEToRef + GLWESwitchingKeyDegrees, + { + self.prepare_gglwe(res, other, scratch); + *res.input_degree() = *other.input_degree(); + *res.output_degree() = *other.output_degree(); + } +} + +impl<B: Backend> GLWESwitchingKeyPreparedFactory<B> for Module<B> where Self: GGLWEPreparedFactory<B> {} + +impl<B: Backend> GLWESwitchingKeyPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GGLWEInfos, + M: GLWESwitchingKeyPreparedFactory<B>, + { + module.alloc_glwe_switching_key_prepared_from_infos(infos) + } + + pub fn alloc<M>( + module: &M, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> Self + where + M: GLWESwitchingKeyPreparedFactory<B>, + { + module.alloc_glwe_switching_key_prepared(base2k, k, rank_in, rank_out, dnum, dsize) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWESwitchingKeyPreparedFactory<B>, + { + module.bytes_of_glwe_switching_key_prepared_from_infos(infos) + } + + pub fn bytes_of<M>( + module: &M, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> usize + where + M: GLWESwitchingKeyPreparedFactory<B>, + { + module.bytes_of_glwe_switching_key_prepared(base2k, k, rank_in, rank_out, dnum, dsize) + } +} + +impl<D: DataMut, B: Backend> GLWESwitchingKeyPrepared<D, B> { + pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>) + where + O: GGLWEToRef + GLWESwitchingKeyDegrees, + M: GLWESwitchingKeyPreparedFactory<B>, + { + module.prepare_glwe_switching(self, other, scratch); + } +} + +impl<B: Backend> GLWESwitchingKeyPrepared<Vec<u8>, B> { + pub fn prepare_tmp_bytes<M>(&self, module: &M) -> usize + where + M: GLWESwitchingKeyPreparedFactory<B>, + { + module.prepare_glwe_switching_key_tmp_bytes(self) + } +} + +impl<D: DataRef, BE: Backend> GGLWEPreparedToRef<BE> for GLWESwitchingKeyPrepared<D, BE> +where + GGLWEPrepared<D, BE>: GGLWEPreparedToRef<BE>, +{ + fn to_ref(&self) -> GGLWEPrepared<&[u8], BE> { + self.key.to_ref() + } +} + +impl<D: DataRef, BE: Backend> GGLWEPreparedToMut<BE> for GLWESwitchingKeyPrepared<D, BE> +where + GGLWEPrepared<D, BE>: GGLWEPreparedToMut<BE>, +{ + fn to_mut(&mut self) -> GGLWEPrepared<&mut [u8], BE> { + self.key.to_mut() + } +}
@@ -0,0 +1,238 @@
+use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWEPrepared, GGLWEPreparedFactory, GGLWEPreparedToMut, GGLWEPreparedToRef, + GLWEInfos, GLWETensorKey, GLWETensorKeyToRef, LWEInfos, Rank, TorusPrecision, +}; + +#[derive(PartialEq, Eq)] +pub struct GLWETensorKeyPrepared<D: Data, B: Backend> { + pub(crate) keys: Vec<GGLWEPrepared<D, B>>, +} + +impl<D: Data, B: Backend> LWEInfos for GLWETensorKeyPrepared<D, B> { + fn n(&self) -> Degree { + self.keys[0].n() + } + + fn base2k(&self) -> Base2K { + self.keys[0].base2k() + } + + fn k(&self) -> TorusPrecision { + self.keys[0].k() + } + + fn size(&self) -> usize { + self.keys[0].size() + } +} + +impl<D: Data, B: Backend> GLWEInfos for GLWETensorKeyPrepared<D, B> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data, B: Backend> GGLWEInfos for GLWETensorKeyPrepared<D, B> { + fn rank_in(&self) -> Rank { + self.rank_out() + } + + fn rank_out(&self) -> Rank { + self.keys[0].rank_out() + } + + fn dsize(&self) -> Dsize { + self.keys[0].dsize() + } + + fn dnum(&self) -> Dnum { + self.keys[0].dnum() + } +} + +pub trait GLWETensorKeyPreparedFactory<B: Backend> +where + Self: GGLWEPreparedFactory<B>, +{ + fn alloc_tensor_key_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + dnum: Dnum, + dsize: Dsize, + rank: Rank, + ) -> GLWETensorKeyPrepared<Vec<u8>, B> { + let pairs: u32 = (((rank.as_u32() + 1) * rank.as_u32()) >> 1).max(1); + GLWETensorKeyPrepared { + keys: (0..pairs) + .map(|_| self.alloc_gglwe_prepared(base2k, k, Rank(1), rank, dnum, dsize)) + .collect(), + } + } + + fn alloc_tensor_key_prepared_from_infos<A>(&self, infos: &A) -> GLWETensorKeyPrepared<Vec<u8>, B> + where + A: GGLWEInfos, + { + assert_eq!( + infos.rank_in(), + infos.rank_out(), + "rank_in != rank_out is not supported for TensorKeyPrepared" + ); + self.alloc_tensor_key_prepared( + infos.base2k(), + infos.k(), + infos.dnum(), + infos.dsize(), + infos.rank_out(), + ) + } + + fn bytes_of_tensor_key_prepared(&self, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize { + let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize; + pairs * self.bytes_of_gglwe_prepared(base2k, k, Rank(1), rank, dnum, dsize) + } + + fn bytes_of_tensor_key_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.bytes_of_tensor_key_prepared( + infos.base2k(), + infos.k(), + infos.rank(), + infos.dnum(), + infos.dsize(), + ) + } + + fn prepare_tensor_key_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.prepare_gglwe_tmp_bytes(infos) + } + + fn prepare_tensor_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>) + where + R: GLWETensorKeyPreparedToMut<B>, + O: GLWETensorKeyToRef, + { + let mut res: GLWETensorKeyPrepared<&mut [u8], B> = res.to_mut(); + let other: GLWETensorKey<&[u8]> = other.to_ref(); + + assert_eq!(res.keys.len(), other.keys.len()); + + for (a, b) in res.keys.iter_mut().zip(other.keys.iter()) { + self.prepare_gglwe(a, b, scratch); + } + } +} + +impl<B: Backend> GLWETensorKeyPreparedFactory<B> for Module<B> where Module<B>: GGLWEPreparedFactory<B> {} + +impl<B: Backend> GLWETensorKeyPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GGLWEInfos, + M: GLWETensorKeyPreparedFactory<B>, + { + module.alloc_tensor_key_prepared_from_infos(infos) + } + + pub fn alloc_with<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self + where + M: GLWETensorKeyPreparedFactory<B>, + { + module.alloc_tensor_key_prepared(base2k, k, dnum, dsize, rank) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWETensorKeyPreparedFactory<B>, + { + module.bytes_of_tensor_key_prepared_from_infos(infos) + } + + pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize + where + M: GLWETensorKeyPreparedFactory<B>, + { + module.bytes_of_tensor_key_prepared(base2k, k, rank, dnum, dsize) + } +} + +impl<D: DataMut, B: Backend> GLWETensorKeyPrepared<D, B> { + // Returns a mutable reference to GGLWE_{s}(s[i] * s[j]) + pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWEPrepared<D, B> { + if i > j { + std::mem::swap(&mut i, &mut j); + }; + let rank: usize = self.rank_out().into(); + &mut self.keys[i * rank + j - (i * (i + 1) / 2)] + } +} + +impl<D: DataRef, B: Backend> GLWETensorKeyPrepared<D, B> { + // Returns a reference to GGLWE_{s}(s[i] * s[j]) + pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWEPrepared<D, B> { + if i > j { + std::mem::swap(&mut i, &mut j); + }; + let rank: usize = self.rank_out().into(); + &self.keys[i * rank + j - (i * (i + 1) / 2)] + } +} + +impl<B: Backend> GLWETensorKeyPrepared<Vec<u8>, B> { + pub fn prepare_tmp_bytes<A, M>(&self, module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWETensorKeyPreparedFactory<B>, + { + module.prepare_tensor_key_tmp_bytes(infos) + } +} + +impl<D: DataMut, B: Backend> GLWETensorKeyPrepared<D, B> { + pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>) + where + O: GLWETensorKeyToRef, + M: GLWETensorKeyPreparedFactory<B>, + { + module.prepare_tensor_key(self, other, scratch); + } +} + +pub trait GLWETensorKeyPreparedToMut<B: Backend> { + fn to_mut(&mut self) -> GLWETensorKeyPrepared<&mut [u8], B>; +} + +impl<D: DataMut, B: Backend> GLWETensorKeyPreparedToMut<B> for GLWETensorKeyPrepared<D, B> +where + GGLWEPrepared<D, B>: GGLWEPreparedToMut<B>, +{ + fn to_mut(&mut self) -> GLWETensorKeyPrepared<&mut [u8], B> { + GLWETensorKeyPrepared { + keys: self.keys.iter_mut().map(|c| c.to_mut()).collect(), + } + } +} + +pub trait GLWETensorKeyPreparedToRef<B: Backend> { + fn to_ref(&self) -> GLWETensorKeyPrepared<&[u8], B>; +} + +impl<D: DataRef, B: Backend> GLWETensorKeyPreparedToRef<B> for GLWETensorKeyPrepared<D, B> +where + GGLWEPrepared<D, B>: GGLWEPreparedToRef<B>, +{ + fn to_ref(&self) -> GLWETensorKeyPrepared<&[u8], B> { + GLWETensorKeyPrepared { + keys: self.keys.iter().map(|c| c.to_ref()).collect(), + } + } +}
@@ -1,143 +0,0 @@
-use poulpy_hal::{ - api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, GLWEToLWEKey, LWEInfos, Rank, TorusPrecision, - prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace}, -}; - -#[derive(PartialEq, Eq)] -pub struct GLWEToLWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GGLWESwitchingKeyPrepared<D, B>); - -impl<D: Data, B: Backend> LWEInfos for GLWEToLWESwitchingKeyPrepared<D, B> { - fn base2k(&self) -> Base2K { - self.0.base2k() - } - - fn k(&self) -> TorusPrecision { - self.0.k() - } - - fn n(&self) -> Degree { - self.0.n() - } - - fn size(&self) -> usize { - self.0.size() - } -} - -impl<D: Data, B: Backend> GLWEInfos for GLWEToLWESwitchingKeyPrepared<D, B> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data, B: Backend> GGLWEInfos for GLWEToLWESwitchingKeyPrepared<D, B> { - fn rank_in(&self) -> Rank { - self.0.rank_in() - } - - fn dsize(&self) -> Dsize { - self.0.dsize() - } - - fn rank_out(&self) -> Rank { - self.0.rank_out() - } - - fn dnum(&self) -> Dnum { - self.0.dnum() - } -} - -impl<B: Backend> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> { - pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: GGLWEInfos, - Module<B>: VmpPMatAlloc<B>, - { - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is not supported for GLWEToLWESwitchingKeyPrepared" - ); - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for GLWEToLWESwitchingKeyPrepared" - ); - Self(GGLWESwitchingKeyPrepared::alloc(module, infos)) - } - - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self - where - Module<B>: VmpPMatAlloc<B>, - { - Self(GGLWESwitchingKeyPrepared::alloc_with( - module, - base2k, - k, - rank_in, - Rank(1), - dnum, - Dsize(1), - )) - } - - pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VmpPMatAllocBytes, - { - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is not supported for GLWEToLWESwitchingKeyPrepared" - ); - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for GLWEToLWESwitchingKeyPrepared" - ); - GGLWESwitchingKeyPrepared::alloc_bytes(module, infos) - } - - pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize - where - Module<B>: VmpPMatAllocBytes, - { - GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rank_in, Rank(1), dnum, Dsize(1)) - } -} - -impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> -where - GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>, -{ - fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize { - GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos) - } -} - -impl<D: DataRef, B: Backend> PrepareAlloc<B, GLWEToLWESwitchingKeyPrepared<Vec<u8>, B>> for GLWEToLWEKey<D> -where - Module<B>: VmpPrepare<B> + VmpPMatAlloc<B>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> { - let mut ksk_prepared: GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> = GLWEToLWESwitchingKeyPrepared::alloc(module, self); - ksk_prepared.prepare(module, self, scratch); - ksk_prepared - } -} - -impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, GLWEToLWEKey<DR>> for GLWEToLWESwitchingKeyPrepared<DM, B> -where - Module<B>: VmpPrepare<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &GLWEToLWEKey<DR>, scratch: &mut Scratch<B>) { - self.0.prepare(module, &other.0, scratch); - } -}
@@ -0,0 +1,211 @@
+use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWEPrepared, GGLWEPreparedToMut, GGLWEPreparedToRef, GGLWEToRef, GLWEInfos, + GLWESwitchingKeyDegrees, GLWESwitchingKeyDegreesMut, LWEInfos, Rank, TorusPrecision, + prepared::{GLWESwitchingKeyPrepared, GLWESwitchingKeyPreparedFactory}, +}; + +#[derive(PartialEq, Eq)] +pub struct GLWEToLWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GLWESwitchingKeyPrepared<D, B>); + +impl<D: Data, B: Backend> LWEInfos for GLWEToLWESwitchingKeyPrepared<D, B> { + fn base2k(&self) -> Base2K { + self.0.base2k() + } + + fn k(&self) -> TorusPrecision { + self.0.k() + } + + fn n(&self) -> Degree { + self.0.n() + } + + fn size(&self) -> usize { + self.0.size() + } +} + +impl<D: Data, B: Backend> GLWEInfos for GLWEToLWESwitchingKeyPrepared<D, B> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data, B: Backend> GGLWEInfos for GLWEToLWESwitchingKeyPrepared<D, B> { + fn rank_in(&self) -> Rank { + self.0.rank_in() + } + + fn dsize(&self) -> Dsize { + self.0.dsize() + } + + fn rank_out(&self) -> Rank { + self.0.rank_out() + } + + fn dnum(&self) -> Dnum { + self.0.dnum() + } +} + +pub trait GLWEToLWESwitchingKeyPreparedFactory<B: Backend> +where + Self: GLWESwitchingKeyPreparedFactory<B>, +{ + fn alloc_glwe_to_lwe_switching_key_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + dnum: Dnum, + ) -> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> { + GLWEToLWESwitchingKeyPrepared(self.alloc_glwe_switching_key_prepared(base2k, k, rank_in, Rank(1), dnum, Dsize(1))) + } + fn alloc_glwe_to_lwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> + where + A: GGLWEInfos, + { + debug_assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is not supported for GLWEToLWESwitchingKeyPrepared" + ); + debug_assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for GLWEToLWESwitchingKeyPrepared" + ); + self.alloc_glwe_to_lwe_switching_key_prepared(infos.base2k(), infos.k(), infos.rank_in(), infos.dnum()) + } + + fn bytes_of_glwe_to_lwe_switching_key_prepared(&self, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize { + self.bytes_of_glwe_switching_key_prepared(base2k, k, rank_in, Rank(1), dnum, Dsize(1)) + } + + fn bytes_of_glwe_to_lwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + debug_assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is not supported for GLWEToLWESwitchingKeyPrepared" + ); + debug_assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for GLWEToLWESwitchingKeyPrepared" + ); + self.bytes_of_glwe_to_lwe_switching_key_prepared(infos.base2k(), infos.k(), infos.rank_in(), infos.dnum()) + } + + fn prepare_glwe_to_lwe_switching_key_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + self.prepare_glwe_switching_key_tmp_bytes(infos) + } + + fn prepare_glwe_to_lwe_switching_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>) + where + R: GGLWEPreparedToMut<B> + GLWESwitchingKeyDegreesMut, + O: GGLWEToRef + GLWESwitchingKeyDegrees, + { + self.prepare_glwe_switching(res, other, scratch); + } +} + +impl<B: Backend> GLWEToLWESwitchingKeyPreparedFactory<B> for Module<B> where Self: GLWESwitchingKeyPreparedFactory<B> {} + +impl<B: Backend> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GGLWEInfos, + M: GLWEToLWESwitchingKeyPreparedFactory<B>, + { + module.alloc_glwe_to_lwe_switching_key_prepared_from_infos(infos) + } + + pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> Self + where + M: GLWEToLWESwitchingKeyPreparedFactory<B>, + { + module.alloc_glwe_to_lwe_switching_key_prepared(base2k, k, rank_in, dnum) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: GLWEToLWESwitchingKeyPreparedFactory<B>, + { + module.bytes_of_glwe_to_lwe_switching_key_prepared_from_infos(infos) + } + + pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum) -> usize + where + M: GLWEToLWESwitchingKeyPreparedFactory<B>, + { + module.bytes_of_glwe_to_lwe_switching_key_prepared(base2k, k, rank_in, dnum) + } +} + +impl<B: Backend> GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> { + pub fn prepare_tmp_bytes<A, M>(&self, module: &M, infos: &A) + where + A: GGLWEInfos, + M: GLWEToLWESwitchingKeyPreparedFactory<B>, + { + module.prepare_glwe_to_lwe_switching_key_tmp_bytes(infos); + } +} + +impl<D: DataMut, B: Backend> GLWEToLWESwitchingKeyPrepared<D, B> { + pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>) + where + O: GGLWEToRef + GLWESwitchingKeyDegrees, + M: GLWEToLWESwitchingKeyPreparedFactory<B>, + { + module.prepare_glwe_to_lwe_switching_key(self, other, scratch); + } +} + +impl<D: DataRef, B: Backend> GGLWEPreparedToRef<B> for GLWEToLWESwitchingKeyPrepared<D, B> +where + GLWESwitchingKeyPrepared<D, B>: GGLWEPreparedToRef<B>, +{ + fn to_ref(&self) -> GGLWEPrepared<&[u8], B> { + self.0.to_ref() + } +} + +impl<D: DataMut, B: Backend> GGLWEPreparedToMut<B> for GLWEToLWESwitchingKeyPrepared<D, B> +where + GLWESwitchingKeyPrepared<D, B>: GGLWEPreparedToRef<B>, +{ + fn to_mut(&mut self) -> GGLWEPrepared<&mut [u8], B> { + self.0.to_mut() + } +} + +impl<D: DataMut, B: Backend> GLWESwitchingKeyDegreesMut for GLWEToLWESwitchingKeyPrepared<D, B> { + fn input_degree(&mut self) -> &mut Degree { + &mut self.0.input_degree + } + + fn output_degree(&mut self) -> &mut Degree { + &mut self.0.output_degree + } +} + +impl<D: DataRef, B: Backend> GLWESwitchingKeyDegrees for GLWEToLWESwitchingKeyPrepared<D, B> { + fn input_degree(&self) -> &Degree { + &self.0.input_degree + } + + fn output_degree(&self) -> &Degree { + &self.0.output_degree + } +}
@@ -1,152 +0,0 @@
-use poulpy_hal::{ - api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWESwitchingKey, Rank, TorusPrecision, - prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace}, -}; - -#[derive(PartialEq, Eq)] -pub struct LWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GGLWESwitchingKeyPrepared<D, B>); - -impl<D: Data, B: Backend> LWEInfos for LWESwitchingKeyPrepared<D, B> { - fn base2k(&self) -> Base2K { - self.0.base2k() - } - - fn k(&self) -> TorusPrecision { - self.0.k() - } - - fn n(&self) -> Degree { - self.0.n() - } - - fn size(&self) -> usize { - self.0.size() - } -} -impl<D: Data, B: Backend> GLWEInfos for LWESwitchingKeyPrepared<D, B> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data, B: Backend> GGLWEInfos for LWESwitchingKeyPrepared<D, B> { - fn dsize(&self) -> Dsize { - self.0.dsize() - } - - fn rank_in(&self) -> Rank { - self.0.rank_in() - } - - fn rank_out(&self) -> Rank { - self.0.rank_out() - } - - fn dnum(&self) -> Dnum { - self.0.dnum() - } -} - -impl<B: Backend> LWESwitchingKeyPrepared<Vec<u8>, B> { - pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: GGLWEInfos, - Module<B>: VmpPMatAlloc<B>, - { - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for LWESwitchingKey" - ); - debug_assert_eq!( - infos.rank_in().0, - 1, - "rank_in > 1 is not supported for LWESwitchingKey" - ); - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is not supported for LWESwitchingKey" - ); - Self(GGLWESwitchingKeyPrepared::alloc(module, infos)) - } - - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self - where - Module<B>: VmpPMatAlloc<B>, - { - Self(GGLWESwitchingKeyPrepared::alloc_with( - module, - base2k, - k, - Rank(1), - Rank(1), - dnum, - Dsize(1), - )) - } - - pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VmpPMatAllocBytes, - { - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for LWESwitchingKey" - ); - debug_assert_eq!( - infos.rank_in().0, - 1, - "rank_in > 1 is not supported for LWESwitchingKey" - ); - debug_assert_eq!( - infos.rank_out().0, - 1, - "rank_out > 1 is not supported for LWESwitchingKey" - ); - GGLWESwitchingKeyPrepared::alloc_bytes(module, infos) - } - - pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize - where - Module<B>: VmpPMatAllocBytes, - { - GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, Rank(1), Rank(1), dnum, Dsize(1)) - } -} - -impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for LWESwitchingKeyPrepared<Vec<u8>, B> -where - GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>, -{ - fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize { - GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos) - } -} - -impl<D: DataRef, B: Backend> PrepareAlloc<B, LWESwitchingKeyPrepared<Vec<u8>, B>> for LWESwitchingKey<D> -where - Module<B>: VmpPrepare<B> + VmpPMatAlloc<B>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> LWESwitchingKeyPrepared<Vec<u8>, B> { - let mut ksk_prepared: LWESwitchingKeyPrepared<Vec<u8>, B> = LWESwitchingKeyPrepared::alloc(module, self); - ksk_prepared.prepare(module, self, scratch); - ksk_prepared - } -} - -impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, LWESwitchingKey<DR>> for LWESwitchingKeyPrepared<DM, B> -where - Module<B>: VmpPrepare<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &LWESwitchingKey<DR>, scratch: &mut Scratch<B>) { - self.0.prepare(module, &other.0, scratch); - } -}
@@ -0,0 +1,209 @@
+use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWEPrepared, GGLWEPreparedToMut, GGLWEPreparedToRef, GGLWEToRef, GLWEInfos, + GLWESwitchingKeyDegrees, GLWESwitchingKeyDegreesMut, LWEInfos, Rank, TorusPrecision, + prepared::{GLWESwitchingKeyPrepared, GLWESwitchingKeyPreparedFactory}, +}; + +#[derive(PartialEq, Eq)] +pub struct LWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GLWESwitchingKeyPrepared<D, B>); + +impl<D: Data, B: Backend> LWEInfos for LWESwitchingKeyPrepared<D, B> { + fn base2k(&self) -> Base2K { + self.0.base2k() + } + + fn k(&self) -> TorusPrecision { + self.0.k() + } + + fn n(&self) -> Degree { + self.0.n() + } + + fn size(&self) -> usize { + self.0.size() + } +} +impl<D: Data, B: Backend> GLWEInfos for LWESwitchingKeyPrepared<D, B> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data, B: Backend> GGLWEInfos for LWESwitchingKeyPrepared<D, B> { + fn dsize(&self) -> Dsize { + self.0.dsize() + } + + fn rank_in(&self) -> Rank { + self.0.rank_in() + } + + fn rank_out(&self) -> Rank { + self.0.rank_out() + } + + fn dnum(&self) -> Dnum { + self.0.dnum() + } +} + +pub trait LWESwitchingKeyPreparedFactory<B: Backend> +where + Self: GLWESwitchingKeyPreparedFactory<B>, +{ + fn alloc_lwe_switching_key_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + dnum: Dnum, + ) -> LWESwitchingKeyPrepared<Vec<u8>, B> { + LWESwitchingKeyPrepared(self.alloc_glwe_switching_key_prepared(base2k, k, Rank(1), Rank(1), dnum, Dsize(1))) + } + + fn alloc_lwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> LWESwitchingKeyPrepared<Vec<u8>, B> + where + A: GGLWEInfos, + { + debug_assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for LWESwitchingKey" + ); + debug_assert_eq!( + infos.rank_in().0, + 1, + "rank_in > 1 is not supported for LWESwitchingKey" + ); + debug_assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is not supported for LWESwitchingKey" + ); + self.alloc_lwe_switching_key_prepared(infos.base2k(), infos.k(), infos.dnum()) + } + + fn bytes_of_lwe_switching_key_prepared(&self, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize { + self.bytes_of_glwe_switching_key_prepared(base2k, k, Rank(1), Rank(1), dnum, Dsize(1)) + } + + fn bytes_of_lwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + debug_assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for LWESwitchingKey" + ); + debug_assert_eq!( + infos.rank_in().0, + 1, + "rank_in > 1 is not supported for LWESwitchingKey" + ); + debug_assert_eq!( + infos.rank_out().0, + 1, + "rank_out > 1 is not supported for LWESwitchingKey" + ); + self.bytes_of_lwe_switching_key_prepared(infos.base2k(), infos.k(), infos.dnum()) + } + + fn prepare_lwe_switching_key_tmp_bytes<A>(&self, infos: &A) + where + A: GGLWEInfos, + { + self.prepare_glwe_switching_key_tmp_bytes(infos); + } + fn prepare_lwe_switching_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>) + where + R: GGLWEPreparedToMut<B> + GLWESwitchingKeyDegreesMut, + O: GGLWEToRef + GLWESwitchingKeyDegrees, + { + self.prepare_glwe_switching(res, other, scratch); + } +} + +impl<B: Backend> LWESwitchingKeyPreparedFactory<B> for Module<B> where Self: GLWESwitchingKeyPreparedFactory<B> {} + +impl<B: Backend> LWESwitchingKeyPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GGLWEInfos, + M: LWESwitchingKeyPreparedFactory<B>, + { + module.alloc_lwe_switching_key_prepared_from_infos(infos) + } + + pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self + where + M: LWESwitchingKeyPreparedFactory<B>, + { + module.alloc_lwe_switching_key_prepared(base2k, k, dnum) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: LWESwitchingKeyPreparedFactory<B>, + { + module.bytes_of_lwe_switching_key_prepared_from_infos(infos) + } + + pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize + where + M: LWESwitchingKeyPreparedFactory<B>, + { + module.bytes_of_lwe_switching_key_prepared(base2k, k, dnum) + } +} + +impl<B: Backend> LWESwitchingKeyPrepared<Vec<u8>, B> { + pub fn prepare_tmp_bytes<A, M>(&self, module: &M, infos: &A) + where + A: GGLWEInfos, + M: LWESwitchingKeyPreparedFactory<B>, + { + module.prepare_lwe_switching_key_tmp_bytes(infos); + } +} + +impl<D: DataMut, B: Backend> LWESwitchingKeyPrepared<D, B> { + pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>) + where + O: GGLWEToRef + GLWESwitchingKeyDegrees, + M: LWESwitchingKeyPreparedFactory<B>, + { + module.prepare_lwe_switching_key(self, other, scratch); + } +} + +impl<D: DataRef, B: Backend> GGLWEPreparedToRef<B> for LWESwitchingKeyPrepared<D, B> +where + GGLWEPrepared<D, B>: GGLWEPreparedToRef<B>, +{ + fn to_ref(&self) -> GGLWEPrepared<&[u8], B> { + self.0.to_ref() + } +} + +impl<D: DataMut, B: Backend> GGLWEPreparedToMut<B> for LWESwitchingKeyPrepared<D, B> +where + GGLWEPrepared<D, B>: GGLWEPreparedToMut<B>, +{ + fn to_mut(&mut self) -> GGLWEPrepared<&mut [u8], B> { + self.0.to_mut() + } +} + +impl<D: DataMut, B: Backend> GLWESwitchingKeyDegreesMut for LWESwitchingKeyPrepared<D, B> { + fn input_degree(&mut self) -> &mut Degree { + &mut self.0.input_degree + } + + fn output_degree(&mut self) -> &mut Degree { + &mut self.0.output_degree + } +}
@@ -1,144 +0,0 @@
-use poulpy_hal::{ - api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare}, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, -}; - -use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, LWEToGLWESwitchingKey, Rank, TorusPrecision, - prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc, PrepareScratchSpace}, -}; - -/// A special [GLWESwitchingKey] required to for the conversion from [LWECiphertext] to [GLWECiphertext]. -#[derive(PartialEq, Eq)] -pub struct LWEToGLWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GGLWESwitchingKeyPrepared<D, B>); - -impl<D: Data, B: Backend> LWEInfos for LWEToGLWESwitchingKeyPrepared<D, B> { - fn base2k(&self) -> Base2K { - self.0.base2k() - } - - fn k(&self) -> TorusPrecision { - self.0.k() - } - - fn n(&self) -> Degree { - self.0.n() - } - - fn size(&self) -> usize { - self.0.size() - } -} - -impl<D: Data, B: Backend> GLWEInfos for LWEToGLWESwitchingKeyPrepared<D, B> { - fn rank(&self) -> Rank { - self.rank_out() - } -} - -impl<D: Data, B: Backend> GGLWEInfos for LWEToGLWESwitchingKeyPrepared<D, B> { - fn dsize(&self) -> Dsize { - self.0.dsize() - } - - fn rank_in(&self) -> Rank { - self.0.rank_in() - } - - fn rank_out(&self) -> Rank { - self.0.rank_out() - } - - fn dnum(&self) -> Dnum { - self.0.dnum() - } -} - -impl<B: Backend> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> { - pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: GGLWEInfos, - Module<B>: VmpPMatAlloc<B>, - { - debug_assert_eq!( - infos.rank_in().0, - 1, - "rank_in > 1 is not supported for LWEToGLWESwitchingKey" - ); - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for LWEToGLWESwitchingKey" - ); - Self(GGLWESwitchingKeyPrepared::alloc(module, infos)) - } - - pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self - where - Module<B>: VmpPMatAlloc<B>, - { - Self(GGLWESwitchingKeyPrepared::alloc_with( - module, - base2k, - k, - Rank(1), - rank_out, - dnum, - Dsize(1), - )) - } - - pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize - where - A: GGLWEInfos, - Module<B>: VmpPMatAllocBytes, - { - debug_assert_eq!( - infos.rank_in().0, - 1, - "rank_in > 1 is not supported for LWEToGLWESwitchingKey" - ); - debug_assert_eq!( - infos.dsize().0, - 1, - "dsize > 1 is not supported for LWEToGLWESwitchingKey" - ); - GGLWESwitchingKeyPrepared::alloc_bytes(module, infos) - } - - pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, rank_out: Rank) -> usize - where - Module<B>: VmpPMatAllocBytes, - { - GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, Rank(1), rank_out, dnum, Dsize(1)) - } -} - -impl<B: Backend, A: GGLWEInfos> PrepareScratchSpace<B, A> for LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> -where - GGLWESwitchingKeyPrepared<Vec<u8>, B>: PrepareScratchSpace<B, A>, -{ - fn prepare_scratch_space(module: &Module<B>, infos: &A) -> usize { - GGLWESwitchingKeyPrepared::prepare_scratch_space(module, infos) - } -} - -impl<D: DataRef, B: Backend> PrepareAlloc<B, LWEToGLWESwitchingKeyPrepared<Vec<u8>, B>> for LWEToGLWESwitchingKey<D> -where - Module<B>: VmpPrepare<B> + VmpPMatAlloc<B>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> { - let mut ksk_prepared: LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> = LWEToGLWESwitchingKeyPrepared::alloc(module, self); - ksk_prepared.prepare(module, self, scratch); - ksk_prepared - } -} - -impl<DM: DataMut, DR: DataRef, B: Backend> Prepare<B, LWEToGLWESwitchingKey<DR>> for LWEToGLWESwitchingKeyPrepared<DM, B> -where - Module<B>: VmpPrepare<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &LWEToGLWESwitchingKey<DR>, scratch: &mut Scratch<B>) { - self.0.prepare(module, &other.0, scratch); - } -}
@@ -0,0 +1,208 @@
+use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}; + +use crate::layouts::{ + Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWEPrepared, GGLWEPreparedToMut, GGLWEPreparedToRef, GGLWEToRef, GLWEInfos, + GLWESwitchingKeyDegrees, GLWESwitchingKeyDegreesMut, LWEInfos, Rank, TorusPrecision, + prepared::{GLWESwitchingKeyPrepared, GLWESwitchingKeyPreparedFactory}, +}; + +/// A special [GLWESwitchingKey] required to for the conversion from [LWE] to [GLWE]. +#[derive(PartialEq, Eq)] +pub struct LWEToGLWESwitchingKeyPrepared<D: Data, B: Backend>(pub(crate) GLWESwitchingKeyPrepared<D, B>); + +impl<D: Data, B: Backend> LWEInfos for LWEToGLWESwitchingKeyPrepared<D, B> { + fn base2k(&self) -> Base2K { + self.0.base2k() + } + + fn k(&self) -> TorusPrecision { + self.0.k() + } + + fn n(&self) -> Degree { + self.0.n() + } + + fn size(&self) -> usize { + self.0.size() + } +} + +impl<D: Data, B: Backend> GLWEInfos for LWEToGLWESwitchingKeyPrepared<D, B> { + fn rank(&self) -> Rank { + self.rank_out() + } +} + +impl<D: Data, B: Backend> GGLWEInfos for LWEToGLWESwitchingKeyPrepared<D, B> { + fn dsize(&self) -> Dsize { + self.0.dsize() + } + + fn rank_in(&self) -> Rank { + self.0.rank_in() + } + + fn rank_out(&self) -> Rank { + self.0.rank_out() + } + + fn dnum(&self) -> Dnum { + self.0.dnum() + } +} + +pub trait LWEToGLWESwitchingKeyPreparedFactory<B: Backend> +where + Self: GLWESwitchingKeyPreparedFactory<B>, +{ + fn alloc_lwe_to_glwe_switching_key_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + rank_out: Rank, + dnum: Dnum, + ) -> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> { + LWEToGLWESwitchingKeyPrepared(self.alloc_glwe_switching_key_prepared(base2k, k, Rank(1), rank_out, dnum, Dsize(1))) + } + fn alloc_lwe_to_glwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> + where + A: GGLWEInfos, + { + debug_assert_eq!( + infos.rank_in().0, + 1, + "rank_in > 1 is not supported for LWEToGLWESwitchingKey" + ); + debug_assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for LWEToGLWESwitchingKey" + ); + self.alloc_lwe_to_glwe_switching_key_prepared(infos.base2k(), infos.k(), infos.rank_out(), infos.dnum()) + } + + fn bytes_of_lwe_to_glwe_switching_key_prepared( + &self, + base2k: Base2K, + k: TorusPrecision, + rank_out: Rank, + dnum: Dnum, + ) -> usize { + self.bytes_of_glwe_switching_key_prepared(base2k, k, Rank(1), rank_out, dnum, Dsize(1)) + } + + fn bytes_of_lwe_to_glwe_switching_key_prepared_from_infos<A>(&self, infos: &A) -> usize + where + A: GGLWEInfos, + { + debug_assert_eq!( + infos.rank_in().0, + 1, + "rank_in > 1 is not supported for LWEToGLWESwitchingKey" + ); + debug_assert_eq!( + infos.dsize().0, + 1, + "dsize > 1 is not supported for LWEToGLWESwitchingKey" + ); + self.bytes_of_lwe_to_glwe_switching_key_prepared(infos.base2k(), infos.k(), infos.rank_out(), infos.dnum()) + } + + fn prepare_lwe_to_glwe_switching_key_tmp_bytes<A>(&self, infos: &A) + where + A: GGLWEInfos, + { + self.prepare_glwe_switching_key_tmp_bytes(infos); + } + + fn prepare_lwe_to_glwe_switching_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>) + where + R: GGLWEPreparedToMut<B> + GLWESwitchingKeyDegreesMut, + O: GGLWEToRef + GLWESwitchingKeyDegrees, + { + self.prepare_glwe_switching(res, other, scratch); + } +} + +impl<B: Backend> LWEToGLWESwitchingKeyPreparedFactory<B> for Module<B> where Self: GLWESwitchingKeyPreparedFactory<B> {} + +impl<B: Backend> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self + where + A: GGLWEInfos, + M: LWEToGLWESwitchingKeyPreparedFactory<B>, + { + module.alloc_lwe_to_glwe_switching_key_prepared_from_infos(infos) + } + + pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self + where + M: LWEToGLWESwitchingKeyPreparedFactory<B>, + { + module.alloc_lwe_to_glwe_switching_key_prepared(base2k, k, rank_out, dnum) + } + + pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize + where + A: GGLWEInfos, + M: LWEToGLWESwitchingKeyPreparedFactory<B>, + { + module.bytes_of_lwe_to_glwe_switching_key_prepared_from_infos(infos) + } + + pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> usize + where + M: LWEToGLWESwitchingKeyPreparedFactory<B>, + { + module.bytes_of_lwe_to_glwe_switching_key_prepared(base2k, k, rank_out, dnum) + } +} + +impl<B: Backend> LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> { + pub fn prepare_tmp_bytes<A, M>(&self, module: &M, infos: &A) + where + A: GGLWEInfos, + M: LWEToGLWESwitchingKeyPreparedFactory<B>, + { + module.prepare_lwe_to_glwe_switching_key_tmp_bytes(infos); + } +} + +impl<D: DataMut, B: Backend> LWEToGLWESwitchingKeyPrepared<D, B> { + pub fn prepare<O, M>(&mut self, module: &M, other: &O, scratch: &mut Scratch<B>) + where + O: GGLWEToRef + GLWESwitchingKeyDegrees, + M: LWEToGLWESwitchingKeyPreparedFactory<B>, + { + module.prepare_lwe_to_glwe_switching_key(self, other, scratch); + } +} + +impl<D: DataRef, B: Backend> GGLWEPreparedToRef<B> for LWEToGLWESwitchingKeyPrepared<D, B> +where + GLWESwitchingKeyPrepared<D, B>: GGLWEPreparedToRef<B>, +{ + fn to_ref(&self) -> GGLWEPrepared<&[u8], B> { + self.0.to_ref() + } +} + +impl<D: DataMut, B: Backend> GGLWEPreparedToMut<B> for LWEToGLWESwitchingKeyPrepared<D, B> +where + GLWESwitchingKeyPrepared<D, B>: GGLWEPreparedToMut<B>, +{ + fn to_mut(&mut self) -> GGLWEPrepared<&mut [u8], B> { + self.0.to_mut() + } +} + +impl<D: DataMut, B: Backend> GLWESwitchingKeyDegreesMut for LWEToGLWESwitchingKeyPrepared<D, B> { + fn input_degree(&mut self) -> &mut Degree { + &mut self.0.input_degree + } + + fn output_degree(&mut self) -> &mut Degree { + &mut self.0.output_degree + } +}
@@ -1,34 +1,23 @@
-mod gglwe_atk; -mod gglwe_ct; -mod gglwe_ksk; -mod gglwe_tsk; -mod ggsw_ct; -mod glwe_pk; -mod glwe_sk; -mod glwe_to_lwe_ksk; -mod lwe_ksk; -mod lwe_to_glwe_ksk; +mod gglwe; +mod ggsw; +mod glwe; +mod glwe_automorphism_key; +mod glwe_public_key; +mod glwe_secret; +mod glwe_switching_key; +mod glwe_tensor_key; +mod glwe_to_lwe_switching_key; +mod lwe_switching_key; +mod lwe_to_glwe_switching_key; -pub use gglwe_atk::*; -pub use gglwe_ct::*; -pub use gglwe_ksk::*; -pub use gglwe_tsk::*; -pub use ggsw_ct::*; -pub use glwe_pk::*; -pub use glwe_sk::*; -pub use glwe_to_lwe_ksk::*; -pub use lwe_ksk::*; -pub use lwe_to_glwe_ksk::*; -use poulpy_hal::layouts::{Backend, Module, Scratch}; - -pub trait PrepareScratchSpace<B: Backend, T> { - fn prepare_scratch_space(module: &Module<B>, infos: &T) -> usize; -} - -pub trait PrepareAlloc<B: Backend, T> { - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> T; -} - -pub trait Prepare<B: Backend, T> { - fn prepare(&mut self, module: &Module<B>, other: &T, scratch: &mut Scratch<B>); -} +pub use gglwe::*; +pub use ggsw::*; +pub use glwe::*; +pub use glwe_automorphism_key::*; +pub use glwe_public_key::*; +pub use glwe_secret::*; +pub use glwe_switching_key::*; +pub use glwe_tensor_key::*; +pub use glwe_to_lwe_switching_key::*; +pub use lwe_switching_key::*; +pub use lwe_to_glwe_switching_key::*;
@@ -14,12 +14,18 @@ mod utils;
pub use operations::*; pub mod layouts; +pub use automorphism::*; +pub use conversion::*; +pub use decryption::*; pub use dist::*; +pub use encryption::*; pub use external_product::*; pub use glwe_packing::*; +pub use glwe_trace::*; +pub use keyswitching::*; +pub use noise::*; +pub use scratch::*; pub use encryption::SIGMA; - -pub use scratch::*; pub mod tests;
@@ -0,0 +1,76 @@
+use poulpy_hal::{ + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, ScratchTakeBasic, VecZnxFillUniform, VecZnxSubScalarInplace}, + layouts::{Backend, DataRef, Module, ScalarZnxToRef, Scratch, ScratchOwned, ZnxZero}, +}; + +use crate::decryption::GLWEDecrypt; +use crate::layouts::{GGLWE, GGLWEInfos, GGLWEToRef, GLWEPlaintext, LWEInfos, prepared::GLWESecretPreparedToRef}; + +impl<D: DataRef> GGLWE<D> { + pub fn assert_noise<M, S, P, BE: Backend>(&self, module: &M, sk_prepared: &S, pt_want: &P, max_noise: f64) + where + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + M: GGLWENoise<BE>, + Scratch<BE>: ScratchTakeBasic, + { + module.gglwe_assert_noise(self, sk_prepared, pt_want, max_noise); + } +} + +pub trait GGLWENoise<BE: Backend> { + fn gglwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64) + where + R: GGLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + Scratch<BE>: ScratchTakeBasic; +} + +impl<BE: Backend> GGLWENoise<BE> for Module<BE> +where + Module<BE>: GLWEDecrypt<BE> + VecZnxFillUniform + VecZnxSubScalarInplace, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeBasic, +{ + fn gglwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64) + where + R: GGLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeBasic, + { + let res: &GGLWE<&[u8]> = &res.to_ref(); + + let dsize: usize = res.dsize().into(); + let base2k: usize = res.base2k().into(); + + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res)); + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(res); + + (0..res.rank_in().into()).for_each(|col_i| { + (0..res.dnum().into()).for_each(|row_i| { + self.glwe_decrypt( + &res.at(row_i, col_i), + &mut pt, + sk_prepared, + scratch.borrow(), + ); + + self.vec_znx_sub_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, col_i); + + let noise_have: f64 = pt.data.std(base2k, 0).log2(); + + // println!("noise_have: {noise_have}"); + + assert!( + noise_have <= max_noise, + "noise_have: {noise_have} > max_noise: {max_noise}" + ); + + pt.data.zero(); + }); + }); + } +}
@@ -1,61 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, - VecZnxNormalizeTmpBytes, VecZnxSubScalarInplace, - }, - layouts::{Backend, DataRef, Module, ScalarZnx, ScratchOwned, ZnxZero}, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl}, -}; - -use crate::layouts::{GGLWECiphertext, GGLWEInfos, GLWECiphertext, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}; - -impl<D: DataRef> GGLWECiphertext<D> { - pub fn assert_noise<B, DataSk, DataWant>( - &self, - module: &Module<B>, - sk: &GLWESecretPrepared<DataSk, B>, - pt_want: &ScalarZnx<DataWant>, - max_noise: f64, - ) where - DataSk: DataRef, - DataWant: DataRef, - Module<B>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxSubScalarInplace, - B: Backend + TakeVecZnxDftImpl<B> + TakeVecZnxBigImpl<B> + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, - { - let dsize: usize = self.dsize().into(); - let base2k: usize = self.base2k().into(); - - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWECiphertext::decrypt_scratch_space(module, self)); - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); - - (0..self.rank_in().into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_i| { - self.at(row_i, col_i) - .decrypt(module, &mut pt, sk, scratch.borrow()); - - module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, col_i); - - let noise_have: f64 = pt.data.std(base2k, 0).log2(); - - println!("noise_have: {noise_have}"); - - assert!( - noise_have <= max_noise, - "noise_have: {noise_have} > max_noise: {max_noise}" - ); - - pt.data.zero(); - }); - }); - } -}
@@ -0,0 +1,173 @@
+use poulpy_hal::{ + api::{ + ScratchOwnedAlloc, ScratchOwnedBorrow, ScratchTakeBasic, SvpApplyDftToDftInplace, VecZnxAddScalarInplace, VecZnxBigAlloc, + VecZnxBigNormalize, VecZnxDftAlloc, VecZnxDftApply, VecZnxIdftApplyTmpA, VecZnxNormalizeTmpBytes, VecZnxSubInplace, + }, + layouts::{Backend, DataRef, Module, ScalarZnxToRef, Scratch, ScratchOwned, VecZnxBig, VecZnxDft, ZnxZero}, +}; + +use crate::decryption::GLWEDecrypt; +use crate::layouts::prepared::GLWESecretPreparedToRef; +use crate::layouts::{GGSW, GGSWInfos, GGSWToRef, GLWEInfos, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}; + +impl<D: DataRef> GGSW<D> { + pub fn assert_noise<M, BE: Backend, P, S, F>(&self, module: &M, sk_prepared: &S, pt_want: &P, max_noise: F) + where + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + M: GGSWNoise<BE>, + F: Fn(usize) -> f64, + { + module.ggsw_assert_noise(self, sk_prepared, pt_want, max_noise); + } + + pub fn print_noise<M, BE: Backend, P, S>(&self, module: &M, sk_prepared: &S, pt_want: &P) + where + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + M: GGSWNoise<BE>, + { + module.ggsw_print_noise(self, sk_prepared, pt_want); + } +} + +pub trait GGSWNoise<BE: Backend> { + fn ggsw_assert_noise<R, S, P, F>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: F) + where + R: GGSWToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + F: Fn(usize) -> f64; + + fn ggsw_print_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P) + where + R: GGSWToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef; +} + +impl<BE: Backend> GGSWNoise<BE> for Module<BE> +where + Module<BE>: GLWEDecrypt<BE> + + VecZnxDftAlloc<BE> + + VecZnxBigAlloc<BE> + + VecZnxAddScalarInplace + + VecZnxIdftApplyTmpA<BE> + + VecZnxSubInplace, + Scratch<BE>: ScratchTakeBasic, + ScratchOwned<BE>: ScratchOwnedBorrow<BE> + ScratchOwnedAlloc<BE>, +{ + fn ggsw_assert_noise<R, S, P, F>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: F) + where + R: GGSWToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + F: Fn(usize) -> f64, + { + let res: &GGSW<&[u8]> = &res.to_ref(); + let sk_prepared: &GLWESecretPrepared<&[u8], BE> = &sk_prepared.to_ref(); + + let base2k: usize = res.base2k().into(); + let dsize: usize = res.dsize().into(); + + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(res); + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(res); + let mut pt_dft: VecZnxDft<Vec<u8>, BE> = self.vec_znx_dft_alloc(1, res.size()); + let mut pt_big: VecZnxBig<Vec<u8>, BE> = self.vec_znx_big_alloc(1, res.size()); + + let mut scratch: ScratchOwned<BE> = + ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res) | self.vec_znx_normalize_tmp_bytes()); + + (0..(res.rank() + 1).into()).for_each(|col_j| { + (0..res.dnum().into()).for_each(|row_i| { + self.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0); + + // mul with sk[col_j-1] + if col_j > 0 { + self.vec_znx_dft_apply(1, 0, &mut pt_dft, 0, &pt.data, 0); + self.svp_apply_dft_to_dft_inplace(&mut pt_dft, 0, &sk_prepared.data, col_j - 1); + self.vec_znx_idft_apply_tmpa(&mut pt_big, 0, &mut pt_dft, 0); + self.vec_znx_big_normalize( + base2k, + &mut pt.data, + 0, + base2k, + &pt_big, + 0, + scratch.borrow(), + ); + } + + self.glwe_decrypt( + &res.at(row_i, col_j), + &mut pt_have, + sk_prepared, + scratch.borrow(), + ); + + self.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0); + + let std_pt: f64 = pt_have.data.std(base2k, 0).log2(); + let noise: f64 = max_noise(col_j); + assert!(std_pt <= noise, "{std_pt} > {noise}"); + + pt.data.zero(); + }); + }); + } + + fn ggsw_print_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P) + where + R: GGSWToRef, + S: GLWESecretPreparedToRef<BE>, + P: ScalarZnxToRef, + { + let res: &GGSW<&[u8]> = &res.to_ref(); + let sk_prepared: &GLWESecretPrepared<&[u8], BE> = &sk_prepared.to_ref(); + + let base2k: usize = res.base2k().into(); + let dsize: usize = res.dsize().into(); + + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(res); + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(res); + let mut pt_dft: VecZnxDft<Vec<u8>, BE> = self.vec_znx_dft_alloc(1, res.size()); + let mut pt_big: VecZnxBig<Vec<u8>, BE> = self.vec_znx_big_alloc(1, res.size()); + + let mut scratch: ScratchOwned<BE> = + ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res) | self.vec_znx_normalize_tmp_bytes()); + + for col_j in 0..(res.rank() + 1).into() { + for row_i in 0..res.dnum().into() { + self.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0); + + // mul with sk[col_j-1] + if col_j > 0 { + self.vec_znx_dft_apply(1, 0, &mut pt_dft, 0, &pt.data, 0); + self.svp_apply_dft_to_dft_inplace(&mut pt_dft, 0, &sk_prepared.data, col_j - 1); + self.vec_znx_idft_apply_tmpa(&mut pt_big, 0, &mut pt_dft, 0); + self.vec_znx_big_normalize( + base2k, + &mut pt.data, + 0, + base2k, + &pt_big, + 0, + scratch.borrow(), + ); + } + + self.glwe_decrypt( + &res.at(row_i, col_j), + &mut pt_have, + sk_prepared, + scratch.borrow(), + ); + self.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0); + + let std_pt: f64 = pt_have.data.std(base2k, 0).log2(); + println!("col: {col_j} row: {row_i}: {std_pt}"); + pt.data.zero(); + } + } + } +}
@@ -1,158 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, VecZnxAddScalarInplace, VecZnxBigAddInplace, - VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, - VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, - VecZnxNormalizeTmpBytes, VecZnxSubInplace, - }, - layouts::{Backend, DataRef, Module, ScalarZnx, ScratchOwned, VecZnxBig, VecZnxDft, ZnxZero}, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl}, -}; - -use crate::layouts::{ - GGSWCiphertext, GGSWInfos, GLWECiphertext, GLWEInfos, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared, -}; - -impl<D: DataRef> GGSWCiphertext<D> { - pub fn assert_noise<B, DataSk, DataScalar, F>( - &self, - module: &Module<B>, - sk_prepared: &GLWESecretPrepared<DataSk, B>, - pt_want: &ScalarZnx<DataScalar>, - max_noise: F, - ) where - DataSk: DataRef, - DataScalar: DataRef, - Module<B>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<B> - + VecZnxAddScalarInplace - + VecZnxSubInplace, - B: Backend + TakeVecZnxDftImpl<B> + TakeVecZnxBigImpl<B> + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, - F: Fn(usize) -> f64, - { - let base2k: usize = self.base2k().into(); - let dsize: usize = self.dsize().into(); - - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); - let mut pt_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(1, self.size()); - let mut pt_big: VecZnxBig<Vec<u8>, B> = module.vec_znx_big_alloc(1, self.size()); - - let mut scratch: ScratchOwned<B> = - ScratchOwned::alloc(GLWECiphertext::decrypt_scratch_space(module, self) | module.vec_znx_normalize_tmp_bytes()); - - (0..(self.rank() + 1).into()).for_each(|col_j| { - (0..self.dnum().into()).for_each(|row_i| { - module.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0); - - // mul with sk[col_j-1] - if col_j > 0 { - module.vec_znx_dft_apply(1, 0, &mut pt_dft, 0, &pt.data, 0); - module.svp_apply_dft_to_dft_inplace(&mut pt_dft, 0, &sk_prepared.data, col_j - 1); - module.vec_znx_idft_apply_tmpa(&mut pt_big, 0, &mut pt_dft, 0); - module.vec_znx_big_normalize( - base2k, - &mut pt.data, - 0, - base2k, - &pt_big, - 0, - scratch.borrow(), - ); - } - - self.at(row_i, col_j) - .decrypt(module, &mut pt_have, sk_prepared, scratch.borrow()); - - module.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0); - - let std_pt: f64 = pt_have.data.std(base2k, 0).log2(); - let noise: f64 = max_noise(col_j); - assert!(std_pt <= noise, "{std_pt} > {noise}"); - - pt.data.zero(); - }); - }); - } -} - -impl<D: DataRef> GGSWCiphertext<D> { - pub fn print_noise<B, DataSk, DataScalar>( - &self, - module: &Module<B>, - sk_prepared: &GLWESecretPrepared<DataSk, B>, - pt_want: &ScalarZnx<DataScalar>, - ) where - DataSk: DataRef, - DataScalar: DataRef, - Module<B>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<B> - + VecZnxAddScalarInplace - + VecZnxSubInplace, - B: Backend + TakeVecZnxDftImpl<B> + TakeVecZnxBigImpl<B> + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, - { - let base2k: usize = self.base2k().into(); - let dsize: usize = self.dsize().into(); - - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); - let mut pt_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(1, self.size()); - let mut pt_big: VecZnxBig<Vec<u8>, B> = module.vec_znx_big_alloc(1, self.size()); - - let mut scratch: ScratchOwned<B> = - ScratchOwned::alloc(GLWECiphertext::decrypt_scratch_space(module, self) | module.vec_znx_normalize_tmp_bytes()); - - (0..(self.rank() + 1).into()).for_each(|col_j| { - (0..self.dnum().into()).for_each(|row_i| { - module.vec_znx_add_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, 0); - - // mul with sk[col_j-1] - if col_j > 0 { - module.vec_znx_dft_apply(1, 0, &mut pt_dft, 0, &pt.data, 0); - module.svp_apply_dft_to_dft_inplace(&mut pt_dft, 0, &sk_prepared.data, col_j - 1); - module.vec_znx_idft_apply_tmpa(&mut pt_big, 0, &mut pt_dft, 0); - module.vec_znx_big_normalize( - base2k, - &mut pt.data, - 0, - base2k, - &pt_big, - 0, - scratch.borrow(), - ); - } - - self.at(row_i, col_j) - .decrypt(module, &mut pt_have, sk_prepared, scratch.borrow()); - module.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt.data, 0); - - let std_pt: f64 = pt_have.data.std(base2k, 0).log2(); - println!("col: {col_j} row: {row_i}: {std_pt}"); - pt.data.zero(); - // println!(">>>>>>>>>>>>>>>>"); - }); - }); - } -}
@@ -0,0 +1,80 @@
+use poulpy_hal::{ + api::{ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxNormalizeInplace, VecZnxSubInplace}, + layouts::{Backend, DataRef, Module, Scratch, ScratchOwned}, +}; + +use crate::{ + ScratchTakeCore, + decryption::GLWEDecrypt, + layouts::{GLWE, GLWEPlaintext, GLWEPlaintextToRef, GLWEToRef, LWEInfos, prepared::GLWESecretPreparedToRef}, +}; + +impl<D: DataRef> GLWE<D> { + pub fn noise<M, S, P, BE: Backend>(&self, module: &M, sk_prepared: &S, pt_want: &P, scratch: &mut Scratch<BE>) -> f64 + where + M: GLWENoise<BE>, + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef, + { + module.glwe_noise(self, sk_prepared, pt_want, scratch) + } + + pub fn assert_noise<M, BE: Backend, S, P>(&self, module: &M, sk_prepared: &S, pt_want: &P, max_noise: f64) + where + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef, + M: GLWENoise<BE>, + { + module.glwe_assert_noise(self, sk_prepared, pt_want, max_noise); + } +} + +pub trait GLWENoise<BE: Backend> { + fn glwe_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, scratch: &mut Scratch<BE>) -> f64 + where + R: GLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef; + + fn glwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64) + where + R: GLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef; +} + +impl<BE: Backend> GLWENoise<BE> for Module<BE> +where + Module<BE>: GLWEDecrypt<BE> + VecZnxSubInplace + VecZnxNormalizeInplace<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn glwe_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, scratch: &mut Scratch<BE>) -> f64 + where + R: GLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef, + { + let res_ref: &GLWE<&[u8]> = &res.to_ref(); + + let pt_want: &GLWEPlaintext<&[u8]> = &pt_want.to_ref(); + + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(res_ref); + self.glwe_decrypt(res, &mut pt_have, sk_prepared, scratch); + self.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt_want.data, 0); + self.vec_znx_normalize_inplace(res_ref.base2k().into(), &mut pt_have.data, 0, scratch); + pt_have.data.std(res_ref.base2k().into(), 0).log2() + } + + fn glwe_assert_noise<R, S, P>(&self, res: &R, sk_prepared: &S, pt_want: &P, max_noise: f64) + where + R: GLWEToRef, + S: GLWESecretPreparedToRef<BE>, + P: GLWEPlaintextToRef, + { + let res: &GLWE<&[u8]> = &res.to_ref(); + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(self.glwe_decrypt_tmp_bytes(res)); + let noise_have: f64 = self.glwe_noise(res, sk_prepared, pt_want, scratch.borrow()); + assert!(noise_have <= max_noise, "{noise_have} {max_noise}"); + } +}
@@ -1,68 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, TakeVecZnxBig, TakeVecZnxDft, VecZnxBigAddInplace, - VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxIdftApplyConsume, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSubInplace, - }, - layouts::{Backend, DataRef, Module, Scratch, ScratchOwned}, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl}, -}; - -use crate::layouts::{GLWECiphertext, GLWEPlaintext, LWEInfos, prepared::GLWESecretPrepared}; - -impl<D: DataRef> GLWECiphertext<D> { - pub fn noise<B, DataSk, DataPt>( - &self, - module: &Module<B>, - sk_prepared: &GLWESecretPrepared<DataSk, B>, - pt_want: &GLWEPlaintext<DataPt>, - scratch: &mut Scratch<B>, - ) -> f64 - where - DataSk: DataRef, - DataPt: DataRef, - B: Backend, - Module<B>: VecZnxDftApply<B> - + VecZnxSubInplace - + VecZnxNormalizeInplace<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + TakeVecZnxBig<B>, - { - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(self); - self.decrypt(module, &mut pt_have, sk_prepared, scratch); - module.vec_znx_sub_inplace(&mut pt_have.data, 0, &pt_want.data, 0); - module.vec_znx_normalize_inplace(self.base2k().into(), &mut pt_have.data, 0, scratch); - pt_have.data.std(self.base2k().into(), 0).log2() - } - - pub fn assert_noise<B, DataSk, DataPt>( - &self, - module: &Module<B>, - sk_prepared: &GLWESecretPrepared<DataSk, B>, - pt_want: &GLWEPlaintext<DataPt>, - max_noise: f64, - ) where - DataSk: DataRef, - DataPt: DataRef, - Module<B>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxSubInplace - + VecZnxNormalizeInplace<B>, - B: Backend + TakeVecZnxDftImpl<B> + TakeVecZnxBigImpl<B> + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, - { - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GLWECiphertext::decrypt_scratch_space(module, self)); - let noise_have: f64 = self.noise(module, sk_prepared, pt_want, scratch.borrow()); - assert!(noise_have <= max_noise, "{noise_have} {max_noise}"); - } -}
@@ -1,6 +1,10 @@
-mod gglwe_ct; -mod ggsw_ct; -mod glwe_ct; +mod gglwe; +mod ggsw; +mod glwe; + +pub use gglwe::*; +pub use ggsw::*; +pub use glwe::*; #[allow(clippy::too_many_arguments)] #[allow(dead_code)]
@@ -1,328 +1,364 @@
use poulpy_hal::{ api::{ - VecZnxAdd, VecZnxAddInplace, VecZnxCopy, VecZnxMulXpMinusOne, VecZnxMulXpMinusOneInplace, VecZnxNegateInplace, + ModuleN, VecZnxAdd, VecZnxAddInplace, VecZnxCopy, VecZnxMulXpMinusOne, VecZnxMulXpMinusOneInplace, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxRotate, VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSubNegateInplace, }, - layouts::{Backend, DataMut, Module, Scratch, VecZnx, ZnxZero}, + layouts::{Backend, Module, Scratch, VecZnx, ZnxZero}, }; -use crate::layouts::{ - GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, GLWEInfos, GLWELayoutSet, GLWEPlaintext, LWEInfos, TorusPrecision, +use crate::{ + ScratchTakeCore, + layouts::{GLWE, GLWEInfos, GLWEToMut, GLWEToRef, LWEInfos, SetGLWEInfos, TorusPrecision}, }; -impl<D> GLWEOperations for GLWEPlaintext<D> +pub trait GLWEAdd where - D: DataMut, - GLWEPlaintext<D>: GLWECiphertextToMut + GLWEInfos, + Self: ModuleN + VecZnxAdd + VecZnxCopy + VecZnxAddInplace, { -} - -impl<D: DataMut> GLWEOperations for GLWECiphertext<D> where GLWECiphertext<D>: GLWECiphertextToMut + GLWEInfos {} - -pub trait GLWEOperations: GLWECiphertextToMut + GLWEInfos + GLWELayoutSet + Sized { - fn add<A, B, BACKEND: Backend>(&mut self, module: &Module<BACKEND>, a: &A, b: &B) + fn glwe_add<R, A, B>(&self, res: &mut R, a: &A, b: &B) where - A: GLWECiphertextToRef + GLWEInfos, - B: GLWECiphertextToRef + GLWEInfos, - Module<BACKEND>: VecZnxAdd + VecZnxCopy, + R: GLWEToMut, + A: GLWEToRef, + B: GLWEToRef, { - #[cfg(debug_assertions)] - { - assert_eq!(a.n(), self.n()); - assert_eq!(b.n(), self.n()); - assert_eq!(a.base2k(), b.base2k()); - assert!(self.rank() >= a.rank().max(b.rank())); - } + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &mut GLWE<&[u8]> = &mut a.to_ref(); + let b: &GLWE<&[u8]> = &b.to_ref(); + + assert_eq!(a.n(), self.n() as u32); + assert_eq!(b.n(), self.n() as u32); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.base2k(), b.base2k()); + assert!(res.rank() >= a.rank().max(b.rank())); let min_col: usize = (a.rank().min(b.rank()) + 1).into(); let max_col: usize = (a.rank().max(b.rank() + 1)).into(); - let self_col: usize = (self.rank() + 1).into(); - - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); - let a_ref: &GLWECiphertext<&[u8]> = &a.to_ref(); - let b_ref: &GLWECiphertext<&[u8]> = &b.to_ref(); + let self_col: usize = (res.rank() + 1).into(); (0..min_col).for_each(|i| { - module.vec_znx_add(&mut self_mut.data, i, &a_ref.data, i, &b_ref.data, i); + self.vec_znx_add(res.data_mut(), i, a.data(), i, b.data(), i); }); if a.rank() > b.rank() { (min_col..max_col).for_each(|i| { - module.vec_znx_copy(&mut self_mut.data, i, &a_ref.data, i); + self.vec_znx_copy(res.data_mut(), i, a.data(), i); }); } else { (min_col..max_col).for_each(|i| { - module.vec_znx_copy(&mut self_mut.data, i, &b_ref.data, i); + self.vec_znx_copy(res.data_mut(), i, b.data(), i); }); } - let size: usize = self_mut.size(); + let size: usize = res.size(); (max_col..self_col).for_each(|i| { (0..size).for_each(|j| { - self_mut.data.zero_at(i, j); + res.data.zero_at(i, j); }); }); - self.set_basek(a.base2k()); - self.set_k(set_k_binary(self, a, b)); + res.set_base2k(a.base2k()); + res.set_k(set_k_binary(res, a, b)); } - fn add_inplace<A, BACKEND: Backend>(&mut self, module: &Module<BACKEND>, a: &A) + fn glwe_add_inplace<R, A>(&self, res: &mut R, a: &A) where - A: GLWECiphertextToRef + GLWEInfos, - Module<BACKEND>: VecZnxAddInplace, + R: GLWEToMut, + A: GLWEToRef, { - #[cfg(debug_assertions)] - { - assert_eq!(a.n(), self.n()); - assert_eq!(self.base2k(), a.base2k()); - assert!(self.rank() >= a.rank()) - } + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); - let a_ref: &GLWECiphertext<&[u8]> = &a.to_ref(); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.n(), self.n() as u32); + assert_eq!(res.base2k(), a.base2k()); + assert!(res.rank() >= a.rank()); (0..(a.rank() + 1).into()).for_each(|i| { - module.vec_znx_add_inplace(&mut self_mut.data, i, &a_ref.data, i); + self.vec_znx_add_inplace(res.data_mut(), i, a.data(), i); }); - self.set_k(set_k_unary(self, a)) + res.set_k(set_k_unary(res, a)) } +} - fn sub<A, B, BACKEND: Backend>(&mut self, module: &Module<BACKEND>, a: &A, b: &B) +impl<BE: Backend> GLWEAdd for Module<BE> where Self: ModuleN + VecZnxAdd + VecZnxCopy + VecZnxAddInplace {} + +impl<BE: Backend> GLWESub for Module<BE> where + Self: ModuleN + VecZnxSub + VecZnxCopy + VecZnxNegateInplace + VecZnxSubInplace + VecZnxSubNegateInplace +{ +} + +pub trait GLWESub +where + Self: ModuleN + VecZnxSub + VecZnxCopy + VecZnxNegateInplace + VecZnxSubInplace + VecZnxSubNegateInplace, +{ + fn glwe_sub<R, A, B>(&self, res: &mut R, a: &A, b: &B) where - A: GLWECiphertextToRef + GLWEInfos, - B: GLWECiphertextToRef + GLWEInfos, - Module<BACKEND>: VecZnxSub + VecZnxCopy + VecZnxNegateInplace, + R: GLWEToMut, + A: GLWEToRef, + B: GLWEToRef, { - #[cfg(debug_assertions)] - { - assert_eq!(a.n(), self.n()); - assert_eq!(b.n(), self.n()); - assert_eq!(a.base2k(), b.base2k()); - assert!(self.rank() >= a.rank().max(b.rank())); - } + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); + let b: &GLWE<&[u8]> = &b.to_ref(); + + assert_eq!(a.n(), self.n() as u32); + assert_eq!(b.n(), self.n() as u32); + assert_eq!(a.base2k(), b.base2k()); + assert!(res.rank() >= a.rank().max(b.rank())); let min_col: usize = (a.rank().min(b.rank()) + 1).into(); let max_col: usize = (a.rank().max(b.rank() + 1)).into(); - let self_col: usize = (self.rank() + 1).into(); - - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); - let a_ref: &GLWECiphertext<&[u8]> = &a.to_ref(); - let b_ref: &GLWECiphertext<&[u8]> = &b.to_ref(); + let self_col: usize = (res.rank() + 1).into(); (0..min_col).for_each(|i| { - module.vec_znx_sub(&mut self_mut.data, i, &a_ref.data, i, &b_ref.data, i); + self.vec_znx_sub(res.data_mut(), i, a.data(), i, b.data(), i); }); if a.rank() > b.rank() { (min_col..max_col).for_each(|i| { - module.vec_znx_copy(&mut self_mut.data, i, &a_ref.data, i); + self.vec_znx_copy(res.data_mut(), i, a.data(), i); }); } else { (min_col..max_col).for_each(|i| { - module.vec_znx_copy(&mut self_mut.data, i, &b_ref.data, i); - module.vec_znx_negate_inplace(&mut self_mut.data, i); + self.vec_znx_copy(res.data_mut(), i, b.data(), i); + self.vec_znx_negate_inplace(res.data_mut(), i); }); } - let size: usize = self_mut.size(); + let size: usize = res.size(); (max_col..self_col).for_each(|i| { (0..size).for_each(|j| { - self_mut.data.zero_at(i, j); + res.data.zero_at(i, j); }); }); - self.set_basek(a.base2k()); - self.set_k(set_k_binary(self, a, b)); + res.set_base2k(a.base2k()); + res.set_k(set_k_binary(res, a, b)); } - fn sub_inplace_ab<A, BACKEND: Backend>(&mut self, module: &Module<BACKEND>, a: &A) + fn glwe_sub_inplace<R, A>(&self, res: &mut R, a: &A) where - A: GLWECiphertextToRef + GLWEInfos, - Module<BACKEND>: VecZnxSubInplace, + R: GLWEToMut, + A: GLWEToRef, { - #[cfg(debug_assertions)] - { - assert_eq!(a.n(), self.n()); - assert_eq!(self.base2k(), a.base2k()); - assert!(self.rank() >= a.rank()) - } + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); - let a_ref: &GLWECiphertext<&[u8]> = &a.to_ref(); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.n(), self.n() as u32); + assert_eq!(res.base2k(), a.base2k()); + assert!(res.rank() >= a.rank()); (0..(a.rank() + 1).into()).for_each(|i| { - module.vec_znx_sub_inplace(&mut self_mut.data, i, &a_ref.data, i); + self.vec_znx_sub_inplace(res.data_mut(), i, a.data(), i); }); - self.set_k(set_k_unary(self, a)) + res.set_k(set_k_unary(res, a)) } - fn sub_inplace_ba<A, BACKEND: Backend>(&mut self, module: &Module<BACKEND>, a: &A) + fn glwe_sub_negate_inplace<R, A>(&self, res: &mut R, a: &A) where - A: GLWECiphertextToRef + GLWEInfos, - Module<BACKEND>: VecZnxSubNegateInplace, + R: GLWEToMut, + A: GLWEToRef, { - #[cfg(debug_assertions)] - { - assert_eq!(a.n(), self.n()); - assert_eq!(self.base2k(), a.base2k()); - assert!(self.rank() >= a.rank()) - } + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); - let a_ref: &GLWECiphertext<&[u8]> = &a.to_ref(); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.n(), self.n() as u32); + assert_eq!(res.base2k(), a.base2k()); + assert!(res.rank() >= a.rank()); (0..(a.rank() + 1).into()).for_each(|i| { - module.vec_znx_sub_negate_inplace(&mut self_mut.data, i, &a_ref.data, i); + self.vec_znx_sub_negate_inplace(res.data_mut(), i, a.data(), i); }); - self.set_k(set_k_unary(self, a)) + res.set_k(set_k_unary(res, a)) } +} - fn rotate<A, B: Backend>(&mut self, module: &Module<B>, k: i64, a: &A) +impl<BE: Backend> GLWERotate<BE> for Module<BE> where Self: ModuleN + VecZnxRotate + VecZnxRotateInplace<BE> {} + +pub trait GLWERotate<BE: Backend> +where + Self: ModuleN + VecZnxRotate + VecZnxRotateInplace<BE>, +{ + fn glwe_rotate<R, A>(&self, k: i64, res: &mut R, a: &A) where - A: GLWECiphertextToRef + GLWEInfos, - Module<B>: VecZnxRotate, + R: GLWEToMut, + A: GLWEToRef, { - #[cfg(debug_assertions)] - { - assert_eq!(a.n(), self.n()); - assert_eq!(self.rank(), a.rank()) - } + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); - let a_ref: &GLWECiphertext<&[u8]> = &a.to_ref(); + assert_eq!(a.n(), self.n() as u32); + assert_eq!(res.rank(), a.rank()); (0..(a.rank() + 1).into()).for_each(|i| { - module.vec_znx_rotate(k, &mut self_mut.data, i, &a_ref.data, i); + self.vec_znx_rotate(k, res.data_mut(), i, a.data(), i); }); - self.set_basek(a.base2k()); - self.set_k(set_k_unary(self, a)) + res.set_base2k(a.base2k()); + res.set_k(set_k_unary(res, a)) } - fn rotate_inplace<B: Backend>(&mut self, module: &Module<B>, k: i64, scratch: &mut Scratch<B>) + fn glwe_rotate_inplace<R>(&self, k: i64, res: &mut R, scratch: &mut Scratch<BE>) where - Module<B>: VecZnxRotateInplace<B>, + R: GLWEToMut, + Scratch<BE>: ScratchTakeCore<BE>, { - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); - (0..(self_mut.rank() + 1).into()).for_each(|i| { - module.vec_znx_rotate_inplace(k, &mut self_mut.data, i, scratch); + (0..(res.rank() + 1).into()).for_each(|i| { + self.vec_znx_rotate_inplace(k, res.data_mut(), i, scratch); }); } +} - fn mul_xp_minus_one<A, B: Backend>(&mut self, module: &Module<B>, k: i64, a: &A) +impl<BE: Backend> GLWEMulXpMinusOne<BE> for Module<BE> where Self: ModuleN + VecZnxMulXpMinusOne + VecZnxMulXpMinusOneInplace<BE> {} + +pub trait GLWEMulXpMinusOne<BE: Backend> +where + Self: ModuleN + VecZnxMulXpMinusOne + VecZnxMulXpMinusOneInplace<BE>, +{ + fn glwe_mul_xp_minus_one<R, A>(&self, k: i64, res: &mut R, a: &A) where - A: GLWECiphertextToRef + GLWEInfos, - Module<B>: VecZnxMulXpMinusOne, + R: GLWEToMut, + A: GLWEToRef, { - #[cfg(debug_assertions)] - { - assert_eq!(a.n(), self.n()); - assert_eq!(self.rank(), a.rank()) - } + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); - let a_ref: &GLWECiphertext<&[u8]> = &a.to_ref(); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.n(), self.n() as u32); + assert_eq!(res.rank(), a.rank()); - (0..(a.rank() + 1).into()).for_each(|i| { - module.vec_znx_mul_xp_minus_one(k, &mut self_mut.data, i, &a_ref.data, i); - }); + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_mul_xp_minus_one(k, res.data_mut(), i, a.data(), i); + } - self.set_basek(a.base2k()); - self.set_k(set_k_unary(self, a)) + res.set_base2k(a.base2k()); + res.set_k(set_k_unary(res, a)) } - fn mul_xp_minus_one_inplace<B: Backend>(&mut self, module: &Module<B>, k: i64, scratch: &mut Scratch<B>) + fn glwe_mul_xp_minus_one_inplace<R>(&self, k: i64, res: &mut R, scratch: &mut Scratch<BE>) where - Module<B>: VecZnxMulXpMinusOneInplace<B>, + R: GLWEToMut, { - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + + assert_eq!(res.n(), self.n() as u32); - (0..(self_mut.rank() + 1).into()).for_each(|i| { - module.vec_znx_mul_xp_minus_one_inplace(k, &mut self_mut.data, i, scratch); - }); + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_mul_xp_minus_one_inplace(k, res.data_mut(), i, scratch); + } } +} - fn copy<A, B: Backend>(&mut self, module: &Module<B>, a: &A) +impl<BE: Backend> GLWECopy for Module<BE> where Self: ModuleN + VecZnxCopy {} + +pub trait GLWECopy +where + Self: ModuleN + VecZnxCopy, +{ + fn glwe_copy<R, A>(&self, res: &mut R, a: &A) where - A: GLWECiphertextToRef + GLWEInfos, - Module<B>: VecZnxCopy, + R: GLWEToMut, + A: GLWEToRef, { - #[cfg(debug_assertions)] - { - assert_eq!(self.n(), a.n()); - assert_eq!(self.rank(), a.rank()); + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); + + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.n(), self.n() as u32); + assert_eq!(res.rank(), a.rank()); + + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_copy(res.data_mut(), i, a.data(), i); } - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); - let a_ref: &GLWECiphertext<&[u8]> = &a.to_ref(); + res.set_k(a.k().min(res.max_k())); + res.set_base2k(a.base2k()); + } +} - (0..(self_mut.rank() + 1).into()).for_each(|i| { - module.vec_znx_copy(&mut self_mut.data, i, &a_ref.data, i); - }); +impl<BE: Backend> GLWEShift<BE> for Module<BE> where Self: ModuleN + VecZnxRshInplace<BE> {} - self.set_k(a.k().min(self.max_k())); - self.set_basek(a.base2k()); +pub trait GLWEShift<BE: Backend> +where + Self: ModuleN + VecZnxRshInplace<BE>, +{ + fn glwe_rsh_tmp_byte(&self) -> usize { + VecZnx::rsh_tmp_bytes(self.n()) } - fn rsh<B: Backend>(&mut self, module: &Module<B>, k: usize, scratch: &mut Scratch<B>) + fn glwe_rsh<R>(&self, k: usize, res: &mut R, scratch: &mut Scratch<BE>) where - Module<B>: VecZnxRshInplace<B>, + R: GLWEToMut, + Scratch<BE>: ScratchTakeCore<BE>, { - let base2k: usize = self.base2k().into(); - (0..(self.rank() + 1).into()).for_each(|i| { - module.vec_znx_rsh_inplace(base2k, k, &mut self.to_mut().data, i, scratch); - }) + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let base2k: usize = res.base2k().into(); + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_rsh_inplace(base2k, k, res.data_mut(), i, scratch); + } } +} - fn normalize<A, B: Backend>(&mut self, module: &Module<B>, a: &A, scratch: &mut Scratch<B>) +impl GLWE<Vec<u8>> { + pub fn rsh_tmp_bytes<M, BE: Backend>(module: &M) -> usize where - A: GLWECiphertextToRef + GLWEInfos, - Module<B>: VecZnxNormalize<B>, + M: GLWEShift<BE>, { - #[cfg(debug_assertions)] - { - assert_eq!(self.n(), a.n()); - assert_eq!(self.rank(), a.rank()); - } + module.glwe_rsh_tmp_byte() + } +} - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); - let a_ref: &GLWECiphertext<&[u8]> = &a.to_ref(); +impl<BE: Backend> GLWENormalize<BE> for Module<BE> where Self: ModuleN + VecZnxNormalize<BE> + VecZnxNormalizeInplace<BE> {} - (0..(self_mut.rank() + 1).into()).for_each(|i| { - module.vec_znx_normalize( - a.base2k().into(), - &mut self_mut.data, +pub trait GLWENormalize<BE: Backend> +where + Self: ModuleN + VecZnxNormalize<BE> + VecZnxNormalizeInplace<BE>, +{ + fn glwe_normalize<R, A>(&self, res: &mut R, a: &A, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + A: GLWEToRef, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); + + assert_eq!(res.n(), self.n() as u32); + assert_eq!(a.n(), self.n() as u32); + assert_eq!(res.rank(), a.rank()); + + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_normalize( + res.base2k().into(), + res.data_mut(), i, a.base2k().into(), - &a_ref.data, + a.data(), i, scratch, ); - }); - self.set_basek(a.base2k()); - self.set_k(a.k().min(self.k())); + } + + res.set_k(a.k().min(res.k())); } - fn normalize_inplace<B: Backend>(&mut self, module: &Module<B>, scratch: &mut Scratch<B>) + fn glwe_normalize_inplace<R>(&self, res: &mut R, scratch: &mut Scratch<BE>) where - Module<B>: VecZnxNormalizeInplace<B>, + R: GLWEToMut, + Scratch<BE>: ScratchTakeCore<BE>, { - let self_mut: &mut GLWECiphertext<&mut [u8]> = &mut self.to_mut(); - (0..(self_mut.rank() + 1).into()).for_each(|i| { - module.vec_znx_normalize_inplace(self_mut.base2k().into(), &mut self_mut.data, i, scratch); - }); - } -} - -impl GLWECiphertext<Vec<u8>> { - pub fn rsh_scratch_space(n: usize) -> usize { - VecZnx::rsh_scratch_space(n) + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + for i in 0..res.rank().as_usize() + 1 { + self.vec_znx_normalize_inplace(res.base2k().into(), res.data_mut(), i, scratch); + } } }
@@ -1,190 +1,69 @@
use poulpy_hal::{ - api::{TakeMatZnx, TakeScalarZnx, TakeSvpPPol, TakeVecZnx, TakeVecZnxDft, TakeVmpPMat}, + api::{ModuleN, ScratchAvailable, ScratchTakeBasic, SvpPPolBytesOf, VecZnxDftBytesOf, VmpPMatBytesOf}, layouts::{Backend, Scratch}, }; use crate::{ dist::Distribution, layouts::{ - Degree, GGLWEAutomorphismKey, GGLWECiphertext, GGLWEInfos, GGLWESwitchingKey, GGLWETensorKey, GGSWCiphertext, GGSWInfos, - GLWECiphertext, GLWEInfos, GLWEPlaintext, GLWEPublicKey, GLWESecret, Rank, + Degree, GGLWE, GGLWEInfos, GGLWELayout, GGSW, GGSWInfos, GLWE, GLWEAutomorphismKey, GLWEInfos, GLWEPlaintext, + GLWEPrepared, GLWEPublicKey, GLWESecret, GLWESwitchingKey, GLWETensorKey, Rank, prepared::{ - GGLWEAutomorphismKeyPrepared, GGLWECiphertextPrepared, GGLWESwitchingKeyPrepared, GGLWETensorKeyPrepared, - GGSWCiphertextPrepared, GLWEPublicKeyPrepared, GLWESecretPrepared, + GGLWEPrepared, GGSWPrepared, GLWEAutomorphismKeyPrepared, GLWEPublicKeyPrepared, GLWESecretPrepared, + GLWESwitchingKeyPrepared, GLWETensorKeyPrepared, }, }, }; -pub trait TakeGLWECt { - fn take_glwe_ct<A>(&mut self, infos: &A) -> (GLWECiphertext<&mut [u8]>, &mut Self) - where - A: GLWEInfos; -} - -pub trait TakeGLWECtSlice { - fn take_glwe_ct_slice<A>(&mut self, size: usize, infos: &A) -> (Vec<GLWECiphertext<&mut [u8]>>, &mut Self) - where - A: GLWEInfos; -} - -pub trait TakeGLWEPt<B: Backend> { - fn take_glwe_pt<A>(&mut self, infos: &A) -> (GLWEPlaintext<&mut [u8]>, &mut Self) - where - A: GLWEInfos; -} - -pub trait TakeGGLWE { - fn take_gglwe<A>(&mut self, infos: &A) -> (GGLWECiphertext<&mut [u8]>, &mut Self) - where - A: GGLWEInfos; -} - -pub trait TakeGGLWEPrepared<B: Backend> { - fn take_gglwe_prepared<A>(&mut self, infos: &A) -> (GGLWECiphertextPrepared<&mut [u8], B>, &mut Self) - where - A: GGLWEInfos; -} - -pub trait TakeGGSW { - fn take_ggsw<A>(&mut self, infos: &A) -> (GGSWCiphertext<&mut [u8]>, &mut Self) - where - A: GGSWInfos; -} - -pub trait TakeGGSWPrepared<B: Backend> { - fn take_ggsw_prepared<A>(&mut self, infos: &A) -> (GGSWCiphertextPrepared<&mut [u8], B>, &mut Self) - where - A: GGSWInfos; -} - -pub trait TakeGGSWPreparedSlice<B: Backend> { - fn take_ggsw_prepared_slice<A>(&mut self, size: usize, infos: &A) -> (Vec<GGSWCiphertextPrepared<&mut [u8], B>>, &mut Self) - where - A: GGSWInfos; -} - -pub trait TakeGLWESecret { - fn take_glwe_secret(&mut self, n: Degree, rank: Rank) -> (GLWESecret<&mut [u8]>, &mut Self); -} - -pub trait TakeGLWESecretPrepared<B: Backend> { - fn take_glwe_secret_prepared(&mut self, n: Degree, rank: Rank) -> (GLWESecretPrepared<&mut [u8], B>, &mut Self); -} - -pub trait TakeGLWEPk { - fn take_glwe_pk<A>(&mut self, infos: &A) -> (GLWEPublicKey<&mut [u8]>, &mut Self) - where - A: GLWEInfos; -} - -pub trait TakeGLWEPkPrepared<B: Backend> { - fn take_glwe_pk_prepared<A>(&mut self, infos: &A) -> (GLWEPublicKeyPrepared<&mut [u8], B>, &mut Self) - where - A: GLWEInfos; -} - -pub trait TakeGLWESwitchingKey { - fn take_glwe_switching_key<A>(&mut self, infos: &A) -> (GGLWESwitchingKey<&mut [u8]>, &mut Self) - where - A: GGLWEInfos; -} - -pub trait TakeGGLWESwitchingKeyPrepared<B: Backend> { - fn take_gglwe_switching_key_prepared<A>(&mut self, infos: &A) -> (GGLWESwitchingKeyPrepared<&mut [u8], B>, &mut Self) - where - A: GGLWEInfos; -} - -pub trait TakeTensorKey { - fn take_tensor_key<A>(&mut self, infos: &A) -> (GGLWETensorKey<&mut [u8]>, &mut Self) - where - A: GGLWEInfos; -} - -pub trait TakeGGLWETensorKeyPrepared<B: Backend> { - fn take_gglwe_tensor_key_prepared<A>(&mut self, infos: &A) -> (GGLWETensorKeyPrepared<&mut [u8], B>, &mut Self) - where - A: GGLWEInfos; -} - -pub trait TakeGGLWEAutomorphismKey { - fn take_gglwe_automorphism_key<A>(&mut self, infos: &A) -> (GGLWEAutomorphismKey<&mut [u8]>, &mut Self) - where - A: GGLWEInfos; -} - -pub trait TakeGGLWEAutomorphismKeyPrepared<B: Backend> { - fn take_gglwe_automorphism_key_prepared<A>(&mut self, infos: &A) -> (GGLWEAutomorphismKeyPrepared<&mut [u8], B>, &mut Self) - where - A: GGLWEInfos; -} - -impl<B: Backend> TakeGLWECt for Scratch<B> +pub trait ScratchTakeCore<B: Backend> where - Scratch<B>: TakeVecZnx, + Self: ScratchTakeBasic + ScratchAvailable, { - fn take_glwe_ct<A>(&mut self, infos: &A) -> (GLWECiphertext<&mut [u8]>, &mut Self) + fn take_glwe<A>(&mut self, infos: &A) -> (GLWE<&mut [u8]>, &mut Self) where A: GLWEInfos, { let (data, scratch) = self.take_vec_znx(infos.n().into(), (infos.rank() + 1).into(), infos.size()); ( - GLWECiphertext::builder() - .base2k(infos.base2k()) - .k(infos.k()) - .data(data) - .build() - .unwrap(), + GLWE { + k: infos.k(), + base2k: infos.base2k(), + data, + }, scratch, ) } -} -impl<B: Backend> TakeGLWECtSlice for Scratch<B> -where - Scratch<B>: TakeVecZnx, -{ - fn take_glwe_ct_slice<A>(&mut self, size: usize, infos: &A) -> (Vec<GLWECiphertext<&mut [u8]>>, &mut Self) + fn take_glwe_slice<A>(&mut self, size: usize, infos: &A) -> (Vec<GLWE<&mut [u8]>>, &mut Self) where A: GLWEInfos, { - let mut scratch: &mut Scratch<B> = self; - let mut cts: Vec<GLWECiphertext<&mut [u8]>> = Vec::with_capacity(size); + let mut scratch: &mut Self = self; + let mut cts: Vec<GLWE<&mut [u8]>> = Vec::with_capacity(size); for _ in 0..size { - let (ct, new_scratch) = scratch.take_glwe_ct(infos); + let (ct, new_scratch) = scratch.take_glwe(infos); scratch = new_scratch; cts.push(ct); } (cts, scratch) } -} -impl<B: Backend> TakeGLWEPt<B> for Scratch<B> -where - Scratch<B>: TakeVecZnx, -{ - fn take_glwe_pt<A>(&mut self, infos: &A) -> (GLWEPlaintext<&mut [u8]>, &mut Self) + fn take_glwe_plaintext<A>(&mut self, infos: &A) -> (GLWEPlaintext<&mut [u8]>, &mut Self) where A: GLWEInfos, { let (data, scratch) = self.take_vec_znx(infos.n().into(), 1, infos.size()); ( - GLWEPlaintext::builder() - .base2k(infos.base2k()) - .k(infos.k()) - .data(data) - .build() - .unwrap(), + GLWEPlaintext { + k: infos.k(), + base2k: infos.base2k(), + data, + }, scratch, ) } -} -impl<B: Backend> TakeGGLWE for Scratch<B> -where - Scratch<B>: TakeMatZnx, -{ - fn take_gglwe<A>(&mut self, infos: &A) -> (GGLWECiphertext<&mut [u8]>, &mut Self) + fn take_gglwe<A>(&mut self, infos: &A) -> (GGLWE<&mut [u8]>, &mut Self) where A: GGLWEInfos, {@@ -196,51 +75,41 @@ (infos.rank_out() + 1).into(),
infos.size(), ); ( - GGLWECiphertext::builder() - .base2k(infos.base2k()) - .k(infos.k()) - .dsize(infos.dsize()) - .data(data) - .build() - .unwrap(), + GGLWE { + k: infos.k(), + base2k: infos.base2k(), + dsize: infos.dsize(), + data, + }, scratch, ) } -} -impl<B: Backend> TakeGGLWEPrepared<B> for Scratch<B> -where - Scratch<B>: TakeVmpPMat<B>, -{ - fn take_gglwe_prepared<A>(&mut self, infos: &A) -> (GGLWECiphertextPrepared<&mut [u8], B>, &mut Self) + fn take_gglwe_prepared<A, M>(&mut self, module: &M, infos: &A) -> (GGLWEPrepared<&mut [u8], B>, &mut Self) where A: GGLWEInfos, + M: ModuleN + VmpPMatBytesOf, { + assert_eq!(module.n() as u32, infos.n()); let (data, scratch) = self.take_vmp_pmat( - infos.n().into(), + module, infos.dnum().into(), infos.rank_in().into(), (infos.rank_out() + 1).into(), infos.size(), ); ( - GGLWECiphertextPrepared::builder() - .base2k(infos.base2k()) - .dsize(infos.dsize()) - .k(infos.k()) - .data(data) - .build() - .unwrap(), + GGLWEPrepared { + k: infos.k(), + base2k: infos.base2k(), + dsize: infos.dsize(), + data, + }, scratch, ) } -} -impl<B: Backend> TakeGGSW for Scratch<B> -where - Scratch<B>: TakeMatZnx, -{ - fn take_ggsw<A>(&mut self, infos: &A) -> (GGSWCiphertext<&mut [u8]>, &mut Self) + fn take_ggsw<A>(&mut self, infos: &A) -> (GGSW<&mut [u8]>, &mut Self) where A: GGSWInfos, {@@ -252,112 +121,106 @@ (infos.rank() + 1).into(),
infos.size(), ); ( - GGSWCiphertext::builder() - .base2k(infos.base2k()) - .dsize(infos.dsize()) - .k(infos.k()) - .data(data) - .build() - .unwrap(), + GGSW { + k: infos.k(), + base2k: infos.base2k(), + dsize: infos.dsize(), + data, + }, scratch, ) } -} -impl<B: Backend> TakeGGSWPrepared<B> for Scratch<B> -where - Scratch<B>: TakeVmpPMat<B>, -{ - fn take_ggsw_prepared<A>(&mut self, infos: &A) -> (GGSWCiphertextPrepared<&mut [u8], B>, &mut Self) + fn take_ggsw_prepared<A, M>(&mut self, module: &M, infos: &A) -> (GGSWPrepared<&mut [u8], B>, &mut Self) where A: GGSWInfos, + M: ModuleN + VmpPMatBytesOf, { + assert_eq!(module.n() as u32, infos.n()); let (data, scratch) = self.take_vmp_pmat( - infos.n().into(), + module, infos.dnum().into(), (infos.rank() + 1).into(), (infos.rank() + 1).into(), infos.size(), ); ( - GGSWCiphertextPrepared::builder() - .base2k(infos.base2k()) - .dsize(infos.dsize()) - .k(infos.k()) - .data(data) - .build() - .unwrap(), + GGSWPrepared { + k: infos.k(), + base2k: infos.base2k(), + dsize: infos.dsize(), + data, + }, scratch, ) } -} -impl<B: Backend> TakeGGSWPreparedSlice<B> for Scratch<B> -where - Scratch<B>: TakeGGSWPrepared<B>, -{ - fn take_ggsw_prepared_slice<A>(&mut self, size: usize, infos: &A) -> (Vec<GGSWCiphertextPrepared<&mut [u8], B>>, &mut Self) + fn take_ggsw_prepared_slice<A, M>( + &mut self, + module: &M, + size: usize, + infos: &A, + ) -> (Vec<GGSWPrepared<&mut [u8], B>>, &mut Self) where A: GGSWInfos, + M: ModuleN + VmpPMatBytesOf, { - let mut scratch: &mut Scratch<B> = self; - let mut cts: Vec<GGSWCiphertextPrepared<&mut [u8], B>> = Vec::with_capacity(size); + let mut scratch: &mut Self = self; + let mut cts: Vec<GGSWPrepared<&mut [u8], B>> = Vec::with_capacity(size); for _ in 0..size { - let (ct, new_scratch) = scratch.take_ggsw_prepared(infos); + let (ct, new_scratch) = scratch.take_ggsw_prepared(module, infos); scratch = new_scratch; cts.push(ct) } (cts, scratch) } -} -impl<B: Backend> TakeGLWEPk for Scratch<B> -where - Scratch<B>: TakeVecZnx, -{ - fn take_glwe_pk<A>(&mut self, infos: &A) -> (GLWEPublicKey<&mut [u8]>, &mut Self) + fn take_glwe_public_key<A>(&mut self, infos: &A) -> (GLWEPublicKey<&mut [u8]>, &mut Self) where A: GLWEInfos, { - let (data, scratch) = self.take_vec_znx(infos.n().into(), (infos.rank() + 1).into(), infos.size()); + let (data, scratch) = self.take_glwe(infos); ( - GLWEPublicKey::builder() - .base2k(infos.base2k()) - .k(infos.k()) - .base2k(infos.base2k()) - .data(data) - .build() - .unwrap(), + GLWEPublicKey { + dist: Distribution::NONE, + key: data, + }, scratch, ) } -} -impl<B: Backend> TakeGLWEPkPrepared<B> for Scratch<B> -where - Scratch<B>: TakeVecZnxDft<B>, -{ - fn take_glwe_pk_prepared<A>(&mut self, infos: &A) -> (GLWEPublicKeyPrepared<&mut [u8], B>, &mut Self) + fn take_glwe_public_key_prepared<A, M>(&mut self, module: &M, infos: &A) -> (GLWEPublicKeyPrepared<&mut [u8], B>, &mut Self) where A: GLWEInfos, + M: ModuleN + VecZnxDftBytesOf, { - let (data, scratch) = self.take_vec_znx_dft(infos.n().into(), (infos.rank() + 1).into(), infos.size()); + let (data, scratch) = self.take_glwe_prepared(module, infos); ( - GLWEPublicKeyPrepared::builder() - .base2k(infos.base2k()) - .k(infos.k()) - .data(data) - .build() - .unwrap(), + GLWEPublicKeyPrepared { + dist: Distribution::NONE, + key: data, + }, scratch, ) } -} -impl<B: Backend> TakeGLWESecret for Scratch<B> -where - Scratch<B>: TakeScalarZnx, -{ + fn take_glwe_prepared<A, M>(&mut self, module: &M, infos: &A) -> (GLWEPrepared<&mut [u8], B>, &mut Self) + where + A: GLWEInfos, + M: ModuleN + VecZnxDftBytesOf, + { + assert_eq!(module.n() as u32, infos.n()); + let (data, scratch) = self.take_vec_znx_dft(module, (infos.rank() + 1).into(), infos.size()); + ( + GLWEPrepared { + k: infos.k(), + base2k: infos.base2k(), + data, + }, + scratch, + ) + } + fn take_glwe_secret(&mut self, n: Degree, rank: Rank) -> (GLWESecret<&mut [u8]>, &mut Self) { let (data, scratch) = self.take_scalar_znx(n.into(), rank.into()); (@@ -368,14 +231,12 @@ },
scratch, ) } -} -impl<B: Backend> TakeGLWESecretPrepared<B> for Scratch<B> -where - Scratch<B>: TakeSvpPPol<B>, -{ - fn take_glwe_secret_prepared(&mut self, n: Degree, rank: Rank) -> (GLWESecretPrepared<&mut [u8], B>, &mut Self) { - let (data, scratch) = self.take_svp_ppol(n.into(), rank.into()); + fn take_glwe_secret_prepared<M>(&mut self, module: &M, rank: Rank) -> (GLWESecretPrepared<&mut [u8], B>, &mut Self) + where + M: ModuleN + SvpPPolBytesOf, + { + let (data, scratch) = self.take_svp_ppol(module, rank.into()); ( GLWESecretPrepared { data,@@ -384,141 +245,127 @@ },
scratch, ) } -} -impl<B: Backend> TakeGLWESwitchingKey for Scratch<B> -where - Scratch<B>: TakeMatZnx, -{ - fn take_glwe_switching_key<A>(&mut self, infos: &A) -> (GGLWESwitchingKey<&mut [u8]>, &mut Self) + fn take_glwe_switching_key<A>(&mut self, infos: &A) -> (GLWESwitchingKey<&mut [u8]>, &mut Self) where A: GGLWEInfos, { let (data, scratch) = self.take_gglwe(infos); ( - GGLWESwitchingKey { + GLWESwitchingKey { key: data, - sk_in_n: 0, - sk_out_n: 0, + input_degree: Degree(0), + output_degree: Degree(0), }, scratch, ) } -} -impl<B: Backend> TakeGGLWESwitchingKeyPrepared<B> for Scratch<B> -where - Scratch<B>: TakeGGLWEPrepared<B>, -{ - fn take_gglwe_switching_key_prepared<A>(&mut self, infos: &A) -> (GGLWESwitchingKeyPrepared<&mut [u8], B>, &mut Self) + fn take_glwe_switching_key_prepared<A, M>( + &mut self, + module: &M, + infos: &A, + ) -> (GLWESwitchingKeyPrepared<&mut [u8], B>, &mut Self) where A: GGLWEInfos, + M: ModuleN + VmpPMatBytesOf, { - let (data, scratch) = self.take_gglwe_prepared(infos); + assert_eq!(module.n() as u32, infos.n()); + let (data, scratch) = self.take_gglwe_prepared(module, infos); ( - GGLWESwitchingKeyPrepared { + GLWESwitchingKeyPrepared { key: data, - sk_in_n: 0, - sk_out_n: 0, + input_degree: Degree(0), + output_degree: Degree(0), }, scratch, ) } -} -impl<B: Backend> TakeGGLWEAutomorphismKey for Scratch<B> -where - Scratch<B>: TakeMatZnx, -{ - fn take_gglwe_automorphism_key<A>(&mut self, infos: &A) -> (GGLWEAutomorphismKey<&mut [u8]>, &mut Self) + fn take_glwe_automorphism_key<A>(&mut self, infos: &A) -> (GLWEAutomorphismKey<&mut [u8]>, &mut Self) where A: GGLWEInfos, { - let (data, scratch) = self.take_glwe_switching_key(infos); - (GGLWEAutomorphismKey { key: data, p: 0 }, scratch) + let (data, scratch) = self.take_gglwe(infos); + (GLWEAutomorphismKey { key: data, p: 0 }, scratch) } -} -impl<B: Backend> TakeGGLWEAutomorphismKeyPrepared<B> for Scratch<B> -where - Scratch<B>: TakeGGLWESwitchingKeyPrepared<B>, -{ - fn take_gglwe_automorphism_key_prepared<A>(&mut self, infos: &A) -> (GGLWEAutomorphismKeyPrepared<&mut [u8], B>, &mut Self) + fn take_glwe_automorphism_key_prepared<A, M>( + &mut self, + module: &M, + infos: &A, + ) -> (GLWEAutomorphismKeyPrepared<&mut [u8], B>, &mut Self) where A: GGLWEInfos, + M: ModuleN + VmpPMatBytesOf, { - let (data, scratch) = self.take_gglwe_switching_key_prepared(infos); - (GGLWEAutomorphismKeyPrepared { key: data, p: 0 }, scratch) + assert_eq!(module.n() as u32, infos.n()); + let (data, scratch) = self.take_gglwe_prepared(module, infos); + (GLWEAutomorphismKeyPrepared { key: data, p: 0 }, scratch) } -} -impl<B: Backend> TakeTensorKey for Scratch<B> -where - Scratch<B>: TakeMatZnx, -{ - fn take_tensor_key<A>(&mut self, infos: &A) -> (GGLWETensorKey<&mut [u8]>, &mut Self) + fn take_glwe_tensor_key<A, M>(&mut self, infos: &A) -> (GLWETensorKey<&mut [u8]>, &mut Self) where A: GGLWEInfos, { assert_eq!( infos.rank_in(), infos.rank_out(), - "rank_in != rank_out is not supported for GGLWETensorKey" + "rank_in != rank_out is not supported for GLWETensorKey" ); - let mut keys: Vec<GGLWESwitchingKey<&mut [u8]>> = Vec::new(); + let mut keys: Vec<GGLWE<&mut [u8]>> = Vec::new(); let pairs: usize = (((infos.rank_out().0 + 1) * infos.rank_out().0) >> 1).max(1) as usize; - let mut scratch: &mut Scratch<B> = self; + let mut scratch: &mut Self = self; - let mut ksk_infos: crate::layouts::GGLWECiphertextLayout = infos.layout(); + let mut ksk_infos: GGLWELayout = infos.gglwe_layout(); ksk_infos.rank_in = Rank(1); if pairs != 0 { - let (gglwe, s) = scratch.take_glwe_switching_key(&ksk_infos); + let (gglwe, s) = scratch.take_gglwe(&ksk_infos); scratch = s; keys.push(gglwe); } for _ in 1..pairs { - let (gglwe, s) = scratch.take_glwe_switching_key(&ksk_infos); + let (gglwe, s) = scratch.take_gglwe(&ksk_infos); scratch = s; keys.push(gglwe); } - (GGLWETensorKey { keys }, scratch) + (GLWETensorKey { keys }, scratch) } -} -impl<B: Backend> TakeGGLWETensorKeyPrepared<B> for Scratch<B> -where - Scratch<B>: TakeVmpPMat<B>, -{ - fn take_gglwe_tensor_key_prepared<A>(&mut self, infos: &A) -> (GGLWETensorKeyPrepared<&mut [u8], B>, &mut Self) + fn take_glwe_tensor_key_prepared<A, M>(&mut self, module: &M, infos: &A) -> (GLWETensorKeyPrepared<&mut [u8], B>, &mut Self) where A: GGLWEInfos, + M: ModuleN + VmpPMatBytesOf, { + assert_eq!(module.n() as u32, infos.n()); assert_eq!( infos.rank_in(), infos.rank_out(), "rank_in != rank_out is not supported for GGLWETensorKeyPrepared" ); - let mut keys: Vec<GGLWESwitchingKeyPrepared<&mut [u8], B>> = Vec::new(); + let mut keys: Vec<GGLWEPrepared<&mut [u8], B>> = Vec::new(); let pairs: usize = (((infos.rank_out().0 + 1) * infos.rank_out().0) >> 1).max(1) as usize; - let mut scratch: &mut Scratch<B> = self; + let mut scratch: &mut Self = self; - let mut ksk_infos: crate::layouts::GGLWECiphertextLayout = infos.layout(); + let mut ksk_infos: GGLWELayout = infos.gglwe_layout(); ksk_infos.rank_in = Rank(1); if pairs != 0 { - let (gglwe, s) = scratch.take_gglwe_switching_key_prepared(&ksk_infos); + let (gglwe, s) = scratch.take_gglwe_prepared(module, &ksk_infos); scratch = s; keys.push(gglwe); } for _ in 1..pairs { - let (gglwe, s) = scratch.take_gglwe_switching_key_prepared(&ksk_infos); + let (gglwe, s) = scratch.take_gglwe_prepared(module, &ksk_infos); scratch = s; keys.push(gglwe); } - (GGLWETensorKeyPrepared { keys }, scratch) + (GLWETensorKeyPrepared { keys }, scratch) } } + +impl<B: Backend> ScratchTakeCore<B> for Scratch<B> where Self: ScratchTakeBasic + ScratchAvailable {}
@@ -8,175 +8,174 @@ use poulpy_hal::backend_test_suite;
#[cfg(test)] backend_test_suite!( - mod cpu_spqlios, - backend = poulpy_backend::cpu_spqlios::FFT64Spqlios, - size = 1<<8, - tests = { - // GLWE Encryption - glwe_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_sk, - glwe_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_compressed_encrypt_sk, - glwe_encrypt_zero_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_zero_sk, - glwe_encrypt_pk => crate::tests::test_suite::encryption::test_glwe_encrypt_pk, - // GLWE Keyswitch - glwe_keyswitch => crate::tests::test_suite::keyswitch::test_glwe_keyswitch, - glwe_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_glwe_keyswitch_inplace, - // GLWE Automorphism - glwe_automorphism => crate::tests::test_suite::automorphism::test_glwe_automorphism, - glwe_automorphism_inplace => crate::tests::test_suite::automorphism::test_glwe_automorphism_inplace, - // GLWE External Product - glwe_external_product => crate::tests::test_suite::external_product::test_glwe_external_product, - glwe_external_product_inplace => crate::tests::test_suite::external_product::test_glwe_external_product_inplace, - // GLWE Trace - glwe_trace_inplace => crate::tests::test_suite::test_glwe_trace_inplace, - glwe_packing => crate::tests::test_suite::test_glwe_packing, - // GGLWE Encryption - gglwe_switching_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_encrypt_sk, - gglwe_switching_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_compressed_encrypt_sk, - gglwe_automorphisk_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphisk_key_encrypt_sk, - gglwe_automorphisk_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphisk_key_compressed_encrypt_sk, - gglwe_tensor_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_encrypt_sk, - gglwe_tensor_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_compressed_encrypt_sk, - // GGLWE Keyswitching - gglwe_switching_key_keyswitch => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch, - gglwe_switching_key_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch_inplace, - // GGLWE External Product - gglwe_switching_key_external_product => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product, - gglwe_switching_key_external_product_inplace => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product_inplace, - // GGLWE Automorphism - gglwe_automorphism_key_automorphism => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism, - gglwe_automorphism_key_automorphism_inplace => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism_inplace, - // GGSW Encryption - ggsw_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_encrypt_sk, - ggsw_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_compressed_encrypt_sk, - // GGSW Keyswitching - ggsw_keyswitch => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch, - ggsw_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch_inplace, - // GGSW External Product - ggsw_external_product => crate::tests::test_suite::external_product::test_ggsw_external_product, - ggsw_external_product_inplace => crate::tests::test_suite::external_product::test_ggsw_external_product_inplace, - // GGSW Automorphism - ggsw_automorphism => crate::tests::test_suite::automorphism::test_ggsw_automorphism, - ggsw_automorphism_inplace => crate::tests::test_suite::automorphism::test_ggsw_automorphism_inplace, - // LWE - lwe_keyswitch => crate::tests::test_suite::keyswitch::test_lwe_keyswitch, - glwe_to_lwe => crate::tests::test_suite::test_glwe_to_lwe, - lwe_to_glwe => crate::tests::test_suite::test_lwe_to_glwe, - } + mod cpu_spqlios, + backend = poulpy_backend::cpu_spqlios::FFT64Spqlios, + size = 1<<8, + tests = { + //GLWE Encryption + glwe_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_sk, + glwe_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_compressed_encrypt_sk, + glwe_encrypt_zero_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_zero_sk, + glwe_encrypt_pk => crate::tests::test_suite::encryption::test_glwe_encrypt_pk, +// GLWE Keyswitch +glwe_keyswitch => crate::tests::test_suite::keyswitch::test_glwe_keyswitch, +glwe_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_glwe_keyswitch_inplace, +// GLWE Automorphism +glwe_automorphism => crate::tests::test_suite::automorphism::test_glwe_automorphism, +glwe_automorphism_inplace => crate::tests::test_suite::automorphism::test_glwe_automorphism_inplace, +// GLWE External Product +glwe_external_product => crate::tests::test_suite::external_product::test_glwe_external_product, +glwe_external_product_inplace => crate::tests::test_suite::external_product::test_glwe_external_product_inplace, +// GLWE Trace +glwe_trace_inplace => crate::tests::test_suite::test_glwe_trace_inplace, +glwe_packing => crate::tests::test_suite::test_glwe_packing, +// GGLWE Encryption +gglwe_switching_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_encrypt_sk, +gglwe_switching_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_compressed_encrypt_sk, +gglwe_automorphism_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphism_key_encrypt_sk, +gglwe_automorphism_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphism_key_compressed_encrypt_sk, +gglwe_tensor_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_encrypt_sk, +gglwe_tensor_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_compressed_encrypt_sk, +// GGLWE Keyswitching +gglwe_switching_key_keyswitch => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch, +gglwe_switching_key_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch_inplace, +// GGLWE External Product +gglwe_switching_key_external_product => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product, +gglwe_switching_key_external_product_inplace => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product_inplace, +// GGLWE Automorphism +gglwe_automorphism_key_automorphism => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism, +gglwe_automorphism_key_automorphism_inplace => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism_inplace, +// GGSW Encryption +ggsw_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_encrypt_sk, +ggsw_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_compressed_encrypt_sk, +// GGSW Keyswitching +ggsw_keyswitch => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch, +ggsw_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch_inplace, +// GGSW External Product +ggsw_external_product => crate::tests::test_suite::external_product::test_ggsw_external_product, +ggsw_external_product_inplace => crate::tests::test_suite::external_product::test_ggsw_external_product_inplace, +// GGSW Automorphism +ggsw_automorphism => crate::tests::test_suite::automorphism::test_ggsw_automorphism, +ggsw_automorphism_inplace => crate::tests::test_suite::automorphism::test_ggsw_automorphism_inplace, +// LWE +lwe_keyswitch => crate::tests::test_suite::keyswitch::test_lwe_keyswitch, +glwe_to_lwe => crate::tests::test_suite::test_glwe_to_lwe, +lwe_to_glwe => crate::tests::test_suite::test_lwe_to_glwe, +} ); - #[cfg(test)] backend_test_suite!( - mod cpu_ref, - backend = poulpy_backend::cpu_fft64_ref::FFT64Ref, - size = 1<<8, - tests = { - // GLWE Encryption - glwe_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_sk, - glwe_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_compressed_encrypt_sk, - glwe_encrypt_zero_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_zero_sk, - glwe_encrypt_pk => crate::tests::test_suite::encryption::test_glwe_encrypt_pk, - // GLWE Keyswitch - glwe_keyswitch => crate::tests::test_suite::keyswitch::test_glwe_keyswitch, - glwe_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_glwe_keyswitch_inplace, - // GLWE Automorphism - glwe_automorphism => crate::tests::test_suite::automorphism::test_glwe_automorphism, - glwe_automorphism_inplace => crate::tests::test_suite::automorphism::test_glwe_automorphism_inplace, - // GLWE External Product - glwe_external_product => crate::tests::test_suite::external_product::test_glwe_external_product, - glwe_external_product_inplace => crate::tests::test_suite::external_product::test_glwe_external_product_inplace, - // GLWE Trace - glwe_trace_inplace => crate::tests::test_suite::test_glwe_trace_inplace, - glwe_packing => crate::tests::test_suite::test_glwe_packing, - // GGLWE Encryption - gglwe_switching_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_encrypt_sk, - gglwe_switching_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_compressed_encrypt_sk, - gglwe_automorphisk_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphisk_key_encrypt_sk, - gglwe_automorphisk_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphisk_key_compressed_encrypt_sk, - gglwe_tensor_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_encrypt_sk, - gglwe_tensor_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_compressed_encrypt_sk, - // GGLWE Keyswitching - gglwe_switching_key_keyswitch => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch, - gglwe_switching_key_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch_inplace, - // GGLWE External Product - gglwe_switching_key_external_product => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product, - gglwe_switching_key_external_product_inplace => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product_inplace, - // GGLWE Automorphism - gglwe_automorphism_key_automorphism => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism, - gglwe_automorphism_key_automorphism_inplace => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism_inplace, - // GGSW Encryption - ggsw_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_encrypt_sk, - ggsw_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_compressed_encrypt_sk, - // GGSW Keyswitching - ggsw_keyswitch => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch, - ggsw_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch_inplace, - // GGSW External Product - ggsw_external_product => crate::tests::test_suite::external_product::test_ggsw_external_product, - ggsw_external_product_inplace => crate::tests::test_suite::external_product::test_ggsw_external_product_inplace, - // GGSW Automorphism - ggsw_automorphism => crate::tests::test_suite::automorphism::test_ggsw_automorphism, - ggsw_automorphism_inplace => crate::tests::test_suite::automorphism::test_ggsw_automorphism_inplace, - // LWE - lwe_keyswitch => crate::tests::test_suite::keyswitch::test_lwe_keyswitch, - glwe_to_lwe => crate::tests::test_suite::test_glwe_to_lwe, - lwe_to_glwe => crate::tests::test_suite::test_lwe_to_glwe, - } -); + mod cpu_ref, + backend = poulpy_backend::cpu_fft64_ref::FFT64Ref, + size = 1<<8, + tests = { + //GLWE Encryption + glwe_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_sk, + glwe_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_compressed_encrypt_sk, + glwe_encrypt_zero_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_zero_sk, + glwe_encrypt_pk => crate::tests::test_suite::encryption::test_glwe_encrypt_pk, +// GLWE Keyswitch + glwe_keyswitch => crate::tests::test_suite::keyswitch::test_glwe_keyswitch, +glwe_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_glwe_keyswitch_inplace, +// GLWE Automorphism +glwe_automorphism => crate::tests::test_suite::automorphism::test_glwe_automorphism, +glwe_automorphism_inplace => crate::tests::test_suite::automorphism::test_glwe_automorphism_inplace, +// GLWE External Product +glwe_external_product => crate::tests::test_suite::external_product::test_glwe_external_product, +glwe_external_product_inplace => crate::tests::test_suite::external_product::test_glwe_external_product_inplace, +// GLWE Trace +glwe_trace_inplace => crate::tests::test_suite::test_glwe_trace_inplace, +glwe_packing => crate::tests::test_suite::test_glwe_packing, +// GGLWE Encryption +gglwe_switching_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_encrypt_sk, +gglwe_switching_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_compressed_encrypt_sk, +gglwe_automorphism_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphism_key_encrypt_sk, +gglwe_automorphism_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphism_key_compressed_encrypt_sk, +gglwe_tensor_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_encrypt_sk, +gglwe_tensor_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_compressed_encrypt_sk, +// GGLWE Keyswitching +gglwe_switching_key_keyswitch => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch, +gglwe_switching_key_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch_inplace, +// GGLWE External Product +gglwe_switching_key_external_product => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product, +gglwe_switching_key_external_product_inplace => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product_inplace, +// GGLWE Automorphism +gglwe_automorphism_key_automorphism => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism, +gglwe_automorphism_key_automorphism_inplace => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism_inplace, +// GGSW Encryption +ggsw_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_encrypt_sk, +ggsw_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_compressed_encrypt_sk, +// GGSW Keyswitching +ggsw_keyswitch => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch, +ggsw_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch_inplace, +// GGSW External Product +ggsw_external_product => crate::tests::test_suite::external_product::test_ggsw_external_product, +ggsw_external_product_inplace => crate::tests::test_suite::external_product::test_ggsw_external_product_inplace, +// GGSW Automorphism +ggsw_automorphism => crate::tests::test_suite::automorphism::test_ggsw_automorphism, +ggsw_automorphism_inplace => crate::tests::test_suite::automorphism::test_ggsw_automorphism_inplace, +// LWE +lwe_keyswitch => crate::tests::test_suite::keyswitch::test_lwe_keyswitch, +glwe_to_lwe => crate::tests::test_suite::test_glwe_to_lwe, +lwe_to_glwe => crate::tests::test_suite::test_lwe_to_glwe, +} + ); #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] #[cfg(test)] backend_test_suite!( - mod cpu_avx, - backend = poulpy_backend::cpu_fft64_avx::FFT64Avx, - size = 1<<8, - tests = { - // GLWE Encryption - glwe_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_sk, - glwe_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_compressed_encrypt_sk, - glwe_encrypt_zero_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_zero_sk, - glwe_encrypt_pk => crate::tests::test_suite::encryption::test_glwe_encrypt_pk, - // GLWE Keyswitch - glwe_keyswitch => crate::tests::test_suite::keyswitch::test_glwe_keyswitch, - glwe_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_glwe_keyswitch_inplace, - // GLWE Automorphism - glwe_automorphism => crate::tests::test_suite::automorphism::test_glwe_automorphism, - glwe_automorphism_inplace => crate::tests::test_suite::automorphism::test_glwe_automorphism_inplace, - // GLWE External Product - glwe_external_product => crate::tests::test_suite::external_product::test_glwe_external_product, - glwe_external_product_inplace => crate::tests::test_suite::external_product::test_glwe_external_product_inplace, - // GLWE Trace - glwe_trace_inplace => crate::tests::test_suite::test_glwe_trace_inplace, - glwe_packing => crate::tests::test_suite::test_glwe_packing, - // GGLWE Encryption - gglwe_switching_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_encrypt_sk, - gglwe_switching_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_compressed_encrypt_sk, - gglwe_automorphisk_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphisk_key_encrypt_sk, - gglwe_automorphisk_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphisk_key_compressed_encrypt_sk, - gglwe_tensor_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_encrypt_sk, - gglwe_tensor_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_compressed_encrypt_sk, - // GGLWE Keyswitching - gglwe_switching_key_keyswitch => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch, - gglwe_switching_key_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch_inplace, - // GGLWE External Product - gglwe_switching_key_external_product => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product, - gglwe_switching_key_external_product_inplace => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product_inplace, - // GGLWE Automorphism - gglwe_automorphism_key_automorphism => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism, - gglwe_automorphism_key_automorphism_inplace => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism_inplace, - // GGSW Encryption - ggsw_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_encrypt_sk, - ggsw_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_compressed_encrypt_sk, - // GGSW Keyswitching - ggsw_keyswitch => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch, - ggsw_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch_inplace, - // GGSW External Product - ggsw_external_product => crate::tests::test_suite::external_product::test_ggsw_external_product, - ggsw_external_product_inplace => crate::tests::test_suite::external_product::test_ggsw_external_product_inplace, - // GGSW Automorphism - ggsw_automorphism => crate::tests::test_suite::automorphism::test_ggsw_automorphism, - ggsw_automorphism_inplace => crate::tests::test_suite::automorphism::test_ggsw_automorphism_inplace, - // LWE - lwe_keyswitch => crate::tests::test_suite::keyswitch::test_lwe_keyswitch, - glwe_to_lwe => crate::tests::test_suite::test_glwe_to_lwe, - lwe_to_glwe => crate::tests::test_suite::test_lwe_to_glwe, - } -); + mod cpu_avx, + backend = poulpy_backend::cpu_fft64_avx::FFT64Avx, + size = 1<<8, + tests = { + //GLWE Encryption + glwe_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_sk, + glwe_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_compressed_encrypt_sk, + glwe_encrypt_zero_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_zero_sk, + glwe_encrypt_pk => crate::tests::test_suite::encryption::test_glwe_encrypt_pk, +// GLWE Keyswitch +glwe_keyswitch => crate::tests::test_suite::keyswitch::test_glwe_keyswitch, +glwe_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_glwe_keyswitch_inplace, +// GLWE Automorphism +glwe_automorphism => crate::tests::test_suite::automorphism::test_glwe_automorphism, +glwe_automorphism_inplace => crate::tests::test_suite::automorphism::test_glwe_automorphism_inplace, +// GLWE External Product +glwe_external_product => crate::tests::test_suite::external_product::test_glwe_external_product, +glwe_external_product_inplace => crate::tests::test_suite::external_product::test_glwe_external_product_inplace, +// GLWE Trace +glwe_trace_inplace => crate::tests::test_suite::test_glwe_trace_inplace, +glwe_packing => crate::tests::test_suite::test_glwe_packing, +// GGLWE Encryption +gglwe_switching_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_encrypt_sk, +gglwe_switching_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_compressed_encrypt_sk, +gglwe_automorphism_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphism_key_encrypt_sk, +gglwe_automorphism_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphism_key_compressed_encrypt_sk, +gglwe_tensor_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_encrypt_sk, +gglwe_tensor_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_compressed_encrypt_sk, +// GGLWE Keyswitching +gglwe_switching_key_keyswitch => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch, +gglwe_switching_key_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch_inplace, +// GGLWE External Product +gglwe_switching_key_external_product => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product, +gglwe_switching_key_external_product_inplace => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product_inplace, +// GGLWE Automorphism +gglwe_automorphism_key_automorphism => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism, +gglwe_automorphism_key_automorphism_inplace => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism_inplace, +// GGSW Encryption +ggsw_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_encrypt_sk, +ggsw_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_compressed_encrypt_sk, +// GGSW Keyswitching +ggsw_keyswitch => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch, +ggsw_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch_inplace, +// GGSW External Product +ggsw_external_product => crate::tests::test_suite::external_product::test_ggsw_external_product, +ggsw_external_product_inplace => crate::tests::test_suite::external_product::test_ggsw_external_product_inplace, +// GGSW Automorphism +ggsw_automorphism => crate::tests::test_suite::automorphism::test_ggsw_automorphism, +ggsw_automorphism_inplace => crate::tests::test_suite::automorphism::test_ggsw_automorphism_inplace, +// LWE +lwe_keyswitch => crate::tests::test_suite::keyswitch::test_lwe_keyswitch, +glwe_to_lwe => crate::tests::test_suite::test_glwe_to_lwe, +lwe_to_glwe => crate::tests::test_suite::test_lwe_to_glwe, +} + );
@@ -1,12 +1,12 @@
use poulpy_hal::test_suite::serialization::test_reader_writer_interface; use crate::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKey, GGLWECiphertext, GGLWESwitchingKey, GGLWETensorKey, GGSWCiphertext, - GLWECiphertext, GLWEToLWEKey, LWECiphertext, LWESwitchingKey, LWEToGLWESwitchingKey, Rank, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGLWE, GGSW, GLWE, GLWEAutomorphismKey, GLWESwitchingKey, GLWETensorKey, GLWEToLWESwitchingKey, + LWE, LWESwitchingKey, LWEToGLWESwitchingKey, Rank, TorusPrecision, compressed::{ - GGLWEAutomorphismKeyCompressed, GGLWECiphertextCompressed, GGLWESwitchingKeyCompressed, GGLWETensorKeyCompressed, - GGSWCiphertextCompressed, GLWECiphertextCompressed, GLWEToLWESwitchingKeyCompressed, LWECiphertextCompressed, - LWESwitchingKeyCompressed, LWEToGLWESwitchingKeyCompressed, + GGLWECompressed, GGSWCompressed, GLWEAutomorphismKeyCompressed, GLWECompressed, GLWESwitchingKeyCompressed, + GLWETensorKeyCompressed, GLWEToLWESwitchingKeyCompressed, LWECompressed, LWESwitchingKeyCompressed, + LWEToGLWESwitchingKeyCompressed, }, };@@ -20,125 +20,124 @@ const DSIZE: Dsize = Dsize(1);
#[test] fn glwe_serialization() { - let original: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc_with(N_GLWE, BASE2K, K, RANK); + let original: GLWE<Vec<u8>> = GLWE::alloc(N_GLWE, BASE2K, K, RANK); poulpy_hal::test_suite::serialization::test_reader_writer_interface(original); } #[test] fn glwe_compressed_serialization() { - let original: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc_with(N_GLWE, BASE2K, K, RANK); + let original: GLWECompressed<Vec<u8>> = GLWECompressed::alloc(N_GLWE, BASE2K, K, RANK); test_reader_writer_interface(original); } #[test] fn lwe_serialization() { - let original: LWECiphertext<Vec<u8>> = LWECiphertext::alloc_with(N_LWE, BASE2K, K); + let original: LWE<Vec<u8>> = LWE::alloc(N_LWE, BASE2K, K); test_reader_writer_interface(original); } #[test] fn lwe_compressed_serialization() { - let original: LWECiphertextCompressed<Vec<u8>> = LWECiphertextCompressed::alloc_with(BASE2K, K); + let original: LWECompressed<Vec<u8>> = LWECompressed::alloc(BASE2K, K); test_reader_writer_interface(original); } #[test] fn test_gglwe_serialization() { - let original: GGLWECiphertext<Vec<u8>> = GGLWECiphertext::alloc_with(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); + let original: GGLWE<Vec<u8>> = GGLWE::alloc(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_gglwe_compressed_serialization() { - let original: GGLWECiphertextCompressed<Vec<u8>> = - GGLWECiphertextCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); + let original: GGLWECompressed<Vec<u8>> = GGLWECompressed::alloc(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_glwe_switching_key_serialization() { - let original: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); + let original: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_glwe_switching_key_compressed_serialization() { - let original: GGLWESwitchingKeyCompressed<Vec<u8>> = - GGLWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); + let original: GLWESwitchingKeyCompressed<Vec<u8>> = + GLWESwitchingKeyCompressed::alloc(N_GLWE, BASE2K, K, RANK, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_automorphism_key_serialization() { - let original: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); + let original: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_automorphism_key_compressed_serialization() { - let original: GGLWEAutomorphismKeyCompressed<Vec<u8>> = - GGLWEAutomorphismKeyCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); + let original: GLWEAutomorphismKeyCompressed<Vec<u8>> = + GLWEAutomorphismKeyCompressed::alloc(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_tensor_key_serialization() { - let original: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); + let original: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn test_tensor_key_compressed_serialization() { - let original: GGLWETensorKeyCompressed<Vec<u8>> = GGLWETensorKeyCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); + let original: GLWETensorKeyCompressed<Vec<u8>> = GLWETensorKeyCompressed::alloc(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn glwe_to_lwe_switching_key_serialization() { - let original: GLWEToLWEKey<Vec<u8>> = GLWEToLWEKey::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM); + let original: GLWEToLWESwitchingKey<Vec<u8>> = GLWEToLWESwitchingKey::alloc(N_GLWE, BASE2K, K, RANK, DNUM); test_reader_writer_interface(original); } #[test] fn glwe_to_lwe_switching_key_compressed_serialization() { let original: GLWEToLWESwitchingKeyCompressed<Vec<u8>> = - GLWEToLWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM); + GLWEToLWESwitchingKeyCompressed::alloc(N_GLWE, BASE2K, K, RANK, DNUM); test_reader_writer_interface(original); } #[test] fn lwe_to_glwe_switching_key_serialization() { - let original: LWEToGLWESwitchingKey<Vec<u8>> = LWEToGLWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM); + let original: LWEToGLWESwitchingKey<Vec<u8>> = LWEToGLWESwitchingKey::alloc(N_GLWE, BASE2K, K, RANK, DNUM); test_reader_writer_interface(original); } #[test] fn lwe_to_glwe_switching_key_compressed_serialization() { let original: LWEToGLWESwitchingKeyCompressed<Vec<u8>> = - LWEToGLWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM); + LWEToGLWESwitchingKeyCompressed::alloc(N_GLWE, BASE2K, K, RANK, DNUM); test_reader_writer_interface(original); } #[test] fn lwe_switching_key_serialization() { - let original: LWESwitchingKey<Vec<u8>> = LWESwitchingKey::alloc_with(N_GLWE, BASE2K, K, DNUM); + let original: LWESwitchingKey<Vec<u8>> = LWESwitchingKey::alloc(N_GLWE, BASE2K, K, DNUM); test_reader_writer_interface(original); } #[test] fn lwe_switching_key_compressed_serialization() { - let original: LWESwitchingKeyCompressed<Vec<u8>> = LWESwitchingKeyCompressed::alloc_with(N_GLWE, BASE2K, K, DNUM); + let original: LWESwitchingKeyCompressed<Vec<u8>> = LWESwitchingKeyCompressed::alloc(N_GLWE, BASE2K, K, DNUM); test_reader_writer_interface(original); } #[test] fn ggsw_serialization() { - let original: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); + let original: GGSW<Vec<u8>> = GGSW::alloc(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); } #[test] fn ggsw_compressed_serialization() { - let original: GGSWCiphertextCompressed<Vec<u8>> = GGSWCiphertextCompressed::alloc_with(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); + let original: GGSWCompressed<Vec<u8>> = GGSWCompressed::alloc(N_GLWE, BASE2K, K, RANK, DNUM, DSIZE); test_reader_writer_interface(original); }
@@ -1,71 +1,33 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, - VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, - VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, - VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSubScalarInplace, VecZnxSwitchRing, - VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAutomorphism, VecZnxSubScalarInplace}, + layouts::{Backend, GaloisElement, Module, Scratch, ScratchOwned}, source::Source, }; use crate::{ + GLWEAutomorphismKeyAutomorphism, GLWEAutomorphismKeyEncryptSk, GLWEDecrypt, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWEInfos, GLWEPlaintext, GLWESecret, - prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, Prepare, PrepareAlloc}, + GGLWEInfos, GLWEAutomorphismKey, GLWEAutomorphismKeyLayout, GLWEAutomorphismKeyPreparedFactory, GLWEPlaintext, + GLWESecret, GLWESecretPreparedFactory, + prepared::{GLWEAutomorphismKeyPrepared, GLWESecretPrepared}, }, noise::log2_std_noise_gglwe_product, }; #[allow(clippy::too_many_arguments)] -pub fn test_gglwe_automorphism_key_automorphism<B>(module: &Module<B>) +pub fn test_gglwe_automorphism_key_automorphism<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> + Module<BE>: GLWEAutomorphismKeyEncryptSk<BE> + + GLWEAutomorphismKeyPreparedFactory<BE> + + GLWEAutomorphismKeyAutomorphism<BE> + VecZnxAutomorphism - + VecZnxAutomorphismInplace<B> - + SvpPPolAllocBytes - + VecZnxDftAllocBytes - + VecZnxNormalizeTmpBytes - + VmpPMatAlloc<B> - + VmpPrepare<B> - + SvpPrepare<B> - + SvpApplyDftToDftInplace<B> - + VecZnxAddScalarInplace - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + VecZnxSwitchRing - + SvpPPolAlloc<B> - + VecZnxBigAddInplace<B> - + VecZnxSubScalarInplace, - B: Backend - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxDftImpl<B> - + TakeVecZnxImpl<B> - + TakeSvpPPolImpl<B> - + TakeVecZnxBigImpl<B>, + + GaloisElement + + VecZnxSubScalarInplace + + GLWESecretPreparedFactory<BE> + + GLWEDecrypt<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_in: usize = 60;@@ -84,7 +46,7 @@ let dnum_in: usize = k_in / (base2k * di);
let dnum_out: usize = k_out / (base2k * di); let dnum_apply: usize = k_in.div_ceil(base2k * di); - let auto_key_in_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let auto_key_in_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(),@@ -93,7 +55,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let auto_key_out_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let auto_key_out_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -102,7 +64,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let auto_key_apply_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let auto_key_apply_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_apply.into(),@@ -111,18 +73,18 @@ dsize: di.into(),
rank: rank.into(), }; - let mut auto_key_in: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_in_infos); - let mut auto_key_out: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_out_infos); - let mut auto_key_apply: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_apply_infos); + let mut auto_key_in: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&auto_key_in_infos); + let mut auto_key_out: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&auto_key_out_infos); + let mut auto_key_apply: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&auto_key_apply_infos); 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<B> = ScratchOwned::alloc( - GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key_in_infos) - | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key_apply_infos) - | GGLWEAutomorphismKey::automorphism_scratch_space( + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &auto_key_in_infos) + | GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &auto_key_apply_infos) + | GLWEAutomorphismKey::automorphism_tmp_bytes( module, &auto_key_out_infos, &auto_key_in_infos,@@ -130,7 +92,7 @@ &auto_key_apply_infos,
), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&auto_key_in); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&auto_key_in); sk.fill_ternary_prob(0.5, &mut source_xs); // gglwe_{s1}(s0) = s0 -> s1@@ -153,8 +115,8 @@ &mut source_xe,
scratch.borrow(), ); - let mut auto_key_apply_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = - GGLWEAutomorphismKeyPrepared::alloc(module, &auto_key_apply_infos); + let mut auto_key_apply_prepared: GLWEAutomorphismKeyPrepared<Vec<u8>, BE> = + GLWEAutomorphismKeyPrepared::alloc_from_infos(module, &auto_key_apply_infos); auto_key_apply_prepared.prepare(module, &auto_key_apply, scratch.borrow());@@ -166,9 +128,9 @@ &auto_key_apply_prepared,
scratch.borrow(), ); - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&auto_key_out_infos); + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&auto_key_out_infos); - let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(&auto_key_out_infos); + let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&auto_key_out_infos); sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk for i in 0..rank { module.vec_znx_automorphism(@@ -180,7 +142,8 @@ i,
); } - let sk_auto_dft: GLWESecretPrepared<Vec<u8>, B> = sk_auto.prepare_alloc(module, scratch.borrow()); + let mut sk_auto_dft: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk_auto); + sk_auto_dft.prepare(module, &sk_auto); (0..auto_key_out.rank_in().into()).for_each(|col_i| { (0..auto_key_out.dnum().into()).for_each(|row_i| {@@ -222,61 +185,18 @@ }
} #[allow(clippy::too_many_arguments)] -pub fn test_gglwe_automorphism_key_automorphism_inplace<B>(module: &Module<B>) +pub fn test_gglwe_automorphism_key_automorphism_inplace<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphism - + VecZnxSwitchRing - + VecZnxAddScalarInplace + Module<BE>: GLWEAutomorphismKeyEncryptSk<BE> + + GLWEAutomorphismKeyPreparedFactory<BE> + + GLWEAutomorphismKeyAutomorphism<BE> + VecZnxAutomorphism - + VecZnxAutomorphismInplace<B> - + VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes + + GaloisElement + VecZnxSubScalarInplace - + VecZnxCopy - + VmpPMatAlloc<B> - + VmpPrepare<B>, - B: Backend - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxDftImpl<B> - + TakeVecZnxImpl<B> - + TakeSvpPPolImpl<B> - + TakeVecZnxBigImpl<B>, + + GLWESecretPreparedFactory<BE> + + GLWEDecrypt<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_in: usize = 60;@@ -293,7 +213,7 @@
let dnum_in: usize = k_in / (base2k * di); let dnum_apply: usize = k_in.div_ceil(base2k * di); - let auto_key_layout: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let auto_key_layout: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(),@@ -302,7 +222,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let auto_key_apply_layout: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let auto_key_apply_layout: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_apply.into(),@@ -311,20 +231,20 @@ dsize: di.into(),
rank: rank.into(), }; - let mut auto_key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_layout); - let mut auto_key_apply: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_apply_layout); + let mut auto_key: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&auto_key_layout); + let mut auto_key_apply: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&auto_key_apply_layout); 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<B> = ScratchOwned::alloc( - GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key) - | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key_apply) - | GGLWEAutomorphismKey::automorphism_inplace_scratch_space(module, &auto_key, &auto_key_apply), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &auto_key) + | GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &auto_key_apply) + | GLWEAutomorphismKey::automorphism_tmp_bytes(module, &auto_key, &auto_key, &auto_key_apply), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&auto_key); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&auto_key); sk.fill_ternary_prob(0.5, &mut source_xs); // gglwe_{s1}(s0) = s0 -> s1@@ -347,17 +267,17 @@ &mut source_xe,
scratch.borrow(), ); - let mut auto_key_apply_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = - GGLWEAutomorphismKeyPrepared::alloc(module, &auto_key_apply_layout); + let mut auto_key_apply_prepared: GLWEAutomorphismKeyPrepared<Vec<u8>, BE> = + GLWEAutomorphismKeyPrepared::alloc_from_infos(module, &auto_key_apply_layout); auto_key_apply_prepared.prepare(module, &auto_key_apply, scratch.borrow()); // gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0) auto_key.automorphism_inplace(module, &auto_key_apply_prepared, scratch.borrow()); - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&auto_key); + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&auto_key); - let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(&auto_key); + let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&auto_key); sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk for i in 0..rank {@@ -370,7 +290,8 @@ i,
); } - let sk_auto_dft: GLWESecretPrepared<Vec<u8>, B> = sk_auto.prepare_alloc(module, scratch.borrow()); + let mut sk_auto_dft: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk_auto); + sk_auto_dft.prepare(module, &sk_auto); (0..auto_key.rank_in().into()).for_each(|col_i| { (0..auto_key.dnum().into()).for_each(|row_i| {
@@ -1,79 +1,33 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, - SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, - VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigNormalize, - VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAddInplace, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxDftCopy, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScalarZnx, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, VecZnxBigAllocBytesImpl, VecZnxDftAllocBytesImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAutomorphismInplace}, + layouts::{Backend, Module, ScalarZnx, Scratch, ScratchOwned}, source::Source, }; use crate::{ + GGSWAutomorphism, GGSWEncryptSk, GGSWNoise, GLWEAutomorphismKeyEncryptSk, GLWETensorKeyEncryptSk, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGLWEAutomorphismKey, GGLWETensorKey, GGLWETensorKeyLayout, GGSWCiphertext, GGSWCiphertextLayout, GLWESecret, - prepared::{GGLWEAutomorphismKeyPrepared, GGLWETensorKeyPrepared, GLWESecretPrepared, Prepare, PrepareAlloc}, + GGSW, GGSWLayout, GLWEAutomorphismKey, GLWEAutomorphismKeyPreparedFactory, GLWESecret, GLWESecretPreparedFactory, + GLWETensorKey, GLWETensorKeyLayout, GLWETensorKeyPreparedFactory, + prepared::{GLWEAutomorphismKeyPrepared, GLWESecretPrepared, GLWETensorKeyPrepared}, }, noise::noise_ggsw_keyswitch, }; -pub fn test_ggsw_automorphism<B>(module: &Module<B>) +pub fn test_ggsw_automorphism<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<B> - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxAddScalarInplace - + VecZnxCopy - + VecZnxSubInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftCopy<B> - + VecZnxDftAddInplace<B> - + VecZnxFillUniform - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpApplyDftToDft<B> - + VecZnxSwitchRing - + VecZnxAutomorphismInplace<B> - + VecZnxAutomorphism, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + Module<BE>: GGSWEncryptSk<BE> + + GLWEAutomorphismKeyEncryptSk<BE> + + GLWEAutomorphismKeyPreparedFactory<BE> + + GGSWAutomorphism<BE> + + GLWETensorKeyPreparedFactory<BE> + + GLWETensorKeyEncryptSk<BE> + + GLWESecretPreparedFactory<BE> + + VecZnxAutomorphismInplace<BE> + + GGSWNoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_in: usize = 54;@@ -92,7 +46,7 @@ let dnum_in: usize = k_in.div_euclid(base2k * di);
let dsize_in: usize = 1; - let ggsw_in_layout: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_in_layout: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(),@@ -101,7 +55,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let ggsw_out_layout: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_out_layout: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -110,7 +64,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let tensor_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout { + let tensor_key_layout: GLWETensorKeyLayout = GLWETensorKeyLayout { n: n.into(), base2k: base2k.into(), k: k_tsk.into(),@@ -119,7 +73,7 @@ dsize: di.into(),
rank: rank.into(), }; - let auto_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout { + let auto_key_layout: GLWETensorKeyLayout = GLWETensorKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -128,28 +82,30 @@ dsize: di.into(),
rank: rank.into(), }; - let mut ct_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_in_layout); - let mut ct_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_layout); - let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tensor_key_layout); - let mut auto_key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_layout); + let mut ct_in: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_in_layout); + let mut ct_out: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_out_layout); + let mut tensor_key: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc_from_infos(&tensor_key_layout); + let mut auto_key: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&auto_key_layout); let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 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 scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGSWCiphertext::encrypt_sk_scratch_space(module, &ct_in) - | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key) - | GGLWETensorKey::encrypt_sk_scratch_space(module, &tensor_key) - | GGSWCiphertext::automorphism_scratch_space(module, &ct_out, &ct_in, &auto_key, &tensor_key), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GGSW::encrypt_sk_tmp_bytes(module, &ct_in) + | GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &auto_key) + | GLWETensorKey::encrypt_sk_tmp_bytes(module, &tensor_key) + | GGSW::automorphism_tmp_bytes(module, &ct_out, &ct_in, &auto_key, &tensor_key), ); let var_xs: f64 = 0.5; - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ct_out); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&ct_out); sk.fill_ternary_prob(var_xs, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk); + sk_prepared.prepare(module, &sk); auto_key.encrypt_sk( module,@@ -178,11 +134,12 @@ &mut source_xe,
scratch.borrow(), ); - let mut auto_key_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = - GGLWEAutomorphismKeyPrepared::alloc(module, &auto_key_layout); + let mut auto_key_prepared: GLWEAutomorphismKeyPrepared<Vec<u8>, BE> = + GLWEAutomorphismKeyPrepared::alloc_from_infos(module, &auto_key_layout); auto_key_prepared.prepare(module, &auto_key, scratch.borrow()); - let mut tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = GGLWETensorKeyPrepared::alloc(module, &tensor_key_layout); + let mut tsk_prepared: GLWETensorKeyPrepared<Vec<u8>, BE> = + GLWETensorKeyPrepared::alloc_from_infos(module, &tensor_key_layout); tsk_prepared.prepare(module, &tensor_key, scratch.borrow()); ct_out.automorphism(@@ -217,56 +174,19 @@ }
} #[allow(clippy::too_many_arguments)] -pub fn test_ggsw_automorphism_inplace<B>(module: &Module<B>) +pub fn test_ggsw_automorphism_inplace<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<B> - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxAddScalarInplace - + VecZnxCopy - + VecZnxSubInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxDftCopy<B> - + VecZnxDftAddInplace<B> - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + VecZnxFillUniform - + SvpApplyDftToDft<B> - + VecZnxSwitchRing - + VecZnxAutomorphismInplace<B> - + VecZnxAutomorphism, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + Module<BE>: GGSWEncryptSk<BE> + + GLWEAutomorphismKeyEncryptSk<BE> + + GLWEAutomorphismKeyPreparedFactory<BE> + + GGSWAutomorphism<BE> + + GLWETensorKeyPreparedFactory<BE> + + GLWETensorKeyEncryptSk<BE> + + GLWESecretPreparedFactory<BE> + + VecZnxAutomorphismInplace<BE> + + GGSWNoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_out: usize = 54;@@ -282,7 +202,7 @@ let dnum: usize = k_out.div_ceil(di * base2k);
let dnum_in: usize = k_out.div_euclid(base2k * di); let dsize_in: usize = 1; - let ggsw_out_layout: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_out_layout: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -291,7 +211,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let tensor_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout { + let tensor_key_layout: GLWETensorKeyLayout = GLWETensorKeyLayout { n: n.into(), base2k: base2k.into(), k: k_tsk.into(),@@ -300,7 +220,7 @@ dsize: di.into(),
rank: rank.into(), }; - let auto_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout { + let auto_key_layout: GLWETensorKeyLayout = GLWETensorKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -309,27 +229,29 @@ dsize: di.into(),
rank: rank.into(), }; - let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_layout); - let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tensor_key_layout); - let mut auto_key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_layout); + let mut ct: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_out_layout); + let mut tensor_key: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc_from_infos(&tensor_key_layout); + let mut auto_key: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&auto_key_layout); let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 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 scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGSWCiphertext::encrypt_sk_scratch_space(module, &ct) - | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key) - | GGLWETensorKey::encrypt_sk_scratch_space(module, &tensor_key) - | GGSWCiphertext::automorphism_inplace_scratch_space(module, &ct, &auto_key, &tensor_key), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GGSW::encrypt_sk_tmp_bytes(module, &ct) + | GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &auto_key) + | GLWETensorKey::encrypt_sk_tmp_bytes(module, &tensor_key) + | GGSW::automorphism_tmp_bytes(module, &ct, &ct, &auto_key, &tensor_key), ); let var_xs: f64 = 0.5; - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ct); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&ct); sk.fill_ternary_prob(var_xs, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk); + sk_prepared.prepare(module, &sk); auto_key.encrypt_sk( module,@@ -358,11 +280,12 @@ &mut source_xe,
scratch.borrow(), ); - let mut auto_key_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = - GGLWEAutomorphismKeyPrepared::alloc(module, &auto_key_layout); + let mut auto_key_prepared: GLWEAutomorphismKeyPrepared<Vec<u8>, BE> = + GLWEAutomorphismKeyPrepared::alloc_from_infos(module, &auto_key_layout); auto_key_prepared.prepare(module, &auto_key, scratch.borrow()); - let mut tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = GGLWETensorKeyPrepared::alloc(module, &tensor_key_layout); + let mut tsk_prepared: GLWETensorKeyPrepared<Vec<u8>, BE> = + GLWETensorKeyPrepared::alloc_from_infos(module, &tensor_key_layout); tsk_prepared.prepare(module, &tensor_key, scratch.borrow()); ct.automorphism_inplace(module, &auto_key_prepared, &tsk_prepared, scratch.borrow());
@@ -1,69 +1,33 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, - VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAutomorphismInplace, VecZnxFillUniform}, + layouts::{Backend, Module, Scratch, ScratchOwned}, source::Source, }; use crate::{ + GLWEAutomorphism, GLWEAutomorphismKeyEncryptSk, GLWEDecrypt, GLWEEncryptSk, GLWENoise, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, - prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, Prepare, PrepareAlloc}, + GLWE, GLWEAutomorphismKey, GLWEAutomorphismKeyLayout, GLWEAutomorphismKeyPreparedFactory, GLWELayout, GLWEPlaintext, + GLWESecret, GLWESecretPreparedFactory, + prepared::{GLWEAutomorphismKeyPrepared, GLWESecretPrepared}, }, noise::log2_std_noise_gglwe_product, }; -pub fn test_glwe_automorphism<B>(module: &Module<B>) +pub fn test_glwe_automorphism<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes + Module<BE>: GLWEEncryptSk<BE> + + GLWESecretPreparedFactory<BE> + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxAutomorphism - + VecZnxSwitchRing - + VecZnxAddScalarInplace - + VecZnxAutomorphismInplace<B> - + VmpPMatAlloc<B> - + VmpPrepare<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + + GLWEDecrypt<BE> + + GLWEAutomorphism<BE> + + GLWEAutomorphismKeyEncryptSk<BE> + + GLWEAutomorphismKeyPreparedFactory<BE> + + GLWENoise<BE> + + VecZnxAutomorphismInplace<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_in: usize = 60;@@ -77,21 +41,21 @@
let n: usize = module.n(); let dnum: usize = k_in.div_ceil(base2k * dsize); - let ct_in_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let ct_in_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_in.into(), rank: rank.into(), }; - let ct_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let ct_out_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), rank: rank.into(), }; - let autokey_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let autokey_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -100,10 +64,10 @@ dnum: dnum.into(),
dsize: di.into(), }; - let mut autokey: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&autokey_infos); - let mut ct_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&ct_in_infos); - let mut ct_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&ct_out_infos); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ct_out_infos); + let mut autokey: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&autokey_infos); + let mut ct_in: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&ct_in_infos); + let mut ct_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&ct_out_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&ct_out_infos); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]);@@ -111,16 +75,18 @@ let mut source_xa: Source = Source::new([0u8; 32]);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &autokey) - | GLWECiphertext::decrypt_scratch_space(module, &ct_out) - | GLWECiphertext::encrypt_sk_scratch_space(module, &ct_in) - | GLWECiphertext::automorphism_scratch_space(module, &ct_out, &ct_in, &autokey), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &autokey) + | GLWE::decrypt_tmp_bytes(module, &ct_out) + | GLWE::encrypt_sk_tmp_bytes(module, &ct_in) + | GLWE::automorphism_tmp_bytes(module, &ct_out, &ct_in, &autokey), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ct_out); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&ct_out); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk); + sk_prepared.prepare(module, &sk); autokey.encrypt_sk( module,@@ -140,8 +106,8 @@ &mut source_xe,
scratch.borrow(), ); - let mut autokey_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = - GGLWEAutomorphismKeyPrepared::alloc(module, &autokey_infos); + let mut autokey_prepared: GLWEAutomorphismKeyPrepared<Vec<u8>, BE> = + GLWEAutomorphismKeyPrepared::alloc_from_infos(module, &autokey_infos); autokey_prepared.prepare(module, &autokey, scratch.borrow()); ct_out.automorphism(module, &ct_in, &autokey_prepared, scratch.borrow());@@ -167,46 +133,19 @@ }
} #[allow(clippy::too_many_arguments)] -pub fn test_glwe_automorphism_inplace<B>(module: &Module<B>) +pub fn test_glwe_automorphism_inplace<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes + Module<BE>: GLWEEncryptSk<BE> + + GLWESecretPreparedFactory<BE> + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxAutomorphism - + VecZnxSwitchRing - + VecZnxAddScalarInplace - + VecZnxAutomorphismInplace<B> - + VmpPMatAlloc<B> - + VmpPrepare<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + + GLWEDecrypt<BE> + + GLWEAutomorphism<BE> + + GLWEAutomorphismKeyEncryptSk<BE> + + GLWEAutomorphismKeyPreparedFactory<BE> + + GLWENoise<BE> + + VecZnxAutomorphismInplace<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_out: usize = 60;@@ -219,14 +158,14 @@
let n: usize = module.n(); let dnum: usize = k_out.div_ceil(base2k * dsize); - let ct_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let ct_out_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), rank: rank.into(), }; - let autokey_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let autokey_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -235,9 +174,9 @@ dnum: dnum.into(),
dsize: di.into(), }; - let mut autokey: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&autokey_infos); - let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&ct_out_infos); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ct_out_infos); + let mut autokey: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&autokey_infos); + let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&ct_out_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&ct_out_infos); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]);@@ -245,16 +184,18 @@ let mut source_xa: Source = Source::new([0u8; 32]);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &autokey) - | GLWECiphertext::decrypt_scratch_space(module, &ct) - | GLWECiphertext::encrypt_sk_scratch_space(module, &ct) - | GLWECiphertext::automorphism_inplace_scratch_space(module, &ct, &autokey), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &autokey) + | GLWE::decrypt_tmp_bytes(module, &ct) + | GLWE::encrypt_sk_tmp_bytes(module, &ct) + | GLWE::automorphism_tmp_bytes(module, &ct, &ct, &autokey), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ct); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&ct); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk); + sk_prepared.prepare(module, &sk); autokey.encrypt_sk( module,@@ -274,8 +215,8 @@ &mut source_xe,
scratch.borrow(), ); - let mut autokey_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = - GGLWEAutomorphismKeyPrepared::alloc(module, &autokey); + let mut autokey_prepared: GLWEAutomorphismKeyPrepared<Vec<u8>, BE> = + GLWEAutomorphismKeyPrepared::alloc_from_infos(module, &autokey); autokey_prepared.prepare(module, &autokey, scratch.borrow()); ct.automorphism_inplace(module, &autokey_prepared, scratch.borrow());
@@ -1,69 +1,30 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphismInplace, VecZnxBigAddInplace, - VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAllocBytes, - VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, ZnAddNormal, ZnFillUniform, ZnNormalizeInplace, - }, - layouts::{Backend, Module, ScratchOwned, ZnxView}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow}, + layouts::{Backend, Module, Scratch, ScratchOwned, ZnxView}, source::Source, }; -use crate::layouts::{ - Base2K, Degree, Dnum, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, GLWEToLWEKey, GLWEToLWEKeyLayout, - LWECiphertext, LWECiphertextLayout, LWEPlaintext, LWESecret, LWEToGLWESwitchingKey, LWEToGLWESwitchingKeyLayout, Rank, - TorusPrecision, - prepared::{GLWESecretPrepared, GLWEToLWESwitchingKeyPrepared, LWEToGLWESwitchingKeyPrepared, PrepareAlloc}, +use crate::{ + GLWEDecrypt, GLWEEncryptSk, GLWEFromLWE, GLWEToLWESwitchingKeyEncryptSk, LWEDecrypt, LWEEncryptSk, + LWEToGLWESwitchingKeyEncryptSk, ScratchTakeCore, + layouts::{ + Base2K, Degree, Dnum, GLWE, GLWELayout, GLWEPlaintext, GLWESecret, GLWESecretPreparedFactory, GLWEToLWEKeyLayout, + GLWEToLWESwitchingKey, GLWEToLWESwitchingKeyPreparedFactory, LWE, LWELayout, LWEPlaintext, LWESecret, + LWEToGLWESwitchingKey, LWEToGLWESwitchingKeyLayout, LWEToGLWESwitchingKeyPreparedFactory, Rank, TorusPrecision, + prepared::{GLWESecretPrepared, GLWEToLWESwitchingKeyPrepared, LWEToGLWESwitchingKeyPrepared}, + }, }; -pub fn test_lwe_to_glwe<B>(module: &Module<B>) +pub fn test_lwe_to_glwe<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxAutomorphismInplace<B> - + ZnNormalizeInplace<B> - + ZnFillUniform - + ZnAddNormal, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: GLWEFromLWE<BE> + + LWEToGLWESwitchingKeyEncryptSk<BE> + + GLWEDecrypt<BE> + + GLWESecretPreparedFactory<BE> + + LWEEncryptSk<BE> + + LWEToGLWESwitchingKeyPreparedFactory<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let n_glwe: Degree = Degree(module.n() as u32); let n_lwe: Degree = Degree(22);@@ -83,104 +44,79 @@ dnum: Dnum(2),
rank_out: rank, }; - let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_infos: GLWELayout = GLWELayout { n: n_glwe, base2k: Base2K(17), k: TorusPrecision(34), rank, }; - let lwe_infos: LWECiphertextLayout = LWECiphertextLayout { + let lwe_infos: LWELayout = LWELayout { n: n_lwe, base2k: Base2K(17), k: TorusPrecision(34), }; - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - LWEToGLWESwitchingKey::encrypt_sk_scratch_space(module, &lwe_to_glwe_infos) - | GLWECiphertext::from_lwe_scratch_space(module, &glwe_infos, &lwe_infos, &lwe_to_glwe_infos) - | GLWECiphertext::decrypt_scratch_space(module, &glwe_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + LWEToGLWESwitchingKey::encrypt_sk_tmp_bytes(module, &lwe_to_glwe_infos) + | GLWE::from_lwe_tmp_bytes(module, &glwe_infos, &lwe_infos, &lwe_to_glwe_infos) + | GLWE::decrypt_tmp_bytes(module, &glwe_infos), ); - let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos); + let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos); sk_glwe.fill_ternary_prob(0.5, &mut source_xs); - let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow()); + let mut sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk_glwe); + sk_glwe_prepared.prepare(module, &sk_glwe); let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe); sk_lwe.fill_ternary_prob(0.5, &mut source_xs); let data: i64 = 17; - let mut lwe_pt: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(&lwe_infos); + let mut lwe_pt: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_from_infos(&lwe_infos); lwe_pt.encode_i64(data, k_lwe_pt); - let mut lwe_ct: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos); + let mut lwe_ct: LWE<Vec<u8>> = LWE::alloc_from_infos(&lwe_infos); lwe_ct.encrypt_sk(module, &lwe_pt, &sk_lwe, &mut source_xa, &mut source_xe); - let mut ksk: LWEToGLWESwitchingKey<Vec<u8>> = LWEToGLWESwitchingKey::alloc(&lwe_to_glwe_infos); + let mut ksk: LWEToGLWESwitchingKey<Vec<u8>> = LWEToGLWESwitchingKey::alloc_from_infos(&lwe_to_glwe_infos); ksk.encrypt_sk( module, &sk_lwe, - &sk_glwe, + &sk_glwe_prepared, &mut source_xa, &mut source_xe, scratch.borrow(), ); - let mut glwe_ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos); + let mut glwe_ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos); - let ksk_prepared: LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow()); + let mut ksk_prepared: LWEToGLWESwitchingKeyPrepared<Vec<u8>, BE> = + LWEToGLWESwitchingKeyPrepared::alloc_from_infos(module, &ksk); + ksk_prepared.prepare(module, &ksk, scratch.borrow()); glwe_ct.from_lwe(module, &lwe_ct, &ksk_prepared, scratch.borrow()); - let mut glwe_pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos); + let mut glwe_pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos); glwe_ct.decrypt(module, &mut glwe_pt, &sk_glwe_prepared, scratch.borrow()); assert_eq!(glwe_pt.data.at(0, 0)[0], lwe_pt.data.at(0, 0)[0]); } -pub fn test_glwe_to_lwe<B>(module: &Module<B>) +pub fn test_glwe_to_lwe<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxAutomorphismInplace<B> - + ZnNormalizeInplace<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: GLWEFromLWE<BE> + + GLWEToLWESwitchingKeyEncryptSk<BE> + + GLWEEncryptSk<BE> + + LWEDecrypt<BE> + + GLWEDecrypt<BE> + + GLWESecretPreparedFactory<BE> + + GLWEToLWESwitchingKeyEncryptSk<BE> + + GLWEToLWESwitchingKeyPreparedFactory<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let n_glwe: Degree = Degree(module.n() as u32); let n_lwe: Degree = Degree(22);@@ -196,14 +132,14 @@ dnum: Dnum(2),
rank_in: rank, }; - let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_infos: GLWELayout = GLWELayout { n: n_glwe, base2k: Base2K(17), k: TorusPrecision(34), rank, }; - let lwe_infos: LWECiphertextLayout = LWECiphertextLayout { + let lwe_infos: LWELayout = LWELayout { n: n_lwe, base2k: Base2K(17), k: TorusPrecision(34),@@ -213,25 +149,26 @@ let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GLWEToLWEKey::encrypt_sk_scratch_space(module, &glwe_to_lwe_infos) - | LWECiphertext::from_glwe_scratch_space(module, &lwe_infos, &glwe_infos, &glwe_to_lwe_infos) - | GLWECiphertext::decrypt_scratch_space(module, &glwe_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWEToLWESwitchingKey::encrypt_sk_tmp_bytes(module, &glwe_to_lwe_infos) + | LWE::from_glwe_tmp_bytes(module, &lwe_infos, &glwe_infos, &glwe_to_lwe_infos) + | GLWE::decrypt_tmp_bytes(module, &glwe_infos), ); - let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos); + let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos); sk_glwe.fill_ternary_prob(0.5, &mut source_xs); - let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow()); + let mut sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk_glwe); + sk_glwe_prepared.prepare(module, &sk_glwe); let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe); sk_lwe.fill_ternary_prob(0.5, &mut source_xs); let data: i64 = 17; - let mut glwe_pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos); + let mut glwe_pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos); glwe_pt.encode_coeff_i64(data, k_lwe_pt, 0); - let mut glwe_ct = GLWECiphertext::alloc(&glwe_infos); + let mut glwe_ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos); glwe_ct.encrypt_sk( module, &glwe_pt,@@ -241,7 +178,7 @@ &mut source_xe,
scratch.borrow(), ); - let mut ksk: GLWEToLWEKey<Vec<u8>> = GLWEToLWEKey::alloc(&glwe_to_lwe_infos); + let mut ksk: GLWEToLWESwitchingKey<Vec<u8>> = GLWEToLWESwitchingKey::alloc_from_infos(&glwe_to_lwe_infos); ksk.encrypt_sk( module,@@ -252,13 +189,15 @@ &mut source_xe,
scratch.borrow(), ); - let mut lwe_ct: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos); + let mut lwe_ct: LWE<Vec<u8>> = LWE::alloc_from_infos(&lwe_infos); - let ksk_prepared: GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow()); + let mut ksk_prepared: GLWEToLWESwitchingKeyPrepared<Vec<u8>, BE> = + GLWEToLWESwitchingKeyPrepared::alloc_from_infos(module, &ksk); + ksk_prepared.prepare(module, &ksk, scratch.borrow()); lwe_ct.from_glwe(module, &glwe_ct, &ksk_prepared, scratch.borrow()); - let mut lwe_pt: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(&lwe_infos); + let mut lwe_pt: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_from_infos(&lwe_infos); lwe_ct.decrypt(module, &mut lwe_pt, &sk_lwe); assert_eq!(glwe_pt.data.at(0, 0)[0], lwe_pt.data.at(0, 0)[0]);
@@ -1,71 +1,34 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, - VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, - VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, - VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSubScalarInplace, VecZnxSwitchRing, - VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxAutomorphism, VecZnxFillUniform}, + layouts::{Backend, GaloisElement, Module, Scratch, ScratchOwned}, source::Source, }; use crate::{ + GGLWEKeyswitch, GLWEAutomorphismKeyCompressedEncryptSk, GLWEAutomorphismKeyEncryptSk, GLWESwitchingKeyCompressedEncryptSk, + GLWESwitchingKeyEncryptSk, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GLWEInfos, GLWESecret, - compressed::{Decompress, GGLWEAutomorphismKeyCompressed}, - prepared::{GLWESecretPrepared, PrepareAlloc}, + AutomorphismKeyDecompress, GLWEAutomorphismKey, GLWEAutomorphismKeyLayout, GLWEInfos, GLWESecret, + GLWESecretPreparedFactory, GLWESwitchingKeyDecompress, compressed::GLWEAutomorphismKeyCompressed, + prepared::GLWESecretPrepared, }, + noise::GGLWENoise, }; -pub fn test_gglwe_automorphisk_key_encrypt_sk<B>(module: &Module<B>) +pub fn test_gglwe_automorphism_key_encrypt_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes + Module<BE>: GLWEAutomorphismKeyEncryptSk<BE> + + GGLWEKeyswitch<BE> + + GLWESecretPreparedFactory<BE> + + GLWESwitchingKeyEncryptSk<BE> + + GLWESwitchingKeyCompressedEncryptSk<BE> + + GLWESwitchingKeyDecompress + + GGLWENoise<BE> + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxAutomorphism - + VecZnxSwitchRing - + VecZnxAddScalarInplace - + VecZnxAutomorphismInplace<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxSubScalarInplace - + VecZnxCopy - + VmpPMatAlloc<B> - + VmpPrepare<B>, - B: Backend - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxDftImpl<B> - + TakeVecZnxImpl<B> - + TakeSvpPPolImpl<B> - + TakeVecZnxBigImpl<B>, + + VecZnxAutomorphism, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_ksk: usize = 60;@@ -75,7 +38,7 @@ for di in 1..dsize + 1 {
let n: usize = module.n(); let dnum: usize = (k_ksk - di * base2k) / (di * base2k); - let atk_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let atk_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -84,17 +47,17 @@ dsize: di.into(),
rank: rank.into(), }; - let mut atk: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&atk_infos); + let mut atk: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&atk_infos); 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<B> = ScratchOwned::alloc(GGLWEAutomorphismKey::encrypt_sk_scratch_space( + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(GLWEAutomorphismKey::encrypt_sk_tmp_bytes( module, &atk_infos, )); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&atk_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&atk_infos); sk.fill_ternary_prob(0.5, &mut source_xs); let p = -5;@@ -118,57 +81,28 @@ &sk.data.as_vec_znx(),
i, ); }); - let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow()); + let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, sk_out.rank()); + sk_out_prepared.prepare(module, &sk_out); atk.key - .key .assert_noise(module, &sk_out_prepared, &sk.data, SIGMA); } } } -pub fn test_gglwe_automorphisk_key_compressed_encrypt_sk<B>(module: &Module<B>) +pub fn test_gglwe_automorphism_key_compressed_encrypt_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigAddSmallInplace<B> + Module<BE>: GLWEAutomorphismKeyCompressedEncryptSk<BE> + + GGLWEKeyswitch<BE> + + GLWESecretPreparedFactory<BE> + + GLWESwitchingKeyEncryptSk<BE> + + GLWESwitchingKeyCompressedEncryptSk<BE> + + AutomorphismKeyDecompress + VecZnxAutomorphism - + VecZnxSwitchRing - + VecZnxAddScalarInplace - + VecZnxAutomorphismInplace<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxSubScalarInplace - + VecZnxCopy - + VmpPMatAlloc<B> - + VmpPrepare<B>, - B: Backend - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxDftImpl<B> - + TakeVecZnxImpl<B> - + TakeSvpPPolImpl<B> - + TakeVecZnxBigImpl<B>, + + VecZnxFillUniform + + GGLWENoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_ksk: usize = 60;@@ -178,7 +112,7 @@ for di in 1..dsize + 1 {
let n: usize = module.n(); let dnum: usize = (k_ksk - di * base2k) / (di * base2k); - let atk_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let atk_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -187,16 +121,17 @@ dsize: di.into(),
rank: rank.into(), }; - let mut atk_compressed: GGLWEAutomorphismKeyCompressed<Vec<u8>> = GGLWEAutomorphismKeyCompressed::alloc(&atk_infos); + let mut atk_compressed: GLWEAutomorphismKeyCompressed<Vec<u8>> = + GLWEAutomorphismKeyCompressed::alloc_from_infos(&atk_infos); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGLWEAutomorphismKey::encrypt_sk_scratch_space( + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(GLWEAutomorphismKeyCompressed::encrypt_sk_tmp_bytes( module, &atk_infos, )); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&atk_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&atk_infos); sk.fill_ternary_prob(0.5, &mut source_xs); let p = -5;@@ -215,13 +150,13 @@ &sk.data.as_vec_znx(),
i, ); }); - let sk_out_prepared = sk_out.prepare_alloc(module, scratch.borrow()); + let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, sk_out.rank()); + sk_out_prepared.prepare(module, &sk_out); - let mut atk: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&atk_infos); + let mut atk: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&atk_infos); atk.decompress(module, &atk_compressed); atk.key - .key .assert_noise(module, &sk_out_prepared, &sk.data, SIGMA); } }
@@ -1,77 +1,44 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, - VecZnxSubScalarInplace, VecZnxSwitchRing, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, VecZnxBigAllocBytesImpl, VecZnxDftAllocBytesImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform}, + layouts::{Backend, Module, Scratch, ScratchOwned}, source::Source, }; use crate::{ + GGLWEEncryptSk, GGLWEKeyswitch, GLWESwitchingKeyCompressedEncryptSk, GLWESwitchingKeyEncryptSk, ScratchTakeCore, + decryption::GLWEDecrypt, encryption::SIGMA, layouts::{ - GGLWECiphertextLayout, GGLWESwitchingKey, GLWESecret, - compressed::{Decompress, GGLWESwitchingKeyCompressed}, - prepared::{GLWESecretPrepared, PrepareAlloc}, + GGLWELayout, GLWESecret, GLWESecretPreparedFactory, GLWESwitchingKey, GLWESwitchingKeyCompressed, + GLWESwitchingKeyDecompress, + prepared::{GGLWEPreparedFactory, GLWESecretPrepared}, }, + noise::GGLWENoise, }; -pub fn test_gglwe_switching_key_encrypt_sk<B>(module: &Module<B>) +pub fn test_gglwe_switching_key_encrypt_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes + Module<BE>: GGLWEEncryptSk<BE> + + GGLWEPreparedFactory<BE> + + GGLWEKeyswitch<BE> + + GLWEDecrypt<BE> + + GLWESecretPreparedFactory<BE> + + GLWESwitchingKeyEncryptSk<BE> + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxSwitchRing - + VecZnxAddScalarInplace - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxSubScalarInplace - + VecZnxCopy - + VmpPMatAlloc<B> - + VmpPrepare<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + + GGLWENoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { + let n: usize = module.n(); let base2k: usize = 12; let k_ksk: usize = 54; let dsize: usize = k_ksk / base2k; for rank_in in 1_usize..3 { for rank_out in 1_usize..3 { for di in 1_usize..dsize + 1 { - let n: usize = module.n(); let dnum: usize = (k_ksk - di * base2k) / (di * base2k); - let gglwe_infos: GGLWECiphertextLayout = GGLWECiphertextLayout { + let gglwe_infos: GGLWELayout = GGLWELayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -81,23 +48,22 @@ rank_in: rank_in.into(),
rank_out: rank_out.into(), }; - let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_infos); + let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_infos); 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<B> = ScratchOwned::alloc(GGLWESwitchingKey::encrypt_sk_scratch_space( - module, - &gglwe_infos, - )); + let mut scratch: ScratchOwned<BE> = + ScratchOwned::alloc(GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_infos)); - let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into()); + let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into()); sk_in.fill_ternary_prob(0.5, &mut source_xs); - let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into()); + let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into()); sk_out.fill_ternary_prob(0.5, &mut source_xs); - let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow()); + let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into()); + sk_out_prepared.prepare(module, &sk_out); ksk.encrypt_sk( module,@@ -115,55 +81,31 @@ }
} } -pub fn test_gglwe_switching_key_compressed_encrypt_sk<B>(module: &Module<B>) +pub fn test_gglwe_switching_key_compressed_encrypt_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxSwitchRing - + VecZnxAddScalarInplace - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxSubScalarInplace - + VecZnxCopy - + VmpPMatAlloc<B> - + VmpPrepare<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + Module<BE>: GGLWEEncryptSk<BE> + + GGLWEPreparedFactory<BE> + + GGLWEKeyswitch<BE> + + GLWEDecrypt<BE> + + GLWESecretPreparedFactory<BE> + + GLWESwitchingKeyEncryptSk<BE> + + GLWESwitchingKeyCompressedEncryptSk<BE> + + GLWESwitchingKeyDecompress + + GGLWENoise<BE> + + VecZnxFillUniform, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { + let n: usize = module.n(); let base2k: usize = 12; let k_ksk: usize = 54; let dsize: usize = k_ksk / base2k; for rank_in in 1_usize..3 { for rank_out in 1_usize..3 { for di in 1_usize..dsize + 1 { - let n: usize = module.n(); let dnum: usize = (k_ksk - di * base2k) / (di * base2k); - let gglwe_infos: GGLWECiphertextLayout = GGLWECiphertextLayout { + let gglwe_infos: GGLWELayout = GGLWELayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -173,22 +115,24 @@ rank_in: rank_in.into(),
rank_out: rank_out.into(), }; - let mut ksk_compressed: GGLWESwitchingKeyCompressed<Vec<u8>> = GGLWESwitchingKeyCompressed::alloc(&gglwe_infos); + let mut ksk_compressed: GLWESwitchingKeyCompressed<Vec<u8>> = + GLWESwitchingKeyCompressed::alloc_from_infos(&gglwe_infos); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGLWESwitchingKeyCompressed::encrypt_sk_scratch_space( + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(GLWESwitchingKeyCompressed::encrypt_sk_tmp_bytes( module, &gglwe_infos, )); - let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into()); + let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into()); sk_in.fill_ternary_prob(0.5, &mut source_xs); - let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into()); + let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into()); sk_out.fill_ternary_prob(0.5, &mut source_xs); - let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow()); + let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into()); + sk_out_prepared.prepare(module, &sk_out); let seed_xa = [1u8; 32];@@ -201,7 +145,7 @@ &mut source_xe,
scratch.borrow(), ); - let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_infos); + let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_infos); ksk.decompress(module, &ksk_compressed); ksk.key
@@ -1,69 +1,23 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAlloc, VecZnxDftAllocBytes, - VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScalarZnx, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, VecZnxBigAllocBytesImpl, VecZnxDftAllocBytesImpl, - }, + api::{ScratchOwnedAlloc, ScratchOwnedBorrow}, + layouts::{Backend, Module, ScalarZnx, Scratch, ScratchOwned}, source::Source, }; use crate::{ + GGSWCompressedEncryptSk, GGSWEncryptSk, GGSWNoise, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGSWCiphertext, GGSWCiphertextLayout, GLWESecret, - compressed::{Decompress, GGSWCiphertextCompressed}, - prepared::{GLWESecretPrepared, PrepareAlloc}, + GGSW, GGSWDecompress, GGSWLayout, GLWESecret, GLWESecretPreparedFactory, compressed::GGSWCompressed, + prepared::GLWESecretPrepared, }, }; -pub fn test_ggsw_encrypt_sk<B>(module: &Module<B>) +pub fn test_ggsw_encrypt_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxAddScalarInplace - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxCopy - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + Module<BE>: GGSWEncryptSk<BE> + GLWESecretPreparedFactory<BE> + GGSWNoise<BE>, { let base2k: usize = 12; let k: usize = 54;@@ -73,7 +27,7 @@ for di in 1..dsize + 1 {
let n: usize = module.n(); let dnum: usize = (k - di * base2k) / (di * base2k); - let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k.into(),@@ -82,7 +36,7 @@ dsize: di.into(),
rank: rank.into(), }; - let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos); + let mut ct: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_infos); let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);@@ -92,14 +46,13 @@ let mut source_xa: Source = Source::new([0u8; 32]);
pt_scalar.fill_ternary_hw(0, n, &mut source_xs); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGSWCiphertext::encrypt_sk_scratch_space( - module, - &ggsw_infos, - )); + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(GGSW::encrypt_sk_tmp_bytes(module, &ggsw_infos)); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ggsw_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&ggsw_infos); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); ct.encrypt_sk( module,@@ -117,46 +70,11 @@ }
} } -pub fn test_ggsw_compressed_encrypt_sk<B>(module: &Module<B>) +pub fn test_ggsw_compressed_encrypt_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxAddScalarInplace - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxCopy - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + Module<BE>: GGSWCompressedEncryptSk<BE> + GLWESecretPreparedFactory<BE> + GGSWNoise<BE> + GGSWDecompress, { let base2k: usize = 12; let k: usize = 54;@@ -166,7 +84,7 @@ for di in 1..dsize + 1 {
let n: usize = module.n(); let dnum: usize = (k - di * base2k) / (di * base2k); - let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k.into(),@@ -175,7 +93,7 @@ dsize: di.into(),
rank: rank.into(), }; - let mut ct_compressed: GGSWCiphertextCompressed<Vec<u8>> = GGSWCiphertextCompressed::alloc(&ggsw_infos); + let mut ct_compressed: GGSWCompressed<Vec<u8>> = GGSWCompressed::alloc_from_infos(&ggsw_infos); let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);@@ -184,14 +102,13 @@ let mut source_xe: Source = Source::new([0u8; 32]);
pt_scalar.fill_ternary_hw(0, n, &mut source_xs); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGSWCiphertextCompressed::encrypt_sk_scratch_space( - module, - &ggsw_infos, - )); + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(GGSWCompressed::encrypt_sk_tmp_bytes(module, &ggsw_infos)); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ggsw_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&ggsw_infos); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); let seed_xa: [u8; 32] = [1u8; 32];@@ -206,7 +123,7 @@ );
let noise_f = |_col_i: usize| -(k as f64) + SIGMA.log2() + 0.5; - let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos); + let mut ct: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_infos); ct.decompress(module, &ct_compressed); ct.assert_noise(module, &sk_prepared, &pt_scalar, noise_f);
@@ -1,61 +1,26 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, - SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxBigAddInplace, VecZnxBigAddNormal, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxCopy, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, - VecZnxSubInplace, - }, - layouts::{Backend, Module, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform}, + layouts::{Backend, Module, Scratch, ScratchOwned}, source::Source, }; use crate::{ + GLWECompressedEncryptSk, GLWEEncryptPk, GLWEEncryptSk, GLWEPublicKeyGenerate, GLWESub, ScratchTakeCore, + decryption::GLWEDecrypt, encryption::SIGMA, layouts::{ - GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWEPlaintextLayout, GLWEPublicKey, GLWESecret, LWEInfos, - compressed::{Decompress, GLWECiphertextCompressed}, - prepared::{GLWEPublicKeyPrepared, GLWESecretPrepared, PrepareAlloc}, + GLWE, GLWELayout, GLWEPlaintext, GLWEPlaintextLayout, GLWEPublicKey, GLWEPublicKeyPreparedFactory, GLWESecret, + GLWESecretPreparedFactory, LWEInfos, + compressed::GLWECompressed, + prepared::{GLWEPublicKeyPrepared, GLWESecretPrepared}, }, - operations::GLWEOperations, }; -pub fn test_glwe_encrypt_sk<B>(module: &Module<B>) +pub fn test_glwe_encrypt_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + SvpApplyDftToDft<B> - + VecZnxBigAddNormal<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: GLWEEncryptSk<BE> + GLWEDecrypt<BE> + GLWESecretPreparedFactory<BE> + VecZnxFillUniform + GLWESub, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 8; let k_ct: usize = 54;@@ -64,7 +29,7 @@
for rank in 1_usize..3 { let n: usize = module.n(); - let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_ct.into(),@@ -77,22 +42,22 @@ base2k: base2k.into(),
k: k_pt.into(), }; - let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&pt_infos); - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&pt_infos); + let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&pt_infos); + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&pt_infos); 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<B> = ScratchOwned::alloc( - GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_infos) - | GLWECiphertext::decrypt_scratch_space(module, &glwe_infos), - ); + let mut scratch: ScratchOwned<BE> = + ScratchOwned::alloc(GLWE::encrypt_sk_tmp_bytes(module, &glwe_infos) | GLWE::decrypt_tmp_bytes(module, &glwe_infos)); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);@@ -107,7 +72,7 @@ );
ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow()); - pt_want.sub_inplace_ab(module, &pt_have); + module.glwe_sub_inplace(&mut pt_want, &pt_have); let noise_have: f64 = pt_want.data.std(base2k, 0) * (ct.k().as_u32() as f64).exp2(); let noise_want: f64 = SIGMA;@@ -116,48 +81,21 @@ assert!(noise_have <= noise_want + 0.2);
} } -pub fn test_glwe_compressed_encrypt_sk<B>(module: &Module<B>) +pub fn test_glwe_compressed_encrypt_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + SvpApplyDftToDft<B> - + VecZnxBigAddNormal<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + VecZnxCopy, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: GLWECompressedEncryptSk<BE> + GLWEDecrypt<BE> + GLWESecretPreparedFactory<BE> + VecZnxFillUniform + GLWESub, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 8; let k_ct: usize = 54; let k_pt: usize = 30; for rank in 1_usize..3 { + // println!("rank: {}", rank); let n: usize = module.n(); - let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_ct.into(),@@ -170,23 +108,24 @@ base2k: base2k.into(),
k: k_pt.into(), }; - let mut ct_compressed: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(&glwe_infos); + let mut ct_compressed: GLWECompressed<Vec<u8>> = GLWECompressed::alloc_from_infos(&glwe_infos); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&pt_infos); - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&pt_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&pt_infos); + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&pt_infos); 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<B> = ScratchOwned::alloc( - GLWECiphertextCompressed::encrypt_sk_scratch_space(module, &glwe_infos) - | GLWECiphertext::decrypt_scratch_space(module, &glwe_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWECompressed::encrypt_sk_tmp_bytes(module, &glwe_infos) | GLWE::decrypt_tmp_bytes(module, &glwe_infos), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);@@ -201,12 +140,12 @@ &mut source_xe,
scratch.borrow(), ); - let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos); + let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos); ct.decompress(module, &ct_compressed); ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow()); - pt_want.sub_inplace_ab(module, &pt_have); + module.glwe_sub_inplace(&mut pt_want, &pt_have); let noise_have: f64 = pt_want.data.std(base2k, 0) * (ct.k().as_u32() as f64).exp2(); let noise_want: f64 = SIGMA;@@ -219,38 +158,11 @@ );
} } -pub fn test_glwe_encrypt_zero_sk<B>(module: &Module<B>) +pub fn test_glwe_encrypt_zero_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + SvpApplyDftToDft<B> - + VecZnxBigAddNormal<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: GLWEEncryptSk<BE> + GLWEDecrypt<BE> + GLWESecretPreparedFactory<BE> + VecZnxFillUniform + GLWESub, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 8; let k_ct: usize = 54;@@ -258,29 +170,29 @@
for rank in 1_usize..3 { let n: usize = module.n(); - let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_ct.into(), rank: rank.into(), }; - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos); + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos); 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 scratch: ScratchOwned<B> = ScratchOwned::alloc( - GLWECiphertext::decrypt_scratch_space(module, &glwe_infos) - | GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_infos), - ); + let mut scratch: ScratchOwned<BE> = + ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, &glwe_infos) | GLWE::encrypt_sk_tmp_bytes(module, &glwe_infos)); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); - let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos); + let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos); ct.encrypt_zero_sk( module,@@ -295,40 +207,17 @@ assert!((SIGMA - pt.data.std(base2k, 0) * (k_ct as f64).exp2()) <= 0.2);
} } -pub fn test_glwe_encrypt_pk<B>(module: &Module<B>) +pub fn test_glwe_encrypt_pk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes + Module<BE>: GLWEEncryptPk<BE> + + GLWEPublicKeyPreparedFactory<BE> + + GLWEPublicKeyGenerate<BE> + + GLWEDecrypt<BE> + + GLWESecretPreparedFactory<BE> + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxCopy - + VecZnxDftAlloc<B> - + SvpApplyDftToDft<B> - + VecZnxBigAddNormal<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + + GLWESub, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 8; let k_ct: usize = 54;@@ -336,38 +225,38 @@
for rank in 1_usize..3 { let n: usize = module.n(); - let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_ct.into(), rank: rank.into(), }; - let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos); - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos); + let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos); + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos); 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 scratch: ScratchOwned<B> = ScratchOwned::alloc( - GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_infos) - | GLWECiphertext::decrypt_scratch_space(module, &glwe_infos) - | GLWECiphertext::encrypt_pk_scratch_space(module, &glwe_infos), - ); + let mut scratch: ScratchOwned<BE> = + ScratchOwned::alloc(GLWE::decrypt_tmp_bytes(module, &glwe_infos) | GLWE::encrypt_pk_tmp_bytes(module, &glwe_infos)); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); - let mut pk: GLWEPublicKey<Vec<u8>> = GLWEPublicKey::alloc(&glwe_infos); - pk.generate_from_sk(module, &sk_prepared, &mut source_xa, &mut source_xe); + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); + + let mut pk: GLWEPublicKey<Vec<u8>> = GLWEPublicKey::alloc_from_infos(&glwe_infos); + pk.generate(module, &sk_prepared, &mut source_xa, &mut source_xe); module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa); - let pk_prepared: GLWEPublicKeyPrepared<Vec<u8>, B> = pk.prepare_alloc(module, scratch.borrow()); + let mut pk_prepared: GLWEPublicKeyPrepared<Vec<u8>, BE> = GLWEPublicKeyPrepared::alloc_from_infos(module, &glwe_infos); + pk_prepared.prepare(module, &pk); ct.encrypt_pk( module,@@ -380,7 +269,7 @@ );
ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow()); - pt_want.sub_inplace_ab(module, &pt_have); + module.glwe_sub_inplace(&mut pt_want, &pt_have); let noise_have: f64 = pt_want.data.std(base2k, 0).log2(); let noise_want: f64 = ((((rank as f64) + 1.0) * n as f64 * 0.5 * SIGMA * SIGMA).sqrt()).log2() - (k_ct as f64);
@@ -1,68 +1,37 @@
use poulpy_hal::{ api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, - SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxCopy, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSubScalarInplace, VecZnxSwitchRing, - }, - layouts::{Backend, Module, ScratchOwned, VecZnxDft}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, VecZnxBigAllocBytesImpl, VecZnxDftAllocBytesImpl, + ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, VecZnxBigAlloc, VecZnxBigNormalize, + VecZnxCopy, VecZnxDftAlloc, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyTmpA, VecZnxSubScalarInplace, + VecZnxSwitchRing, }, + layouts::{Backend, Module, Scratch, ScratchOwned, VecZnxBig, VecZnxDft}, source::Source, }; use crate::{ + GLWETensorKeyCompressedEncryptSk, GLWETensorKeyEncryptSk, ScratchTakeCore, + decryption::GLWEDecrypt, encryption::SIGMA, layouts::{ - Dsize, GGLWETensorKey, GGLWETensorKeyLayout, GLWEPlaintext, GLWESecret, - compressed::{Decompress, GGLWETensorKeyCompressed}, - prepared::{GLWESecretPrepared, PrepareAlloc}, + Dsize, GLWEPlaintext, GLWESecret, GLWESecretPreparedFactory, GLWETensorKey, GLWETensorKeyCompressed, GLWETensorKeyLayout, + prepared::GLWESecretPrepared, }, }; -pub fn test_gglwe_tensor_key_encrypt_sk<B>(module: &Module<B>) +pub fn test_gglwe_tensor_key_encrypt_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxCopy - + VecZnxDftAlloc<B> - + SvpApplyDftToDft<B> - + VecZnxBigAlloc<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxAddScalarInplace - + VecZnxSwitchRing + Module<BE>: GLWETensorKeyEncryptSk<BE> + + GLWESecretPreparedFactory<BE> + + GLWEDecrypt<BE> + + VecZnxDftAlloc<BE> + + VecZnxBigAlloc<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDft<BE> + + VecZnxIdftApplyTmpA<BE> + + VecZnxBigNormalize<BE> + VecZnxSubScalarInplace, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 8; let k: usize = 54;@@ -71,7 +40,7 @@ for rank in 1_usize..3 {
let n: usize = module.n(); let dnum: usize = k / base2k; - let tensor_key_infos = GGLWETensorKeyLayout { + let tensor_key_infos = GLWETensorKeyLayout { n: n.into(), base2k: base2k.into(), k: k.into(),@@ -80,20 +49,21 @@ dsize: Dsize(1),
rank: rank.into(), }; - let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tensor_key_infos); + let mut tensor_key: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc_from_infos(&tensor_key_infos); 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<B> = ScratchOwned::alloc(GGLWETensorKey::encrypt_sk_scratch_space( + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(GLWETensorKey::encrypt_sk_tmp_bytes( module, &tensor_key_infos, )); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&tensor_key_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&tensor_key_infos); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); tensor_key.encrypt_sk( module,@@ -103,12 +73,12 @@ &mut source_xe,
scratch.borrow(), ); - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&tensor_key_infos); + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&tensor_key_infos); - let mut sk_ij_dft = module.vec_znx_dft_alloc(1, 1); - let mut sk_ij_big = module.vec_znx_big_alloc(1, 1); - let mut sk_ij: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), 1_u32.into()); - let mut sk_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(rank, 1); + let mut sk_ij_dft: VecZnxDft<Vec<u8>, BE> = module.vec_znx_dft_alloc(1, 1); + let mut sk_ij_big: VecZnxBig<Vec<u8>, BE> = module.vec_znx_big_alloc(1, 1); + let mut sk_ij: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), 1_u32.into()); + let mut sk_dft: VecZnxDft<Vec<u8>, BE> = module.vec_znx_dft_alloc(rank, 1); for i in 0..rank { module.vec_znx_dft_apply(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i);@@ -128,10 +98,9 @@ 0,
scratch.borrow(), ); for row_i in 0..dnum { - tensor_key - .at(i, j) - .at(row_i, 0) - .decrypt(module, &mut pt, &sk_prepared, scratch.borrow()); + let ct = tensor_key.at(i, j).at(row_i, 0); + + ct.decrypt(module, &mut pt, &sk_prepared, scratch.borrow()); module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, row_i, &sk_ij.data, 0);@@ -143,46 +112,23 @@ }
} } -pub fn test_gglwe_tensor_key_compressed_encrypt_sk<B>(module: &Module<B>) +pub fn test_gglwe_tensor_key_compressed_encrypt_sk<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes + Module<BE>: GLWETensorKeyEncryptSk<BE> + + GLWESecretPreparedFactory<BE> + + GLWETensorKeyCompressedEncryptSk<BE> + + GLWEDecrypt<BE> + + VecZnxDftAlloc<BE> + + VecZnxBigAlloc<BE> + + VecZnxDftApply<BE> + + SvpApplyDftToDft<BE> + + VecZnxIdftApplyTmpA<BE> + + VecZnxSubScalarInplace + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> + VecZnxCopy - + VecZnxDftAlloc<B> - + SvpApplyDftToDft<B> - + VecZnxBigAlloc<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxAddScalarInplace - + VecZnxSwitchRing - + VecZnxSubScalarInplace, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + + VecZnxSwitchRing, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k = 8; let k = 54;@@ -190,7 +136,7 @@ for rank in 1_usize..3 {
let n: usize = module.n(); let dnum: usize = k / base2k; - let tensor_key_infos: GGLWETensorKeyLayout = GGLWETensorKeyLayout { + let tensor_key_infos: GLWETensorKeyLayout = GLWETensorKeyLayout { n: n.into(), base2k: base2k.into(), k: k.into(),@@ -199,33 +145,35 @@ dsize: Dsize(1),
rank: rank.into(), }; - let mut tensor_key_compressed: GGLWETensorKeyCompressed<Vec<u8>> = GGLWETensorKeyCompressed::alloc(&tensor_key_infos); + let mut tensor_key_compressed: GLWETensorKeyCompressed<Vec<u8>> = + GLWETensorKeyCompressed::alloc_from_infos(&tensor_key_infos); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGLWETensorKeyCompressed::encrypt_sk_scratch_space( + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(GLWETensorKeyCompressed::encrypt_sk_tmp_bytes( module, &tensor_key_infos, )); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&tensor_key_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&tensor_key_infos); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); let seed_xa: [u8; 32] = [1u8; 32]; tensor_key_compressed.encrypt_sk(module, &sk, seed_xa, &mut source_xe, scratch.borrow()); - let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tensor_key_infos); + let mut tensor_key: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc_from_infos(&tensor_key_infos); tensor_key.decompress(module, &tensor_key_compressed); - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&tensor_key_infos); + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&tensor_key_infos); - let mut sk_ij_dft = module.vec_znx_dft_alloc(1, 1); - let mut sk_ij_big = module.vec_znx_big_alloc(1, 1); - let mut sk_ij: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), 1_u32.into()); - let mut sk_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(rank, 1); + let mut sk_ij_dft: VecZnxDft<Vec<u8>, BE> = module.vec_znx_dft_alloc(1, 1); + let mut sk_ij_big: VecZnxBig<Vec<u8>, BE> = module.vec_znx_big_alloc(1, 1); + let mut sk_ij: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), 1_u32.into()); + let mut sk_dft: VecZnxDft<Vec<u8>, BE> = module.vec_znx_dft_alloc(rank, 1); for i in 0..rank { module.vec_znx_dft_apply(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i);
@@ -1,72 +1,31 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxSub, - VecZnxSubInplace, VecZnxSubScalarInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, ScratchOwned, ZnxViewMut}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, VecZnxBigAllocBytesImpl, VecZnxDftAllocBytesImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxRotateInplace}, + layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, Scratch, ScratchOwned, ZnxViewMut}, source::Source, }; use crate::{ + GGLWEExternalProduct, GGLWENoise, GGSWEncryptSk, GLWESwitchingKeyEncryptSk, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGLWESwitchingKey, GGLWESwitchingKeyLayout, GGSWCiphertext, GGSWCiphertextLayout, GLWESecret, - prepared::{GGSWCiphertextPrepared, GLWESecretPrepared, PrepareAlloc}, + GGSW, GGSWLayout, GGSWPreparedFactory, GLWESecret, GLWESecretPreparedFactory, GLWESwitchingKey, GLWESwitchingKeyLayout, + prepared::{GGSWPrepared, GLWESecretPrepared}, }, noise::noise_ggsw_product, }; #[allow(clippy::too_many_arguments)] -pub fn test_gglwe_switching_key_external_product<B>(module: &Module<B>) +pub fn test_gglwe_switching_key_external_product<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxSwitchRing - + VecZnxAddScalarInplace - + VecZnxSubScalarInplace - + VecZnxCopy - + VmpPMatAlloc<B> - + VecZnxRotateInplace<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VmpPrepare<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + Module<BE>: GGLWEExternalProduct<BE> + + GGSWEncryptSk<BE> + + GLWESwitchingKeyEncryptSk<BE> + + GLWESecretPreparedFactory<BE> + + VecZnxRotateInplace<BE> + + GGSWPreparedFactory<BE> + + GGLWENoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_in: usize = 60;@@ -81,7 +40,7 @@ let n: usize = module.n();
let dnum: usize = k_in.div_ceil(base2k * di); let dsize_in: usize = 1; - let gglwe_in_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let gglwe_in_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(),@@ -91,7 +50,7 @@ rank_in: rank_in.into(),
rank_out: rank_out.into(), }; - let gglwe_out_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let gglwe_out_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -101,7 +60,7 @@ rank_in: rank_in.into(),
rank_out: rank_out.into(), }; - let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_ggsw.into(),@@ -110,9 +69,9 @@ dsize: di.into(),
rank: rank_out.into(), }; - let mut ct_gglwe_in: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_in_infos); - let mut ct_gglwe_out: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_out_infos); - let mut ct_rgsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos); + let mut ct_gglwe_in: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_in_infos); + let mut ct_gglwe_out: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_out_infos); + let mut ct_rgsw: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_infos); let mut pt_rgsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);@@ -120,15 +79,10 @@ 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<B> = ScratchOwned::alloc( - GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_in_infos) - | GGLWESwitchingKey::external_product_scratch_space( - module, - &gglwe_out_infos, - &gglwe_in_infos, - &ggsw_infos, - ) - | GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_in_infos) + | GLWESwitchingKey::external_product_tmp_bytes(module, &gglwe_out_infos, &gglwe_in_infos, &ggsw_infos) + | GGSW::encrypt_sk_tmp_bytes(module, &ggsw_infos), ); let r: usize = 1;@@ -137,12 +91,14 @@ pt_rgsw.to_mut().raw_mut()[r] = 1; // X^{r}
let var_xs: f64 = 0.5; - let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into()); + let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into()); sk_in.fill_ternary_prob(var_xs, &mut source_xs); - let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into()); + let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into()); sk_out.fill_ternary_prob(var_xs, &mut source_xs); - let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow()); + + let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into()); + sk_out_prepared.prepare(module, &sk_out); // gglwe_{s1}(s0) = s0 -> s1 ct_gglwe_in.encrypt_sk(@@ -163,7 +119,8 @@ &mut source_xe,
scratch.borrow(), ); - let ct_rgsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ct_rgsw.prepare_alloc(module, scratch.borrow()); + let mut ct_rgsw_prepared: GGSWPrepared<Vec<u8>, BE> = GGSWPrepared::alloc_from_infos(module, &ct_rgsw); + ct_rgsw_prepared.prepare(module, &ct_rgsw, scratch.borrow()); // gglwe_(m) (x) RGSW_(X^k) = gglwe_(m * X^k) ct_gglwe_out.external_product(module, &ct_gglwe_in, &ct_rgsw_prepared, scratch.borrow());@@ -207,48 +164,17 @@ }
} #[allow(clippy::too_many_arguments)] -pub fn test_gglwe_switching_key_external_product_inplace<B>(module: &Module<B>) +pub fn test_gglwe_switching_key_external_product_inplace<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxSwitchRing - + VecZnxAddScalarInplace - + VecZnxSubScalarInplace - + VecZnxCopy - + VmpPMatAlloc<B> - + VecZnxRotateInplace<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VmpPrepare<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + Module<BE>: GGLWEExternalProduct<BE> + + GGSWEncryptSk<BE> + + GLWESwitchingKeyEncryptSk<BE> + + GLWESecretPreparedFactory<BE> + + VecZnxRotateInplace<BE> + + GGSWPreparedFactory<BE> + + GGLWENoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_out: usize = 60;@@ -263,7 +189,7 @@ let dnum: usize = k_out.div_ceil(base2k * di);
let dsize_in: usize = 1; - let gglwe_out_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let gglwe_out_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -273,7 +199,7 @@ rank_in: rank_in.into(),
rank_out: rank_out.into(), }; - let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_ggsw.into(),@@ -282,8 +208,8 @@ dsize: di.into(),
rank: rank_out.into(), }; - let mut ct_gglwe: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_out_infos); - let mut ct_rgsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos); + let mut ct_gglwe: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_out_infos); + let mut ct_rgsw: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_infos); let mut pt_rgsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);@@ -291,10 +217,10 @@ 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<B> = ScratchOwned::alloc( - GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_out_infos) - | GGLWESwitchingKey::external_product_inplace_scratch_space(module, &gglwe_out_infos, &ggsw_infos) - | GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_out_infos) + | GLWESwitchingKey::external_product_tmp_bytes(module, &gglwe_out_infos, &gglwe_out_infos, &ggsw_infos) + | GGSW::encrypt_sk_tmp_bytes(module, &ggsw_infos), ); let r: usize = 1;@@ -303,12 +229,14 @@ pt_rgsw.to_mut().raw_mut()[r] = 1; // X^{r}
let var_xs: f64 = 0.5; - let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into()); + let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into()); sk_in.fill_ternary_prob(var_xs, &mut source_xs); - let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into()); + let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into()); sk_out.fill_ternary_prob(var_xs, &mut source_xs); - let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow()); + + let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into()); + sk_out_prepared.prepare(module, &sk_out); // gglwe_{s1}(s0) = s0 -> s1 ct_gglwe.encrypt_sk(@@ -329,7 +257,8 @@ &mut source_xe,
scratch.borrow(), ); - let ct_rgsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ct_rgsw.prepare_alloc(module, scratch.borrow()); + let mut ct_rgsw_prepared: GGSWPrepared<Vec<u8>, BE> = GGSWPrepared::alloc_from_infos(module, &ct_rgsw); + ct_rgsw_prepared.prepare(module, &ct_rgsw, scratch.borrow()); // gglwe_(m) (x) RGSW_(X^k) = gglwe_(m * X^k) ct_gglwe.external_product_inplace(module, &ct_rgsw_prepared, scratch.borrow());
@@ -1,74 +1,30 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAlloc, VecZnxDftAllocBytes, - VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxSub, VecZnxSubInplace, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, ScratchOwned, ZnxViewMut}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, VecZnxBigAllocBytesImpl, VecZnxDftAllocBytesImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxRotateInplace}, + layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, Scratch, ScratchOwned, ZnxViewMut}, source::Source, }; use crate::{ + GGSWEncryptSk, GGSWExternalProduct, GGSWNoise, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGSWCiphertext, GGSWCiphertextLayout, GLWESecret, - prepared::{GGSWCiphertextPrepared, GLWESecretPrepared, PrepareAlloc}, + GGSW, GGSWLayout, GGSWPreparedFactory, GLWESecret, GLWESecretPreparedFactory, + prepared::{GGSWPrepared, GLWESecretPrepared}, }, noise::noise_ggsw_product, }; #[allow(clippy::too_many_arguments)] -pub fn test_ggsw_external_product<B>(module: &Module<B>) +pub fn test_ggsw_external_product<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxAddScalarInplace - + VecZnxCopy - + VmpPMatAlloc<B> - + VecZnxRotateInplace<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VmpPrepare<B> - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + Module<BE>: GGSWEncryptSk<BE> + + GGSWExternalProduct<BE> + + GLWESecretPreparedFactory<BE> + + GGSWPreparedFactory<BE> + + VecZnxRotateInplace<BE> + + GGSWNoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_in: usize = 60;@@ -84,7 +40,7 @@ let dnum: usize = k_in.div_ceil(base2k * di);
let dnum_in: usize = k_in.div_euclid(base2k * di); let dsize_in: usize = 1; - let ggsw_in_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_in_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(),@@ -93,7 +49,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_out_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -102,7 +58,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_apply_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_apply.into(),@@ -111,9 +67,9 @@ dsize: di.into(),
rank: rank.into(), }; - let mut ggsw_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_in_infos); - let mut ggsw_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_infos); - let mut ggsw_apply: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_apply_infos); + let mut ggsw_in: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_in_infos); + let mut ggsw_out: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_out_infos); + let mut ggsw_apply: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_apply_infos); let mut pt_in: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1); let mut pt_apply: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);@@ -127,15 +83,17 @@ let k: usize = 1;
pt_apply.to_mut().raw_mut()[k] = 1; //X^{k} - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_apply_infos) - | GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_in_infos) - | GGSWCiphertext::external_product_scratch_space(module, &ggsw_out_infos, &ggsw_in_infos, &ggsw_apply_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GGSW::encrypt_sk_tmp_bytes(module, &ggsw_apply_infos) + | GGSW::encrypt_sk_tmp_bytes(module, &ggsw_in_infos) + | GGSW::external_product_tmp_bytes(module, &ggsw_out_infos, &ggsw_in_infos, &ggsw_apply_infos), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into()); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into()); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); ggsw_apply.encrypt_sk( module,@@ -155,7 +113,8 @@ &mut source_xe,
scratch.borrow(), ); - let ct_rhs_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ggsw_apply.prepare_alloc(module, scratch.borrow()); + let mut ct_rhs_prepared: GGSWPrepared<Vec<u8>, BE> = GGSWPrepared::alloc_from_infos(module, &ggsw_apply); + ct_rhs_prepared.prepare(module, &ggsw_apply, scratch.borrow()); ggsw_out.external_product(module, &ggsw_in, &ct_rhs_prepared, scratch.borrow());@@ -190,50 +149,16 @@ }
} #[allow(clippy::too_many_arguments)] -pub fn test_ggsw_external_product_inplace<B>(module: &Module<B>) +pub fn test_ggsw_external_product_inplace<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxAddScalarInplace - + VecZnxCopy - + VmpPMatAlloc<B> - + VecZnxRotateInplace<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VmpPrepare<B> - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B> - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + TakeSvpPPolImpl<B>, + Module<BE>: GGSWEncryptSk<BE> + + GGSWExternalProduct<BE> + + GLWESecretPreparedFactory<BE> + + GGSWPreparedFactory<BE> + + VecZnxRotateInplace<BE> + + GGSWNoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_out: usize = 60;@@ -247,7 +172,7 @@ let dnum: usize = k_out.div_ceil(di * base2k);
let dnum_in: usize = k_out.div_euclid(base2k * di); let dsize_in: usize = 1; - let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_out_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -256,7 +181,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_apply_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_apply.into(),@@ -265,8 +190,8 @@ dsize: di.into(),
rank: rank.into(), }; - let mut ggsw_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_infos); - let mut ggsw_apply: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_apply_infos); + let mut ggsw_out: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_out_infos); + let mut ggsw_apply: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_apply_infos); let mut pt_in: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1); let mut pt_apply: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);@@ -281,15 +206,17 @@ let k: usize = 1;
pt_apply.to_mut().raw_mut()[k] = 1; //X^{k} - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_apply_infos) - | GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_out_infos) - | GGSWCiphertext::external_product_inplace_scratch_space(module, &ggsw_out_infos, &ggsw_apply_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GGSW::encrypt_sk_tmp_bytes(module, &ggsw_apply_infos) + | GGSW::encrypt_sk_tmp_bytes(module, &ggsw_out_infos) + | GGSW::external_product_tmp_bytes(module, &ggsw_out_infos, &ggsw_out_infos, &ggsw_apply_infos), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into()); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into()); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); ggsw_apply.encrypt_sk( module,@@ -309,7 +236,8 @@ &mut source_xe,
scratch.borrow(), ); - let ct_rhs_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ggsw_apply.prepare_alloc(module, scratch.borrow()); + let mut ct_rhs_prepared: GGSWPrepared<Vec<u8>, BE> = GGSWPrepared::alloc_from_infos(module, &ggsw_apply); + ct_rhs_prepared.prepare(module, &ggsw_apply, scratch.borrow()); ggsw_out.external_product_inplace(module, &ct_rhs_prepared, scratch.borrow());
@@ -1,66 +1,32 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, - VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxSub, VecZnxSubInplace, - VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScalarZnx, ScratchOwned, ZnxViewMut}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform, VecZnxRotateInplace}, + layouts::{Backend, Module, ScalarZnx, Scratch, ScratchOwned, ZnxViewMut}, source::Source, }; use crate::{ + GGSWEncryptSk, GLWEEncryptSk, GLWEExternalProduct, GLWENoise, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGSWCiphertext, GGSWCiphertextLayout, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, - prepared::{GGSWCiphertextPrepared, GLWESecretPrepared, PrepareAlloc}, + GGSW, GGSWLayout, GGSWPreparedFactory, GLWE, GLWELayout, GLWEPlaintext, GLWESecret, GLWESecretPreparedFactory, + prepared::{GGSWPrepared, GLWESecretPrepared}, }, noise::noise_ggsw_product, }; #[allow(clippy::too_many_arguments)] -pub fn test_glwe_external_product<B>(module: &Module<B>) +pub fn test_glwe_external_product<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> + Module<BE>: GGSWEncryptSk<BE> + + GGSWPreparedFactory<BE> + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VecZnxRotateInplace<B> - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + + GLWEExternalProduct<BE> + + GLWEEncryptSk<BE> + + GLWENoise<BE> + + VecZnxRotateInplace<BE> + + GLWESecretPreparedFactory<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_in: usize = 45;@@ -73,21 +39,21 @@
let n: usize = module.n(); let dnum: usize = k_in.div_ceil(base2k * dsize); - let glwe_in_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_in_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_in.into(), rank: rank.into(), }; - let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_out_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), rank: rank.into(), }; - let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_apply_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_ggsw.into(),@@ -96,11 +62,11 @@ dsize: di.into(),
rank: rank.into(), }; - let mut ggsw_apply: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_apply_infos); - let mut glwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_in_infos); - let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos); + let mut ggsw_apply: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_apply_infos); + let mut glwe_in: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_in_infos); + let mut glwe_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos); let mut pt_ggsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_in_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_in_infos); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]);@@ -115,15 +81,17 @@ let k: usize = 1;
pt_ggsw.raw_mut()[k] = 1; // X^{k} - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_apply_infos) - | GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_in_infos) - | GLWECiphertext::external_product_scratch_space(module, &glwe_out_infos, &glwe_in_infos, &ggsw_apply_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GGSW::encrypt_sk_tmp_bytes(module, &ggsw_apply_infos) + | GLWE::encrypt_sk_tmp_bytes(module, &glwe_in_infos) + | GLWE::external_product_tmp_bytes(module, &glwe_out_infos, &glwe_in_infos, &ggsw_apply_infos), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into()); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into()); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); ggsw_apply.encrypt_sk( module,@@ -143,7 +111,8 @@ &mut source_xe,
scratch.borrow(), ); - let ct_ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ggsw_apply.prepare_alloc(module, scratch.borrow()); + let mut ct_ggsw_prepared: GGSWPrepared<Vec<u8>, BE> = GGSWPrepared::alloc_from_infos(module, &ggsw_apply); + ct_ggsw_prepared.prepare(module, &ggsw_apply, scratch.borrow()); glwe_out.external_product(module, &glwe_in, &ct_ggsw_prepared, scratch.borrow());@@ -176,43 +145,18 @@ }
} #[allow(clippy::too_many_arguments)] -pub fn test_glwe_external_product_inplace<B>(module: &Module<B>) +pub fn test_glwe_external_product_inplace<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> + Module<BE>: GGSWEncryptSk<BE> + + GGSWPreparedFactory<BE> + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VecZnxRotateInplace<B> - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + + GLWEExternalProduct<BE> + + GLWEEncryptSk<BE> + + GLWENoise<BE> + + VecZnxRotateInplace<BE> + + GLWESecretPreparedFactory<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_out: usize = 60;@@ -224,14 +168,14 @@
let n: usize = module.n(); let dnum: usize = k_out.div_ceil(base2k * dsize); - let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_out_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), rank: rank.into(), }; - let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_apply_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_ggsw.into(),@@ -240,10 +184,10 @@ dsize: di.into(),
rank: rank.into(), }; - let mut ggsw_apply: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_apply_infos); - let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos); + let mut ggsw_apply: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_apply_infos); + let mut glwe_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos); let mut pt_ggsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_infos); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]);@@ -258,15 +202,17 @@ let k: usize = 1;
pt_ggsw.raw_mut()[k] = 1; // X^{k} - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_apply_infos) - | GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_out_infos) - | GLWECiphertext::external_product_inplace_scratch_space(module, &glwe_out_infos, &ggsw_apply_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GGSW::encrypt_sk_tmp_bytes(module, &ggsw_apply_infos) + | GLWE::encrypt_sk_tmp_bytes(module, &glwe_out_infos) + | GLWE::external_product_tmp_bytes(module, &glwe_out_infos, &glwe_out_infos, &ggsw_apply_infos), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into()); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into()); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_prepared.prepare(module, &sk); ggsw_apply.encrypt_sk( module,@@ -286,7 +232,8 @@ &mut source_xe,
scratch.borrow(), ); - let ct_ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ggsw_apply.prepare_alloc(module, scratch.borrow()); + let mut ct_ggsw_prepared: GGSWPrepared<Vec<u8>, BE> = GGSWPrepared::alloc_from_infos(module, &ggsw_apply); + ct_ggsw_prepared.prepare(module, &ggsw_apply, scratch.borrow()); glwe_out.external_product_inplace(module, &ct_ggsw_prepared, scratch.borrow());
@@ -1,68 +1,28 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, - VecZnxSubInplace, VecZnxSubScalarInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow}, + layouts::{Backend, Module, Scratch, ScratchOwned}, source::Source, }; use crate::{ + GGLWEKeyswitch, GGLWENoise, GLWESwitchingKeyEncryptSk, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGLWESwitchingKey, GGLWESwitchingKeyLayout, GLWESecret, - prepared::{GGLWESwitchingKeyPrepared, GLWESecretPrepared, PrepareAlloc}, + GLWESecret, GLWESecretPreparedFactory, GLWESwitchingKey, GLWESwitchingKeyLayout, GLWESwitchingKeyPreparedFactory, + prepared::{GLWESecretPrepared, GLWESwitchingKeyPrepared}, }, noise::log2_std_noise_gglwe_product, }; -pub fn test_gglwe_switching_key_keyswitch<B>(module: &Module<B>) +pub fn test_gglwe_switching_key_keyswitch<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxSubScalarInplace, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: GLWESwitchingKeyEncryptSk<BE> + + GGLWEKeyswitch<BE> + + GLWESwitchingKeyPreparedFactory<BE> + + GLWESecretPreparedFactory<BE> + + GGLWENoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_in: usize = 60;@@ -80,7 +40,7 @@ let dnum: usize = k_in / base2k;
let dnum_apply: usize = k_in.div_ceil(base2k * di); let dsize_in: usize = 1; - let gglwe_s0s1_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let gglwe_s0s1_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(),@@ -90,7 +50,7 @@ rank_in: rank_in_s0s1.into(),
rank_out: rank_out_s0s1.into(), }; - let gglwe_s1s2_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let gglwe_s1s2_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -100,7 +60,7 @@ rank_in: rank_out_s0s1.into(),
rank_out: rank_out_s1s2.into(), }; - let gglwe_s0s2_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let gglwe_s0s2_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -110,35 +70,38 @@ rank_in: rank_in_s0s1.into(),
rank_out: rank_out_s1s2.into(), }; - let mut gglwe_s0s1: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_s0s1_infos); - let mut gglwe_s1s2: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_s1s2_infos); - let mut gglwe_s0s2: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_s0s2_infos); + let mut gglwe_s0s1: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s0s1_infos); + let mut gglwe_s1s2: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s1s2_infos); + let mut gglwe_s0s2: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s0s2_infos); 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_enc: ScratchOwned<B> = ScratchOwned::alloc( - GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_s0s1_infos) - | GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_s1s2_infos) - | GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_s0s2_infos), + let mut scratch_enc: ScratchOwned<BE> = ScratchOwned::alloc( + GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s0s1_infos) + | GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s1s2_infos) + | GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s0s2_infos), ); - let mut scratch_apply: ScratchOwned<B> = ScratchOwned::alloc(GGLWESwitchingKey::keyswitch_scratch_space( + let mut scratch_apply: ScratchOwned<BE> = ScratchOwned::alloc(GLWESwitchingKey::keyswitch_tmp_bytes( module, &gglwe_s0s1_infos, &gglwe_s0s2_infos, &gglwe_s1s2_infos, )); - let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in_s0s1.into()); + let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in_s0s1.into()); sk0.fill_ternary_prob(0.5, &mut source_xs); - let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out_s0s1.into()); + let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out_s0s1.into()); sk1.fill_ternary_prob(0.5, &mut source_xs); - let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out_s1s2.into()); + let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out_s1s2.into()); sk2.fill_ternary_prob(0.5, &mut source_xs); - let sk2_prepared: GLWESecretPrepared<Vec<u8>, B> = sk2.prepare_alloc(module, scratch_apply.borrow()); + + let mut sk2_prepared: GLWESecretPrepared<Vec<u8>, BE> = + GLWESecretPrepared::alloc(module, rank_out_s1s2.into()); + sk2_prepared.prepare(module, &sk2); // gglwe_{s1}(s0) = s0 -> s1 gglwe_s0s1.encrypt_sk(@@ -160,8 +123,9 @@ &mut source_xe,
scratch_enc.borrow(), ); - let gglwe_s1s2_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = - gglwe_s1s2.prepare_alloc(module, scratch_apply.borrow()); + let mut gglwe_s1s2_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> = + GLWESwitchingKeyPrepared::alloc_from_infos(module, &gglwe_s1s2); + gglwe_s1s2_prepared.prepare(module, &gglwe_s1s2, scratch_apply.borrow()); // gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0) gglwe_s0s2.keyswitch(@@ -194,45 +158,15 @@ }
} #[allow(clippy::too_many_arguments)] -pub fn test_gglwe_switching_key_keyswitch_inplace<B>(module: &Module<B>) +pub fn test_gglwe_switching_key_keyswitch_inplace<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxSubScalarInplace, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: GLWESwitchingKeyEncryptSk<BE> + + GGLWEKeyswitch<BE> + + GLWESecretPreparedFactory<BE> + + GGLWENoise<BE> + + GLWESwitchingKeyPreparedFactory<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_out: usize = 60;@@ -246,7 +180,7 @@ let n: usize = module.n();
let dnum: usize = k_out.div_ceil(base2k * di); let dsize_in: usize = 1; - let gglwe_s0s1_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let gglwe_s0s1_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -256,7 +190,7 @@ rank_in: rank_in.into(),
rank_out: rank_out.into(), }; - let gglwe_s1s2_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let gglwe_s1s2_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -266,34 +200,37 @@ rank_in: rank_out.into(),
rank_out: rank_out.into(), }; - let mut gglwe_s0s1: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_s0s1_infos); - let mut gglwe_s1s2: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_s1s2_infos); + let mut gglwe_s0s1: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s0s1_infos); + let mut gglwe_s1s2: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&gglwe_s1s2_infos); 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_enc: ScratchOwned<B> = ScratchOwned::alloc( - GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_s0s1_infos) - | GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_s1s2_infos), + let mut scratch_enc: ScratchOwned<BE> = ScratchOwned::alloc( + GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s0s1_infos) + | GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &gglwe_s1s2_infos), ); - let mut scratch_apply: ScratchOwned<B> = ScratchOwned::alloc(GGLWESwitchingKey::keyswitch_inplace_scratch_space( + let mut scratch_apply: ScratchOwned<BE> = ScratchOwned::alloc(GLWESwitchingKey::keyswitch_tmp_bytes( module, + &gglwe_s0s1_infos, &gglwe_s0s1_infos, &gglwe_s1s2_infos, )); let var_xs: f64 = 0.5; - let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into()); + let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into()); sk0.fill_ternary_prob(var_xs, &mut source_xs); - let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into()); + let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into()); sk1.fill_ternary_prob(var_xs, &mut source_xs); - let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into()); + let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into()); sk2.fill_ternary_prob(var_xs, &mut source_xs); - let sk2_prepared: GLWESecretPrepared<Vec<u8>, B> = sk2.prepare_alloc(module, scratch_apply.borrow()); + + let mut sk2_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into()); + sk2_prepared.prepare(module, &sk2); // gglwe_{s1}(s0) = s0 -> s1 gglwe_s0s1.encrypt_sk(@@ -315,13 +252,14 @@ &mut source_xe,
scratch_enc.borrow(), ); - let gglwe_s1s2_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = - gglwe_s1s2.prepare_alloc(module, scratch_apply.borrow()); + let mut gglwe_s1s2_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> = + GLWESwitchingKeyPrepared::alloc_from_infos(module, &gglwe_s1s2); + gglwe_s1s2_prepared.prepare(module, &gglwe_s1s2, scratch_apply.borrow()); // gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0) gglwe_s0s1.keyswitch_inplace(module, &gglwe_s1s2_prepared, scratch_apply.borrow()); - let gglwe_s0s2: GGLWESwitchingKey<Vec<u8>> = gglwe_s0s1; + let gglwe_s0s2: GLWESwitchingKey<Vec<u8>> = gglwe_s0s1; let max_noise: f64 = log2_std_noise_gglwe_product( n as f64,
@@ -1,75 +1,33 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, - SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAddInplace, VecZnxDftAlloc, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, - VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScalarZnx, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow}, + layouts::{Backend, Module, ScalarZnx, Scratch, ScratchOwned}, source::Source, }; use crate::{ + GGSWEncryptSk, GGSWKeyswitch, GGSWNoise, GLWESwitchingKeyEncryptSk, GLWETensorKeyEncryptSk, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGLWESwitchingKey, GGLWESwitchingKeyLayout, GGLWETensorKey, GGLWETensorKeyLayout, GGSWCiphertext, GGSWCiphertextLayout, - GLWESecret, - prepared::{GGLWESwitchingKeyPrepared, GGLWETensorKeyPrepared, GLWESecretPrepared, PrepareAlloc}, + GGSW, GGSWLayout, GLWESecret, GLWESecretPreparedFactory, GLWESwitchingKey, GLWESwitchingKeyLayout, + GLWESwitchingKeyPreparedFactory, GLWETensorKey, GLWETensorKeyLayout, GLWETensorKeyPreparedFactory, + prepared::{GLWESecretPrepared, GLWESwitchingKeyPrepared, GLWETensorKeyPrepared}, }, noise::noise_ggsw_keyswitch, }; #[allow(clippy::too_many_arguments)] -pub fn test_ggsw_keyswitch<B>(module: &Module<B>) +pub fn test_ggsw_keyswitch<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing - + SvpApplyDftToDft<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxDftCopy<B> - + VecZnxDftAddInplace<B> - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: GGSWEncryptSk<BE> + + GLWESwitchingKeyEncryptSk<BE> + + GLWETensorKeyEncryptSk<BE> + + GGSWKeyswitch<BE> + + GLWESecretPreparedFactory<BE> + + GLWETensorKeyPreparedFactory<BE> + + GLWESwitchingKeyPreparedFactory<BE> + + GGSWNoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_in: usize = 54;@@ -85,7 +43,7 @@ let dnum: usize = k_in.div_ceil(di * base2k);
let dsize_in: usize = 1; - let ggsw_in_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_in_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_in.into(),@@ -94,7 +52,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_out_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -103,7 +61,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let tsk_infos: GGLWETensorKeyLayout = GGLWETensorKeyLayout { + let tsk_infos: GLWETensorKeyLayout = GLWETensorKeyLayout { n: n.into(), base2k: base2k.into(), k: k_tsk.into(),@@ -112,7 +70,7 @@ dsize: di.into(),
rank: rank.into(), }; - let ksk_apply_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let ksk_apply_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -122,21 +80,21 @@ rank_in: rank.into(),
rank_out: rank.into(), }; - let mut ggsw_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_in_infos); - let mut ggsw_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_infos); - let mut tsk: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tsk_infos); - let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&ksk_apply_infos); + let mut ggsw_in: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_in_infos); + let mut ggsw_out: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_out_infos); + let mut tsk: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc_from_infos(&tsk_infos); + let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&ksk_apply_infos); let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 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 scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_in_infos) - | GGLWESwitchingKey::encrypt_sk_scratch_space(module, &ksk_apply_infos) - | GGLWETensorKey::encrypt_sk_scratch_space(module, &tsk_infos) - | GGSWCiphertext::keyswitch_scratch_space( + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GGSW::encrypt_sk_tmp_bytes(module, &ggsw_in_infos) + | GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &ksk_apply_infos) + | GLWETensorKey::encrypt_sk_tmp_bytes(module, &tsk_infos) + | GGSW::keyswitch_tmp_bytes( module, &ggsw_out_infos, &ggsw_in_infos,@@ -147,13 +105,17 @@ );
let var_xs: f64 = 0.5; - let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into()); + let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into()); sk_in.fill_ternary_prob(var_xs, &mut source_xs); - let sk_in_dft: GLWESecretPrepared<Vec<u8>, B> = sk_in.prepare_alloc(module, scratch.borrow()); - let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into()); + let mut sk_in_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_in_prepared.prepare(module, &sk_in); + + let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into()); sk_out.fill_ternary_prob(var_xs, &mut source_xs); - let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow()); + + let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_out_prepared.prepare(module, &sk_out); ksk.encrypt_sk( module,@@ -176,14 +138,18 @@
ggsw_in.encrypt_sk( module, &pt_scalar, - &sk_in_dft, + &sk_in_prepared, &mut source_xa, &mut source_xe, scratch.borrow(), ); - let ksk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow()); - let tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = tsk.prepare_alloc(module, scratch.borrow()); + let mut ksk_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> = + GLWESwitchingKeyPrepared::alloc_from_infos(module, &ksk); + ksk_prepared.prepare(module, &ksk, scratch.borrow()); + + let mut tsk_prepared: GLWETensorKeyPrepared<Vec<u8>, BE> = GLWETensorKeyPrepared::alloc_from_infos(module, &tsk); + tsk_prepared.prepare(module, &tsk, scratch.borrow()); ggsw_out.keyswitch( module,@@ -215,50 +181,18 @@ }
} #[allow(clippy::too_many_arguments)] -pub fn test_ggsw_keyswitch_inplace<B>(module: &Module<B>) +pub fn test_ggsw_keyswitch_inplace<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing - + SvpApplyDftToDft<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxDftCopy<B> - + VecZnxDftAddInplace<B> - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B>, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: GGSWEncryptSk<BE> + + GLWESwitchingKeyEncryptSk<BE> + + GLWETensorKeyEncryptSk<BE> + + GGSWKeyswitch<BE> + + GLWESecretPreparedFactory<BE> + + GLWETensorKeyPreparedFactory<BE> + + GLWESwitchingKeyPreparedFactory<BE> + + GGSWNoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_out: usize = 54;@@ -273,7 +207,7 @@ let dnum: usize = k_out.div_ceil(di * base2k);
let dsize_in: usize = 1; - let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_out_infos: GGSWLayout = GGSWLayout { n: n.into(), base2k: base2k.into(), k: k_out.into(),@@ -282,7 +216,7 @@ dsize: dsize_in.into(),
rank: rank.into(), }; - let tsk_infos: GGLWETensorKeyLayout = GGLWETensorKeyLayout { + let tsk_infos: GLWETensorKeyLayout = GLWETensorKeyLayout { n: n.into(), base2k: base2k.into(), k: k_tsk.into(),@@ -291,7 +225,7 @@ dsize: di.into(),
rank: rank.into(), }; - let ksk_apply_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let ksk_apply_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -301,31 +235,41 @@ rank_in: rank.into(),
rank_out: rank.into(), }; - let mut ggsw_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_infos); - let mut tsk: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tsk_infos); - let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&ksk_apply_infos); + let mut ggsw_out: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_out_infos); + let mut tsk: GLWETensorKey<Vec<u8>> = GLWETensorKey::alloc_from_infos(&tsk_infos); + let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&ksk_apply_infos); let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 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 scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_out_infos) - | GGLWESwitchingKey::encrypt_sk_scratch_space(module, &ksk_apply_infos) - | GGLWETensorKey::encrypt_sk_scratch_space(module, &tsk_infos) - | GGSWCiphertext::keyswitch_inplace_scratch_space(module, &ggsw_out_infos, &ksk_apply_infos, &tsk_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GGSW::encrypt_sk_tmp_bytes(module, &ggsw_out_infos) + | GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &ksk_apply_infos) + | GLWETensorKey::encrypt_sk_tmp_bytes(module, &tsk_infos) + | GGSW::keyswitch_tmp_bytes( + module, + &ggsw_out_infos, + &ggsw_out_infos, + &ksk_apply_infos, + &tsk_infos, + ), ); let var_xs: f64 = 0.5; - let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into()); + let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into()); sk_in.fill_ternary_prob(var_xs, &mut source_xs); - let sk_in_dft: GLWESecretPrepared<Vec<u8>, B> = sk_in.prepare_alloc(module, scratch.borrow()); + + let mut sk_in_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_in_prepared.prepare(module, &sk_in); - let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into()); + let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into()); sk_out.fill_ternary_prob(var_xs, &mut source_xs); - let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow()); + + let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_out_prepared.prepare(module, &sk_out); ksk.encrypt_sk( module,@@ -348,14 +292,18 @@
ggsw_out.encrypt_sk( module, &pt_scalar, - &sk_in_dft, + &sk_in_prepared, &mut source_xa, &mut source_xe, scratch.borrow(), ); - let ksk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow()); - let tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = tsk.prepare_alloc(module, scratch.borrow()); + let mut ksk_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> = + GLWESwitchingKeyPrepared::alloc_from_infos(module, &ksk); + ksk_prepared.prepare(module, &ksk, scratch.borrow()); + + let mut tsk_prepared: GLWETensorKeyPrepared<Vec<u8>, BE> = GLWETensorKeyPrepared::alloc_from_infos(module, &tsk); + tsk_prepared.prepare(module, &tsk, scratch.borrow()); ggsw_out.keyswitch_inplace(module, &ksk_prepared, &tsk_prepared, scratch.borrow());
@@ -1,68 +1,32 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, - VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, - VmpPrepare, - }, - layouts::{Backend, Module, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform}, + layouts::{Backend, Module, Scratch, ScratchOwned}, source::Source, }; use crate::{ + GLWEEncryptSk, GLWEKeyswitch, GLWENoise, GLWESwitchingKeyEncryptSk, ScratchTakeCore, encryption::SIGMA, layouts::{ - GGLWESwitchingKey, GGLWESwitchingKeyLayout, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, - prepared::{GGLWESwitchingKeyPrepared, GLWESecretPrepared, PrepareAlloc}, + GLWE, GLWELayout, GLWEPlaintext, GLWESecret, GLWESecretPreparedFactory, GLWESwitchingKey, GLWESwitchingKeyLayout, + GLWESwitchingKeyPreparedFactory, + prepared::{GLWESecretPrepared, GLWESwitchingKeyPrepared}, }, noise::log2_std_noise_gglwe_product, }; #[allow(clippy::too_many_arguments)] -pub fn test_glwe_keyswitch<B>(module: &Module<B>) +pub fn test_glwe_keyswitch<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: VecZnxFillUniform + + GLWESwitchingKeyEncryptSk<BE> + + GLWEEncryptSk<BE> + + GLWEKeyswitch<BE> + + GLWESecretPreparedFactory<BE> + + GLWESwitchingKeyPreparedFactory<BE> + + GLWENoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_in: usize = 45;@@ -77,21 +41,21 @@
let n: usize = module.n(); let dnum: usize = k_in.div_ceil(base2k * dsize); - let glwe_in_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_in_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_in.into(), rank: rank_in.into(), }; - let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_out_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), rank: rank_out.into(), }; - let key_apply: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let ksk: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -101,10 +65,10 @@ rank_in: rank_in.into(),
rank_out: rank_out.into(), }; - let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&key_apply); - let mut glwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_in_infos); - let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_in_infos); + let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&ksk); + let mut glwe_in: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_in_infos); + let mut glwe_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_in_infos); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]);@@ -112,19 +76,23 @@ let mut source_xa: Source = Source::new([0u8; 32]);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGLWESwitchingKey::encrypt_sk_scratch_space(module, &key_apply) - | GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_in_infos) - | GLWECiphertext::keyswitch_scratch_space(module, &glwe_out_infos, &glwe_in_infos, &key_apply), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &ksk) + | GLWE::encrypt_sk_tmp_bytes(module, &glwe_in_infos) + | GLWE::keyswitch_tmp_bytes(module, &glwe_out_infos, &glwe_in_infos, &ksk), ); - let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into()); + let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_in.into()); sk_in.fill_ternary_prob(0.5, &mut source_xs); - let sk_in_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_in.prepare_alloc(module, scratch.borrow()); + + let mut sk_in_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_in.into()); + sk_in_prepared.prepare(module, &sk_in); - let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into()); + let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank_out.into()); sk_out.fill_ternary_prob(0.5, &mut source_xs); - let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow()); + + let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank_out.into()); + sk_out_prepared.prepare(module, &sk_out); ksk.encrypt_sk( module,@@ -144,7 +112,9 @@ &mut source_xe,
scratch.borrow(), ); - let ksk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow()); + let mut ksk_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> = + GLWESwitchingKeyPrepared::alloc_from_infos(module, &ksk); + ksk_prepared.prepare(module, &ksk, scratch.borrow()); glwe_out.keyswitch(module, &glwe_in, &ksk_prepared, scratch.borrow());@@ -167,44 +137,17 @@ }
} } -pub fn test_glwe_keyswitch_inplace<B>(module: &Module<B>) +pub fn test_glwe_keyswitch_inplace<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: VecZnxFillUniform + + GLWESwitchingKeyEncryptSk<BE> + + GLWEEncryptSk<BE> + + GLWEKeyswitch<BE> + + GLWESecretPreparedFactory<BE> + + GLWESwitchingKeyPreparedFactory<BE> + + GLWENoise<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 12; let k_out: usize = 45;@@ -217,14 +160,14 @@
let n: usize = module.n(); let dnum: usize = k_out.div_ceil(base2k * dsize); - let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_out_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_out.into(), rank: rank.into(), }; - let key_apply_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout { + let ksk_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -234,9 +177,9 @@ rank_in: rank.into(),
rank_out: rank.into(), }; - let mut key_apply: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&key_apply_infos); - let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos); + let mut ksk: GLWESwitchingKey<Vec<u8>> = GLWESwitchingKey::alloc_from_infos(&ksk_infos); + let mut glwe_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_infos); let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]);@@ -244,21 +187,25 @@ let mut source_xa: Source = Source::new([0u8; 32]);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa); - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GGLWESwitchingKey::encrypt_sk_scratch_space(module, &key_apply_infos) - | GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_out_infos) - | GLWECiphertext::keyswitch_inplace_scratch_space(module, &glwe_out_infos, &key_apply_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &ksk_infos) + | GLWE::encrypt_sk_tmp_bytes(module, &glwe_out_infos) + | GLWE::keyswitch_tmp_bytes(module, &glwe_out_infos, &glwe_out_infos, &ksk_infos), ); - let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into()); + let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into()); sk_in.fill_ternary_prob(0.5, &mut source_xs); - let sk_in_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_in.prepare_alloc(module, scratch.borrow()); - let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into()); + let mut sk_in_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_in_prepared.prepare(module, &sk_in); + + let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n.into(), rank.into()); sk_out.fill_ternary_prob(0.5, &mut source_xs); - let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow()); + + let mut sk_out_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_out_prepared.prepare(module, &sk_out); - key_apply.encrypt_sk( + ksk.encrypt_sk( module, &sk_in, &sk_out,@@ -276,7 +223,9 @@ &mut source_xe,
scratch.borrow(), ); - let ksk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = key_apply.prepare_alloc(module, scratch.borrow()); + let mut ksk_prepared: GLWESwitchingKeyPrepared<Vec<u8>, BE> = + GLWESwitchingKeyPrepared::alloc_from_infos(module, &ksk); + ksk_prepared.prepare(module, &ksk, scratch.borrow()); glwe_out.keyswitch_inplace(module, &ksk_prepared, scratch.borrow());
@@ -1,68 +1,23 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphismInplace, VecZnxBigAddInplace, - VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, ZnAddNormal, ZnFillUniform, ZnNormalizeInplace, - }, - layouts::{Backend, Module, ScratchOwned, ZnxView}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow}, + layouts::{Backend, Module, Scratch, ScratchOwned, ZnxView}, source::Source, }; -use crate::layouts::{ - LWECiphertext, LWECiphertextLayout, LWEPlaintext, LWESecret, LWESwitchingKey, LWESwitchingKeyLayout, - prepared::{LWESwitchingKeyPrepared, PrepareAlloc}, +use crate::{ + LWEDecrypt, LWEEncryptSk, LWEKeySwitch, LWESwitchingKeyEncrypt, ScratchTakeCore, + layouts::{ + LWE, LWELayout, LWEPlaintext, LWESecret, LWESwitchingKey, LWESwitchingKeyLayout, LWESwitchingKeyPreparedFactory, + prepared::LWESwitchingKeyPrepared, + }, }; -pub fn test_lwe_keyswitch<B>(module: &Module<B>) +pub fn test_lwe_keyswitch<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxAutomorphismInplace<B> - + ZnNormalizeInplace<B> - + ZnFillUniform - + ZnAddNormal - + VecZnxCopy, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: + LWEKeySwitch<BE> + LWESwitchingKeyEncrypt<BE> + LWEEncryptSk<BE> + LWESwitchingKeyPreparedFactory<BE> + LWEDecrypt<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let n: usize = module.n(); let base2k: usize = 17;@@ -86,21 +41,21 @@ k: k_ksk.into(),
dnum: dnum.into(), }; - let lwe_in_infos: LWECiphertextLayout = LWECiphertextLayout { + let lwe_in_infos: LWELayout = LWELayout { n: n_lwe_in.into(), base2k: base2k.into(), k: k_lwe_ct.into(), }; - let lwe_out_infos: LWECiphertextLayout = LWECiphertextLayout { + let lwe_out_infos: LWELayout = LWELayout { n: n_lwe_out.into(), k: k_lwe_ct.into(), base2k: base2k.into(), }; - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - LWESwitchingKey::encrypt_sk_scratch_space(module, &key_apply_infos) - | LWECiphertext::keyswitch_scratch_space(module, &lwe_out_infos, &lwe_in_infos, &key_apply_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + LWESwitchingKey::encrypt_sk_tmp_bytes(module, &key_apply_infos) + | LWE::keyswitch_tmp_bytes(module, &lwe_out_infos, &lwe_in_infos, &key_apply_infos), ); let mut sk_lwe_in: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe_in.into());@@ -111,10 +66,10 @@ sk_lwe_out.fill_ternary_prob(0.5, &mut source_xs);
let data: i64 = 17; - let mut lwe_pt_in: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_with(base2k.into(), k_lwe_pt.into()); + let mut lwe_pt_in: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(base2k.into(), k_lwe_pt.into()); lwe_pt_in.encode_i64(data, k_lwe_pt.into()); - let mut lwe_ct_in: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_in_infos); + let mut lwe_ct_in: LWE<Vec<u8>> = LWE::alloc_from_infos(&lwe_in_infos); lwe_ct_in.encrypt_sk( module, &lwe_pt_in,@@ -123,7 +78,7 @@ &mut source_xa,
&mut source_xe, ); - let mut ksk: LWESwitchingKey<Vec<u8>> = LWESwitchingKey::alloc(&key_apply_infos); + let mut ksk: LWESwitchingKey<Vec<u8>> = LWESwitchingKey::alloc_from_infos(&key_apply_infos); ksk.encrypt_sk( module,@@ -134,13 +89,14 @@ &mut source_xe,
scratch.borrow(), ); - let mut lwe_ct_out: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_out_infos); + let mut lwe_ct_out: LWE<Vec<u8>> = LWE::alloc_from_infos(&lwe_out_infos); - let ksk_prepared: LWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow()); + let mut ksk_prepared: LWESwitchingKeyPrepared<Vec<u8>, BE> = LWESwitchingKeyPrepared::alloc_from_infos(module, &ksk); + ksk_prepared.prepare(module, &ksk, scratch.borrow()); lwe_ct_out.keyswitch(module, &lwe_ct_in, &ksk_prepared, scratch.borrow()); - let mut lwe_pt_out: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(&lwe_out_infos); + let mut lwe_pt_out: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_from_infos(&lwe_out_infos); lwe_ct_out.decrypt(module, &mut lwe_pt_out, &sk_lwe_out); assert_eq!(lwe_pt_in.data.at(0, 0)[0], lwe_pt_out.data.at(0, 0)[0]);
@@ -1,78 +1,32 @@
use std::collections::HashMap; use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, - VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, VecZnxBigNormalize, - VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, - VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow}, + layouts::{Backend, Module, Scratch, ScratchOwned}, source::Source, }; use crate::{ - GLWEOperations, GLWEPacker, + GLWEAutomorphismKeyEncryptSk, GLWEDecrypt, GLWEEncryptSk, GLWEPacker, GLWEPacking, GLWERotate, GLWESub, ScratchTakeCore, layouts::{ - GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, - prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, PrepareAlloc}, + GLWE, GLWEAutomorphismKey, GLWEAutomorphismKeyLayout, GLWEAutomorphismKeyPreparedFactory, GLWELayout, GLWEPlaintext, + GLWESecret, GLWESecretPreparedFactory, + prepared::{GLWEAutomorphismKeyPrepared, GLWESecretPrepared}, }, }; -pub fn test_glwe_packing<B>(module: &Module<B>) +pub fn test_glwe_packing<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxAutomorphism - + VecZnxBigAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxNegateInplace - + VecZnxRshInplace<B> - + VecZnxRotateInplace<B> - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + VecZnxRotate - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxAutomorphismInplace<B> - + VecZnxCopy, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + Module<BE>: GLWEEncryptSk<BE> + + GLWEAutomorphismKeyEncryptSk<BE> + + GLWEAutomorphismKeyPreparedFactory<BE> + + GLWEPacking<BE> + + GLWESecretPreparedFactory<BE> + + GLWESub + + GLWEDecrypt<BE> + + GLWERotate<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let mut source_xs: Source = Source::new([0u8; 32]); let mut source_xe: Source = Source::new([0u8; 32]);@@ -88,14 +42,14 @@ let k_ksk: usize = k_ct + base2k * dsize;
let dnum: usize = k_ct.div_ceil(base2k * dsize); - let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_out_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k_ct.into(), rank: rank.into(), }; - let key_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let key_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_ksk.into(),@@ -104,17 +58,19 @@ dsize: dsize.into(),
dnum: dnum.into(), }; - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc( - GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_out_infos) - | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &key_infos) - | GLWEPacker::scratch_space(module, &glwe_out_infos, &key_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWE::encrypt_sk_tmp_bytes(module, &glwe_out_infos) + | GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &key_infos) + | GLWEPacker::tmp_bytes(module, &glwe_out_infos, &key_infos), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_out_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_out_infos); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_dft: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_dft: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk); + sk_dft.prepare(module, &sk); - let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos); + let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_infos); let mut data: Vec<i64> = vec![0i64; n]; data.iter_mut().enumerate().for_each(|(i, x)| { *x = i as i64;@@ -124,8 +80,8 @@ pt.encode_vec_i64(&data, pt_k.into());
let gal_els: Vec<i64> = GLWEPacker::galois_elements(module); - let mut auto_keys: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new(); - let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&key_infos); + let mut auto_keys: HashMap<i64, GLWEAutomorphismKeyPrepared<Vec<u8>, BE>> = HashMap::new(); + let mut tmp: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&key_infos); gal_els.iter().for_each(|gal_el| { tmp.encrypt_sk( module,@@ -135,15 +91,17 @@ &mut source_xa,
&mut source_xe, scratch.borrow(), ); - let atk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = tmp.prepare_alloc(module, scratch.borrow()); + let mut atk_prepared: GLWEAutomorphismKeyPrepared<Vec<u8>, BE> = + GLWEAutomorphismKeyPrepared::alloc_from_infos(module, &tmp); + atk_prepared.prepare(module, &tmp, scratch.borrow()); auto_keys.insert(*gal_el, atk_prepared); }); let log_batch: usize = 0; - let mut packer: GLWEPacker = GLWEPacker::new(&glwe_out_infos, log_batch); + let mut packer: GLWEPacker = GLWEPacker::alloc(&glwe_out_infos, log_batch); - let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos); + let mut ct: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos); ct.encrypt_sk( module,@@ -166,24 +124,19 @@ &mut source_xe,
scratch.borrow(), ); - pt.rotate_inplace(module, -(1 << log_batch), scratch.borrow()); // X^-batch * pt + module.glwe_rotate_inplace(-(1 << log_batch), &mut pt, scratch.borrow()); // X^-batch * pt if reverse_bits_msb(i, log_n as u32).is_multiple_of(5) { packer.add(module, Some(&ct), &auto_keys, scratch.borrow()); } else { - packer.add( - module, - None::<&GLWECiphertext<Vec<u8>>>, - &auto_keys, - scratch.borrow(), - ) + packer.add(module, None::<&GLWE<Vec<u8>>>, &auto_keys, scratch.borrow()) } }); - let mut res: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos); + let mut res: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos); packer.flush(module, &mut res); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_infos); let mut data: Vec<i64> = vec![0i64; n]; data.iter_mut().enumerate().for_each(|(i, x)| { if i.is_multiple_of(5) {@@ -195,7 +148,7 @@ pt_want.encode_vec_i64(&data, pt_k.into());
res.decrypt(module, &mut pt, &sk_dft, scratch.borrow()); - pt.sub_inplace_ab(module, &pt_want); + module.glwe_sub_inplace(&mut pt, &pt_want); let noise_have: f64 = pt.std().log2();
@@ -1,77 +1,36 @@
use std::collections::HashMap; use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxBigAddInplace, - VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, VecZnxBigNormalize, - VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, - VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, - VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Module, ScratchOwned, ZnxView, ZnxViewMut}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxImpl, - }, + api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform, VecZnxNormalizeInplace, VecZnxSubInplace}, + layouts::{Backend, Module, Scratch, ScratchOwned, ZnxView, ZnxViewMut}, source::Source, }; use crate::{ + GLWEAutomorphismKeyEncryptSk, GLWEDecrypt, GLWEEncryptSk, ScratchTakeCore, encryption::SIGMA, + glwe_trace::GLWETrace, layouts::{ - GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, - LWEInfos, - prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, PrepareAlloc}, + GLWE, GLWEAutomorphismKey, GLWEAutomorphismKeyLayout, GLWEAutomorphismKeyPreparedFactory, GLWELayout, GLWEPlaintext, + GLWESecret, GLWESecretPreparedFactory, LWEInfos, + prepared::{GLWEAutomorphismKeyPrepared, GLWESecretPrepared}, }, noise::var_noise_gglwe_product, }; -pub fn test_glwe_trace_inplace<B>(module: &Module<B>) +pub fn test_glwe_trace_inplace<BE: Backend>(module: &Module<BE>) where - Module<B>: VecZnxDftAllocBytes - + VecZnxAutomorphism - + VecZnxBigAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxRshInplace<B> - + VecZnxRotateInplace<B> - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> + Module<BE>: GLWETrace<BE> + + GLWEEncryptSk<BE> + + GLWEDecrypt<BE> + + GLWEAutomorphismKeyEncryptSk<BE> + + GLWEAutomorphismKeyPreparedFactory<BE> + VecZnxFillUniform + + GLWESecretPreparedFactory<BE> + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxBigAllocBytes - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxAddScalarInplace - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxBigNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxCopy, - B: Backend - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeSvpPPolImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + ScratchAvailableImpl<B> - + TakeScalarZnxImpl<B> - + TakeVecZnxImpl<B>, + + VecZnxNormalizeInplace<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>, { let base2k: usize = 8; let k: usize = 54;@@ -83,14 +42,14 @@
let dsize: usize = 1; let dnum: usize = k.div_ceil(base2k * dsize); - let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_out_infos: GLWELayout = GLWELayout { n: n.into(), base2k: base2k.into(), k: k.into(), rank: rank.into(), }; - let key_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout { + let key_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout { n: n.into(), base2k: base2k.into(), k: k_autokey.into(),@@ -99,24 +58,26 @@ dsize: dsize.into(),
dnum: dnum.into(), }; - let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos); - let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos); - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos); + let mut glwe_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_out_infos); + let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_infos); + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_out_infos); 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<B> = ScratchOwned::alloc( - GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_out_infos) - | GLWECiphertext::decrypt_scratch_space(module, &glwe_out_infos) - | GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &key_infos) - | GLWECiphertext::trace_inplace_scratch_space(module, &glwe_out_infos, &key_infos), + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + GLWE::encrypt_sk_tmp_bytes(module, &glwe_out_infos) + | GLWE::decrypt_tmp_bytes(module, &glwe_out_infos) + | GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &key_infos) + | GLWE::trace_tmp_bytes(module, &glwe_out_infos, &glwe_out_infos, &key_infos), ); - let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_out_infos); + let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_out_infos); sk.fill_ternary_prob(0.5, &mut source_xs); - let sk_dft: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow()); + + let mut sk_dft: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk); + sk_dft.prepare(module, &sk); let mut data_want: Vec<i64> = vec![0i64; n];@@ -135,9 +96,9 @@ &mut source_xe,
scratch.borrow(), ); - let mut auto_keys: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new(); - let gal_els: Vec<i64> = GLWECiphertext::trace_galois_elements(module); - let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&key_infos); + let mut auto_keys: HashMap<i64, GLWEAutomorphismKeyPrepared<Vec<u8>, BE>> = HashMap::new(); + let gal_els: Vec<i64> = GLWE::trace_galois_elements(module); + let mut tmp: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&key_infos); gal_els.iter().for_each(|gal_el| { tmp.encrypt_sk( module,@@ -147,7 +108,9 @@ &mut source_xa,
&mut source_xe, scratch.borrow(), ); - let atk_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> = tmp.prepare_alloc(module, scratch.borrow()); + let mut atk_prepared: GLWEAutomorphismKeyPrepared<Vec<u8>, BE> = + GLWEAutomorphismKeyPrepared::alloc_from_infos(module, &tmp); + atk_prepared.prepare(module, &tmp, scratch.borrow()); auto_keys.insert(*gal_el, atk_prepared); });
@@ -4,3 +4,16 @@ /// Instantiate a new [crate::layouts::Module].
pub trait ModuleNew<B: Backend> { fn new(n: u64) -> Self; } + +pub trait ModuleN { + fn n(&self) -> usize; +} + +pub trait ModuleLogN +where + Self: ModuleN, +{ + fn log_n(&self) -> usize { + (u64::BITS - (self.n() as u64 - 1).leading_zeros()) as usize + } +}
@@ -1,4 +1,7 @@
-use crate::layouts::{Backend, MatZnx, ScalarZnx, Scratch, SvpPPol, VecZnx, VecZnxBig, VecZnxDft, VmpPMat}; +use crate::{ + api::{ModuleN, SvpPPolBytesOf, VecZnxBigBytesOf, VecZnxDftBytesOf, VmpPMatBytesOf}, + layouts::{Backend, MatZnx, ScalarZnx, Scratch, SvpPPol, VecZnx, VecZnxBig, VecZnxDft, VmpPMat}, +}; /// Allocates a new [crate::layouts::ScratchOwned] of `size` aligned bytes. pub trait ScratchOwnedAlloc<B: Backend> {@@ -25,70 +28,102 @@ pub trait TakeSlice {
fn take_slice<T>(&mut self, len: usize) -> (&mut [T], &mut Self); } -/// Take a slice of bytes from a [Scratch], wraps it into a [ScalarZnx] and returns it -/// as well as a new [Scratch] minus the taken array of bytes. -pub trait TakeScalarZnx { - fn take_scalar_znx(&mut self, n: usize, cols: usize) -> (ScalarZnx<&mut [u8]>, &mut Self); -} +impl<B: Backend> ScratchTakeBasic for Scratch<B> where Self: TakeSlice {} -/// Take a slice of bytes from a [Scratch], wraps it into a [SvpPPol] and returns it -/// as well as a new [Scratch] minus the taken array of bytes. -pub trait TakeSvpPPol<B: Backend> { - fn take_svp_ppol(&mut self, n: usize, cols: usize) -> (SvpPPol<&mut [u8], B>, &mut Self); -} +pub trait ScratchTakeBasic +where + Self: TakeSlice, +{ + fn take_scalar_znx(&mut self, n: usize, cols: usize) -> (ScalarZnx<&mut [u8]>, &mut Self) { + let (take_slice, rem_slice) = self.take_slice(ScalarZnx::bytes_of(n, cols)); + (ScalarZnx::from_data(take_slice, n, cols), rem_slice) + } -/// Take a slice of bytes from a [Scratch], wraps it into a [VecZnx] and returns it -/// as well as a new [Scratch] minus the taken array of bytes. -pub trait TakeVecZnx { - fn take_vec_znx(&mut self, n: usize, cols: usize, size: usize) -> (VecZnx<&mut [u8]>, &mut Self); -} + fn take_svp_ppol<M, B: Backend>(&mut self, module: &M, cols: usize) -> (SvpPPol<&mut [u8], B>, &mut Self) + where + M: SvpPPolBytesOf + ModuleN, + { + let (take_slice, rem_slice) = self.take_slice(module.bytes_of_svp_ppol(cols)); + (SvpPPol::from_data(take_slice, module.n(), cols), rem_slice) + } -/// Take a slice of bytes from a [Scratch], slices it into a vector of [VecZnx] aand returns it -/// as well as a new [Scratch] minus the taken array of bytes. -pub trait TakeVecZnxSlice { - fn take_vec_znx_slice(&mut self, len: usize, n: usize, cols: usize, size: usize) -> (Vec<VecZnx<&mut [u8]>>, &mut Self); -} + fn take_vec_znx(&mut self, n: usize, cols: usize, size: usize) -> (VecZnx<&mut [u8]>, &mut Self) { + let (take_slice, rem_slice) = self.take_slice(VecZnx::bytes_of(n, cols, size)); + (VecZnx::from_data(take_slice, n, cols, size), rem_slice) + } + + fn take_vec_znx_big<M, B: Backend>(&mut self, module: &M, cols: usize, size: usize) -> (VecZnxBig<&mut [u8], B>, &mut Self) + where + M: VecZnxBigBytesOf + ModuleN, + { + let (take_slice, rem_slice) = self.take_slice(module.bytes_of_vec_znx_big(cols, size)); + ( + VecZnxBig::from_data(take_slice, module.n(), cols, size), + rem_slice, + ) + } -/// Take a slice of bytes from a [Scratch], wraps it into a [VecZnxBig] and returns it -/// as well as a new [Scratch] minus the taken array of bytes. -pub trait TakeVecZnxBig<B: Backend> { - fn take_vec_znx_big(&mut self, n: usize, cols: usize, size: usize) -> (VecZnxBig<&mut [u8], B>, &mut Self); -} + fn take_vec_znx_dft<M, B: Backend>(&mut self, module: &M, cols: usize, size: usize) -> (VecZnxDft<&mut [u8], B>, &mut Self) + where + M: VecZnxDftBytesOf + ModuleN, + { + let (take_slice, rem_slice) = self.take_slice(module.bytes_of_vec_znx_dft(cols, size)); -/// Take a slice of bytes from a [Scratch], wraps it into a [VecZnxDft] and returns it -/// as well as a new [Scratch] minus the taken array of bytes. -pub trait TakeVecZnxDft<B: Backend> { - fn take_vec_znx_dft(&mut self, n: usize, cols: usize, size: usize) -> (VecZnxDft<&mut [u8], B>, &mut Self); -} + ( + VecZnxDft::from_data(take_slice, module.n(), cols, size), + rem_slice, + ) + } -/// Take a slice of bytes from a [Scratch], slices it into a vector of [VecZnxDft] and returns it -/// as well as a new [Scratch] minus the taken array of bytes. -pub trait TakeVecZnxDftSlice<B: Backend> { - fn take_vec_znx_dft_slice( + fn take_vec_znx_dft_slice<M, B: Backend>( &mut self, + module: &M, len: usize, - n: usize, cols: usize, size: usize, - ) -> (Vec<VecZnxDft<&mut [u8], B>>, &mut Self); -} + ) -> (Vec<VecZnxDft<&mut [u8], B>>, &mut Self) + where + M: VecZnxDftBytesOf + ModuleN, + { + let mut scratch: &mut Self = self; + let mut slice: Vec<VecZnxDft<&mut [u8], B>> = Vec::with_capacity(len); + for _ in 0..len { + let (znx, new_scratch) = scratch.take_vec_znx_dft(module, cols, size); + scratch = new_scratch; + slice.push(znx); + } + (slice, scratch) + } + + fn take_vec_znx_slice(&mut self, len: usize, n: usize, cols: usize, size: usize) -> (Vec<VecZnx<&mut [u8]>>, &mut Self) { + let mut scratch: &mut Self = self; + let mut slice: Vec<VecZnx<&mut [u8]>> = Vec::with_capacity(len); + for _ in 0..len { + let (znx, new_scratch) = scratch.take_vec_znx(n, cols, size); + scratch = new_scratch; + slice.push(znx); + } + (slice, scratch) + } -/// Take a slice of bytes from a [Scratch], wraps it into a [VmpPMat] and returns it -/// as well as a new [Scratch] minus the taken array of bytes. -pub trait TakeVmpPMat<B: Backend> { - fn take_vmp_pmat( + fn take_vmp_pmat<M, B: Backend>( &mut self, - n: usize, + module: &M, rows: usize, cols_in: usize, cols_out: usize, size: usize, - ) -> (VmpPMat<&mut [u8], B>, &mut Self); -} + ) -> (VmpPMat<&mut [u8], B>, &mut Self) + where + M: VmpPMatBytesOf + ModuleN, + { + let (take_slice, rem_slice) = self.take_slice(module.bytes_of_vmp_pmat(rows, cols_in, cols_out, size)); + ( + VmpPMat::from_data(take_slice, module.n(), rows, cols_in, cols_out, size), + rem_slice, + ) + } -/// Take a slice of bytes from a [Scratch], wraps it into a [MatZnx] and returns it -/// as well as a new [Scratch] minus the taken array of bytes. -pub trait TakeMatZnx { fn take_mat_znx( &mut self, n: usize,@@ -96,5 +131,11 @@ rows: usize,
cols_in: usize, cols_out: usize, size: usize, - ) -> (MatZnx<&mut [u8]>, &mut Self); + ) -> (MatZnx<&mut [u8]>, &mut Self) { + let (take_slice, rem_slice) = self.take_slice(MatZnx::bytes_of(n, rows, cols_in, cols_out, size)); + ( + MatZnx::from_data(take_slice, n, rows, cols_in, cols_out, size), + rem_slice, + ) + } }
@@ -8,8 +8,8 @@ fn svp_ppol_alloc(&self, cols: usize) -> SvpPPolOwned<B>;
} /// Returns the size in bytes to allocate a [crate::layouts::SvpPPol]. -pub trait SvpPPolAllocBytes { - fn svp_ppol_alloc_bytes(&self, cols: usize) -> usize; +pub trait SvpPPolBytesOf { + fn bytes_of_svp_ppol(&self, cols: usize) -> usize; } /// Consume a vector of bytes into a [crate::layouts::MatZnx].
@@ -16,8 +16,8 @@ fn vec_znx_big_alloc(&self, cols: usize, size: usize) -> VecZnxBigOwned<B>;
} /// Returns the size in bytes to allocate a [crate::layouts::VecZnxBig]. -pub trait VecZnxBigAllocBytes { - fn vec_znx_big_alloc_bytes(&self, cols: usize, size: usize) -> usize; +pub trait VecZnxBigBytesOf { + fn bytes_of_vec_znx_big(&self, cols: usize, size: usize) -> usize; } /// Consume a vector of bytes into a [crate::layouts::VecZnxBig].
@@ -10,8 +10,8 @@ pub trait VecZnxDftFromBytes<B: Backend> {
fn vec_znx_dft_from_bytes(&self, cols: usize, size: usize, bytes: Vec<u8>) -> VecZnxDftOwned<B>; } -pub trait VecZnxDftAllocBytes { - fn vec_znx_dft_alloc_bytes(&self, cols: usize, size: usize) -> usize; +pub trait VecZnxDftBytesOf { + fn bytes_of_vec_znx_dft(&self, cols: usize, size: usize) -> usize; } pub trait VecZnxDftApply<B: Backend> {
@@ -6,8 +6,8 @@ pub trait VmpPMatAlloc<B: Backend> {
fn vmp_pmat_alloc(&self, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> VmpPMatOwned<B>; } -pub trait VmpPMatAllocBytes { - fn vmp_pmat_alloc_bytes(&self, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize; +pub trait VmpPMatBytesOf { + fn bytes_of_vmp_pmat(&self, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize; } pub trait VmpPMatFromBytes<B: Backend> {
@@ -1,5 +1,5 @@
use crate::{ - api::ModuleNew, + api::{ModuleN, ModuleNew}, layouts::{Backend, Module}, oep::ModuleNewImpl, };@@ -12,3 +12,12 @@ fn new(n: u64) -> Self {
B::new_impl(n) } } + +impl<B> ModuleN for Module<B> +where + B: Backend, +{ + fn n(&self) -> usize { + self.n() + } +}
@@ -1,14 +1,7 @@
use crate::{ - api::{ - ScratchAvailable, ScratchFromBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, TakeMatZnx, TakeScalarZnx, TakeSlice, - TakeSvpPPol, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, TakeVecZnxDftSlice, TakeVecZnxSlice, TakeVmpPMat, - }, - layouts::{Backend, MatZnx, ScalarZnx, Scratch, ScratchOwned, SvpPPol, VecZnx, VecZnxBig, VecZnxDft, VmpPMat}, - oep::{ - ScratchAvailableImpl, ScratchFromBytesImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeMatZnxImpl, - TakeScalarZnxImpl, TakeSliceImpl, TakeSvpPPolImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, - TakeVecZnxImpl, TakeVecZnxSliceImpl, TakeVmpPMatImpl, - }, + api::{ScratchAvailable, ScratchFromBytes, ScratchOwnedAlloc, ScratchOwnedBorrow, TakeSlice}, + layouts::{Backend, Scratch, ScratchOwned}, + oep::{ScratchAvailableImpl, ScratchFromBytesImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeSliceImpl}, }; impl<B> ScratchOwnedAlloc<B> for ScratchOwned<B>@@ -55,104 +48,3 @@ fn take_slice<T>(&mut self, len: usize) -> (&mut [T], &mut Self) {
B::take_slice_impl(self, len) } } - -impl<B> TakeScalarZnx for Scratch<B> -where - B: Backend + TakeScalarZnxImpl<B>, -{ - fn take_scalar_znx(&mut self, n: usize, cols: usize) -> (ScalarZnx<&mut [u8]>, &mut Self) { - B::take_scalar_znx_impl(self, n, cols) - } -} - -impl<B> TakeSvpPPol<B> for Scratch<B> -where - B: Backend + TakeSvpPPolImpl<B>, -{ - fn take_svp_ppol(&mut self, n: usize, cols: usize) -> (SvpPPol<&mut [u8], B>, &mut Self) { - B::take_svp_ppol_impl(self, n, cols) - } -} - -impl<B> TakeVecZnx for Scratch<B> -where - B: Backend + TakeVecZnxImpl<B>, -{ - fn take_vec_znx(&mut self, n: usize, cols: usize, size: usize) -> (VecZnx<&mut [u8]>, &mut Self) { - B::take_vec_znx_impl(self, n, cols, size) - } -} - -impl<B> TakeVecZnxSlice for Scratch<B> -where - B: Backend + TakeVecZnxSliceImpl<B>, -{ - fn take_vec_znx_slice(&mut self, len: usize, n: usize, cols: usize, size: usize) -> (Vec<VecZnx<&mut [u8]>>, &mut Self) { - B::take_vec_znx_slice_impl(self, len, n, cols, size) - } -} - -impl<B> TakeVecZnxBig<B> for Scratch<B> -where - B: Backend + TakeVecZnxBigImpl<B>, -{ - fn take_vec_znx_big(&mut self, n: usize, cols: usize, size: usize) -> (VecZnxBig<&mut [u8], B>, &mut Self) { - B::take_vec_znx_big_impl(self, n, cols, size) - } -} - -impl<B> TakeVecZnxDft<B> for Scratch<B> -where - B: Backend + TakeVecZnxDftImpl<B>, -{ - fn take_vec_znx_dft(&mut self, n: usize, cols: usize, size: usize) -> (VecZnxDft<&mut [u8], B>, &mut Self) { - B::take_vec_znx_dft_impl(self, n, cols, size) - } -} - -impl<B> TakeVecZnxDftSlice<B> for Scratch<B> -where - B: Backend + TakeVecZnxDftSliceImpl<B>, -{ - fn take_vec_znx_dft_slice( - &mut self, - len: usize, - n: usize, - cols: usize, - size: usize, - ) -> (Vec<VecZnxDft<&mut [u8], B>>, &mut Self) { - B::take_vec_znx_dft_slice_impl(self, len, n, cols, size) - } -} - -impl<B> TakeVmpPMat<B> for Scratch<B> -where - B: Backend + TakeVmpPMatImpl<B>, -{ - fn take_vmp_pmat( - &mut self, - n: usize, - rows: usize, - cols_in: usize, - cols_out: usize, - size: usize, - ) -> (VmpPMat<&mut [u8], B>, &mut Self) { - B::take_vmp_pmat_impl(self, n, rows, cols_in, cols_out, size) - } -} - -impl<B> TakeMatZnx for Scratch<B> -where - B: Backend + TakeMatZnxImpl<B>, -{ - fn take_mat_znx( - &mut self, - n: usize, - rows: usize, - cols_in: usize, - cols_out: usize, - size: usize, - ) -> (MatZnx<&mut [u8]>, &mut Self) { - B::take_mat_znx_impl(self, n, rows, cols_in, cols_out, size) - } -}
@@ -1,6 +1,6 @@
use crate::{ api::{ - SvpApplyDft, SvpApplyDftToDft, SvpApplyDftToDftAdd, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, + SvpApplyDft, SvpApplyDftToDft, SvpApplyDftToDftAdd, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolBytesOf, SvpPPolFromBytes, SvpPrepare, }, layouts::{@@ -30,12 +30,12 @@ B::svp_ppol_alloc_impl(self.n(), cols)
} } -impl<B> SvpPPolAllocBytes for Module<B> +impl<B> SvpPPolBytesOf for Module<B> where B: Backend + SvpPPolAllocBytesImpl<B>, { - fn svp_ppol_alloc_bytes(&self, cols: usize) -> usize { - B::svp_ppol_alloc_bytes_impl(self.n(), cols) + fn bytes_of_svp_ppol(&self, cols: usize) -> usize { + B::svp_ppol_bytes_of_impl(self.n(), cols) } }
@@ -1,7 +1,7 @@
use crate::{ api::{ VecZnxBigAdd, VecZnxBigAddInplace, VecZnxBigAddNormal, VecZnxBigAddSmall, VecZnxBigAddSmallInplace, VecZnxBigAlloc, - VecZnxBigAllocBytes, VecZnxBigAutomorphism, VecZnxBigAutomorphismInplace, VecZnxBigAutomorphismInplaceTmpBytes, + VecZnxBigAutomorphism, VecZnxBigAutomorphismInplace, VecZnxBigAutomorphismInplaceTmpBytes, VecZnxBigBytesOf, VecZnxBigFromBytes, VecZnxBigFromSmall, VecZnxBigNegate, VecZnxBigNegateInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSub, VecZnxBigSubInplace, VecZnxBigSubNegateInplace, VecZnxBigSubSmallA, VecZnxBigSubSmallB, VecZnxBigSubSmallInplace, VecZnxBigSubSmallNegateInplace,@@ -49,12 +49,12 @@ B::vec_znx_big_from_bytes_impl(self.n(), cols, size, bytes)
} } -impl<B> VecZnxBigAllocBytes for Module<B> +impl<B> VecZnxBigBytesOf for Module<B> where B: Backend + VecZnxBigAllocBytesImpl<B>, { - fn vec_znx_big_alloc_bytes(&self, cols: usize, size: usize) -> usize { - B::vec_znx_big_alloc_bytes_impl(self.n(), cols, size) + fn bytes_of_vec_znx_big(&self, cols: usize, size: usize) -> usize { + B::vec_znx_big_bytes_of_impl(self.n(), cols, size) } }
@@ -1,8 +1,8 @@
use crate::{ api::{ - VecZnxDftAdd, VecZnxDftAddInplace, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, - VecZnxDftFromBytes, VecZnxDftSub, VecZnxDftSubInplace, VecZnxDftSubNegateInplace, VecZnxDftZero, VecZnxIdftApply, - VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxIdftApplyTmpBytes, + VecZnxDftAdd, VecZnxDftAddInplace, VecZnxDftAlloc, VecZnxDftApply, VecZnxDftBytesOf, VecZnxDftCopy, VecZnxDftFromBytes, + VecZnxDftSub, VecZnxDftSubInplace, VecZnxDftSubNegateInplace, VecZnxDftZero, VecZnxIdftApply, VecZnxIdftApplyConsume, + VecZnxIdftApplyTmpA, VecZnxIdftApplyTmpBytes, }, layouts::{ Backend, Data, Module, Scratch, VecZnxBig, VecZnxBigToMut, VecZnxDft, VecZnxDftOwned, VecZnxDftToMut, VecZnxDftToRef,@@ -24,12 +24,12 @@ B::vec_znx_dft_from_bytes_impl(self.n(), cols, size, bytes)
} } -impl<B> VecZnxDftAllocBytes for Module<B> +impl<B> VecZnxDftBytesOf for Module<B> where B: Backend + VecZnxDftAllocBytesImpl<B>, { - fn vec_znx_dft_alloc_bytes(&self, cols: usize, size: usize) -> usize { - B::vec_znx_dft_alloc_bytes_impl(self.n(), cols, size) + fn bytes_of_vec_znx_dft(&self, cols: usize, size: usize) -> usize { + B::vec_znx_dft_bytes_of_impl(self.n(), cols, size) } }
@@ -1,7 +1,7 @@
use crate::{ api::{ VmpApplyDft, VmpApplyDftTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftAddTmpBytes, - VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatFromBytes, VmpPrepare, VmpPrepareTmpBytes, + VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPMatBytesOf, VmpPMatFromBytes, VmpPrepare, VmpPrepareTmpBytes, }, layouts::{ Backend, MatZnxToRef, Module, Scratch, VecZnxDftToMut, VecZnxDftToRef, VecZnxToRef, VmpPMatOwned, VmpPMatToMut,@@ -23,12 +23,12 @@ B::vmp_pmat_alloc_impl(self.n(), rows, cols_in, cols_out, size)
} } -impl<B> VmpPMatAllocBytes for Module<B> +impl<B> VmpPMatBytesOf for Module<B> where B: Backend + VmpPMatAllocBytesImpl<B>, { - fn vmp_pmat_alloc_bytes(&self, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize { - B::vmp_pmat_alloc_bytes_impl(self.n(), rows, cols_in, cols_out, size) + fn bytes_of_vmp_pmat(&self, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize { + B::vmp_pmat_bytes_of_impl(self.n(), rows, cols_in, cols_out, size) } }
@@ -114,12 +114,12 @@ }
} impl MatZnx<Vec<u8>> { - pub fn alloc_bytes(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize { - rows * cols_in * VecZnx::<Vec<u8>>::alloc_bytes(n, cols_out, size) + pub fn bytes_of(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize { + rows * cols_in * VecZnx::<Vec<u8>>::bytes_of(n, cols_out, size) } pub fn alloc(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> Self { - let data: Vec<u8> = alloc_aligned(Self::alloc_bytes(n, rows, cols_in, cols_out, size)); + let data: Vec<u8> = alloc_aligned(Self::bytes_of(n, rows, cols_in, cols_out, size)); Self { data, n,@@ -132,7 +132,7 @@ }
pub fn from_bytes(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize, bytes: impl Into<Vec<u8>>) -> Self { let data: Vec<u8> = bytes.into(); - assert!(data.len() == Self::alloc_bytes(n, rows, cols_in, cols_out, size)); + assert!(data.len() == Self::bytes_of(n, rows, cols_in, cols_out, size)); Self { data, n,@@ -153,7 +153,7 @@ assert!(col < self.cols_in(), "cols: {} >= {}", col, self.cols_in());
} let self_ref: MatZnx<&[u8]> = self.to_ref(); - let nb_bytes: usize = VecZnx::<Vec<u8>>::alloc_bytes(self.n, self.cols_out, self.size); + let nb_bytes: usize = VecZnx::<Vec<u8>>::bytes_of(self.n, self.cols_out, self.size); let start: usize = nb_bytes * self.cols() * row + col * nb_bytes; let end: usize = start + nb_bytes;@@ -181,7 +181,7 @@ let cols_in: usize = self.cols_in();
let size: usize = self.size(); let self_ref: MatZnx<&mut [u8]> = self.to_mut(); - let nb_bytes: usize = VecZnx::<Vec<u8>>::alloc_bytes(n, cols_out, size); + let nb_bytes: usize = VecZnx::<Vec<u8>>::bytes_of(n, cols_out, size); let start: usize = nb_bytes * cols_in * row + col * nb_bytes; let end: usize = start + nb_bytes;
@@ -1,13 +1,20 @@
-use std::{fmt::Display, marker::PhantomData, ptr::NonNull}; +use std::{ + fmt::{Debug, Display}, + marker::PhantomData, + ptr::NonNull, +}; use rand_distr::num_traits::Zero; -use crate::GALOISGENERATOR; +use crate::{ + GALOISGENERATOR, + api::{ModuleLogN, ModuleN}, +}; #[allow(clippy::missing_safety_doc)] pub trait Backend: Sized { - type ScalarBig: Copy + Zero + Display; - type ScalarPrep: Copy + Zero + Display; + type ScalarBig: Copy + Zero + Display + Debug; + type ScalarPrep: Copy + Zero + Display + Debug; type Handle: 'static; fn layout_prep_word_count() -> usize; fn layout_big_word_count() -> usize;@@ -75,35 +82,55 @@ #[inline]
pub fn log_n(&self) -> usize { (usize::BITS - (self.n() - 1).leading_zeros()) as _ } +} - #[inline] - pub fn cyclotomic_order(&self) -> u64 { +pub trait CyclotomicOrder +where + Self: ModuleN, +{ + fn cyclotomic_order(&self) -> i64 { (self.n() << 1) as _ } +} +impl<BE: Backend> ModuleLogN for Module<BE> where Self: ModuleN {} + +impl<BE: Backend> CyclotomicOrder for Module<BE> where Self: ModuleN {} + +#[inline(always)] +pub fn galois_element(generator: i64, cyclotomic_order: i64) -> i64 { + if generator == 0 { + return 1; + } + + let g_exp: u64 = mod_exp_u64(GALOISGENERATOR, generator.unsigned_abs() as usize) & (cyclotomic_order - 1) as u64; + g_exp as i64 * generator.signum() +} + +pub trait GaloisElement +where + Self: CyclotomicOrder, +{ // Returns GALOISGENERATOR^|generator| * sign(generator) - #[inline] - pub fn galois_element(&self, generator: i64) -> i64 { - if generator == 0 { - return 1; - } - ((mod_exp_u64(GALOISGENERATOR, generator.unsigned_abs() as usize) & (self.cyclotomic_order() - 1)) as i64) - * generator.signum() + fn galois_element(&self, generator: i64) -> i64 { + galois_element(generator, self.cyclotomic_order()) } // Returns gen^-1 - #[inline] - pub fn galois_element_inv(&self, gal_el: i64) -> i64 { + fn galois_element_inv(&self, gal_el: i64) -> i64 { if gal_el == 0 { panic!("cannot invert 0") } - ((mod_exp_u64( + + let g_exp: u64 = mod_exp_u64( gal_el.unsigned_abs(), (self.cyclotomic_order() - 1) as usize, - ) & (self.cyclotomic_order() - 1)) as i64) - * gal_el.signum() + ) & (self.cyclotomic_order() - 1) as u64; + g_exp as i64 * gal_el.signum() } } + +impl<BE: Backend> GaloisElement for Module<BE> where Self: CyclotomicOrder {} impl<B: Backend> Drop for Module<B> { fn drop(&mut self) {
@@ -132,18 +132,18 @@ }
} impl ScalarZnx<Vec<u8>> { - pub fn alloc_bytes(n: usize, cols: usize) -> usize { + pub fn bytes_of(n: usize, cols: usize) -> usize { n * cols * size_of::<i64>() } pub fn alloc(n: usize, cols: usize) -> Self { - let data: Vec<u8> = alloc_aligned::<u8>(Self::alloc_bytes(n, cols)); + let data: Vec<u8> = alloc_aligned::<u8>(Self::bytes_of(n, cols)); Self { data, n, cols } } pub fn from_bytes(n: usize, cols: usize, bytes: impl Into<Vec<u8>>) -> Self { let data: Vec<u8> = bytes.into(); - assert!(data.len() == Self::alloc_bytes(n, cols)); + assert!(data.len() == Self::bytes_of(n, cols)); Self { data, n, cols } } }
@@ -77,7 +77,7 @@ where
B: SvpPPolAllocBytesImpl<B>, { pub fn alloc(n: usize, cols: usize) -> Self { - let data: Vec<u8> = alloc_aligned::<u8>(B::svp_ppol_alloc_bytes_impl(n, cols)); + let data: Vec<u8> = alloc_aligned::<u8>(B::svp_ppol_bytes_of_impl(n, cols)); Self { data: data.into(), n,@@ -88,7 +88,7 @@ }
pub fn from_bytes(n: usize, cols: usize, bytes: impl Into<Vec<u8>>) -> Self { let data: Vec<u8> = bytes.into(); - assert!(data.len() == B::svp_ppol_alloc_bytes_impl(n, cols)); + assert!(data.len() == B::svp_ppol_bytes_of_impl(n, cols)); Self { data: data.into(), n,
@@ -110,7 +110,7 @@ type Scalar = i64;
} impl VecZnx<Vec<u8>> { - pub fn rsh_scratch_space(n: usize) -> usize { + pub fn rsh_tmp_bytes(n: usize) -> usize { n * std::mem::size_of::<i64>() } }@@ -125,12 +125,12 @@ }
} impl VecZnx<Vec<u8>> { - pub fn alloc_bytes(n: usize, cols: usize, size: usize) -> usize { + pub fn bytes_of(n: usize, cols: usize, size: usize) -> usize { n * cols * size * size_of::<i64>() } pub fn alloc(n: usize, cols: usize, size: usize) -> Self { - let data: Vec<u8> = alloc_aligned::<u8>(Self::alloc_bytes(n, cols, size)); + let data: Vec<u8> = alloc_aligned::<u8>(Self::bytes_of(n, cols, size)); Self { data, n,@@ -142,7 +142,7 @@ }
pub fn from_bytes<Scalar: Sized>(n: usize, cols: usize, size: usize, bytes: impl Into<Vec<u8>>) -> Self { let data: Vec<u8> = bytes.into(); - assert!(data.len() == Self::alloc_bytes(n, cols, size)); + assert!(data.len() == Self::bytes_of(n, cols, size)); Self { data, n,
@@ -96,7 +96,7 @@ where
B: VecZnxBigAllocBytesImpl<B>, { pub fn alloc(n: usize, cols: usize, size: usize) -> Self { - let data = alloc_aligned::<u8>(B::vec_znx_big_alloc_bytes_impl(n, cols, size)); + let data = alloc_aligned::<u8>(B::vec_znx_big_bytes_of_impl(n, cols, size)); Self { data: data.into(), n,@@ -109,7 +109,7 @@ }
pub fn from_bytes(n: usize, cols: usize, size: usize, bytes: impl Into<Vec<u8>>) -> Self { let data: Vec<u8> = bytes.into(); - assert!(data.len() == B::vec_znx_big_alloc_bytes_impl(n, cols, size)); + assert!(data.len() == B::vec_znx_big_bytes_of_impl(n, cols, size)); Self { data: data.into(), n,
@@ -116,7 +116,7 @@ where
B: VecZnxDftAllocBytesImpl<B>, { pub fn alloc(n: usize, cols: usize, size: usize) -> Self { - let data: Vec<u8> = alloc_aligned::<u8>(B::vec_znx_dft_alloc_bytes_impl(n, cols, size)); + let data: Vec<u8> = alloc_aligned::<u8>(B::vec_znx_dft_bytes_of_impl(n, cols, size)); Self { data: data.into(), n,@@ -129,7 +129,7 @@ }
pub fn from_bytes(n: usize, cols: usize, size: usize, bytes: impl Into<Vec<u8>>) -> Self { let data: Vec<u8> = bytes.into(); - assert!(data.len() == B::vec_znx_dft_alloc_bytes_impl(n, cols, size)); + assert!(data.len() == B::vec_znx_dft_bytes_of_impl(n, cols, size)); Self { data: data.into(), n,
@@ -88,9 +88,7 @@ where
B: VmpPMatAllocBytesImpl<B>, { pub fn alloc(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> Self { - let data: Vec<u8> = alloc_aligned(B::vmp_pmat_alloc_bytes_impl( - n, rows, cols_in, cols_out, size, - )); + let data: Vec<u8> = alloc_aligned(B::vmp_pmat_bytes_of_impl(n, rows, cols_in, cols_out, size)); Self { data: data.into(), n,@@ -104,7 +102,7 @@ }
pub fn from_bytes(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize, bytes: impl Into<Vec<u8>>) -> Self { let data: Vec<u8> = bytes.into(); - assert!(data.len() == B::vmp_pmat_alloc_bytes_impl(n, rows, cols_in, cols_out, size)); + assert!(data.len() == B::vmp_pmat_bytes_of_impl(n, rows, cols_in, cols_out, size)); Self { data: data.into(), n,
@@ -98,7 +98,7 @@ type Scalar = i64;
} impl Zn<Vec<u8>> { - pub fn rsh_scratch_space(n: usize) -> usize { + pub fn rsh_tmp_bytes(n: usize) -> usize { n * std::mem::size_of::<i64>() } }@@ -113,12 +113,12 @@ }
} impl Zn<Vec<u8>> { - pub fn alloc_bytes(n: usize, cols: usize, size: usize) -> usize { + pub fn bytes_of(n: usize, cols: usize, size: usize) -> usize { n * cols * size * size_of::<i64>() } pub fn alloc(n: usize, cols: usize, size: usize) -> Self { - let data: Vec<u8> = alloc_aligned::<u8>(Self::alloc_bytes(n, cols, size)); + let data: Vec<u8> = alloc_aligned::<u8>(Self::bytes_of(n, cols, size)); Self { data, n,@@ -130,7 +130,7 @@ }
pub fn from_bytes<Scalar: Sized>(n: usize, cols: usize, size: usize, bytes: impl Into<Vec<u8>>) -> Self { let data: Vec<u8> = bytes.into(); - assert!(data.len() == Self::alloc_bytes(n, cols, size)); + assert!(data.len() == Self::bytes_of(n, cols, size)); Self { data, n,
@@ -1,3 +1,5 @@
+use std::fmt::{Debug, Display}; + use crate::{ layouts::{Backend, Data, DataMut, DataRef}, source::Source,@@ -48,7 +50,7 @@ fn data_mut(&mut self) -> &mut Self::D;
} pub trait ZnxView: ZnxInfos + DataView<D: DataRef> { - type Scalar: Copy + Zero; + type Scalar: Copy + Zero + Display + Debug; /// Returns a non-mutable pointer to the underlying coefficients array. fn as_ptr(&self) -> *const Self::Scalar {
@@ -1,4 +1,4 @@
-use crate::layouts::{Backend, MatZnx, ScalarZnx, Scratch, ScratchOwned, SvpPPol, VecZnx, VecZnxBig, VecZnxDft, VmpPMat}; +use crate::layouts::{Backend, Scratch, ScratchOwned}; /// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe) /// * See the [poulpy-backend/src/cpu_fft64_ref/scratch.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/scratch.rs) reference implementation.@@ -39,111 +39,3 @@ /// # Safety [crate::doc::backend_safety] for safety contract.
pub unsafe trait TakeSliceImpl<B: Backend> { fn take_slice_impl<T>(scratch: &mut Scratch<B>, len: usize) -> (&mut [T], &mut Scratch<B>); } - -/// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe) -/// * See the [poulpy-backend/src/cpu_fft64_ref/scratch.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/scratch.rs) reference implementation. -/// * See [crate::api::TakeScalarZnx] for corresponding public API. -/// # Safety [crate::doc::backend_safety] for safety contract. -pub unsafe trait TakeScalarZnxImpl<B: Backend> { - fn take_scalar_znx_impl(scratch: &mut Scratch<B>, n: usize, cols: usize) -> (ScalarZnx<&mut [u8]>, &mut Scratch<B>); -} - -/// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe) -/// * See the [poulpy-backend/src/cpu_fft64_ref/scratch.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/scratch.rs) reference implementation. -/// * See [crate::api::TakeSvpPPol] for corresponding public API. -/// # Safety [crate::doc::backend_safety] for safety contract. -pub unsafe trait TakeSvpPPolImpl<B: Backend> { - fn take_svp_ppol_impl(scratch: &mut Scratch<B>, n: usize, cols: usize) -> (SvpPPol<&mut [u8], B>, &mut Scratch<B>); -} - -/// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe) -/// * See the [poulpy-backend/src/cpu_fft64_ref/scratch.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/scratch.rs) reference implementation. -/// * See [crate::api::TakeVecZnx] for corresponding public API. -/// # Safety [crate::doc::backend_safety] for safety contract. -pub unsafe trait TakeVecZnxImpl<B: Backend> { - fn take_vec_znx_impl(scratch: &mut Scratch<B>, n: usize, cols: usize, size: usize) -> (VecZnx<&mut [u8]>, &mut Scratch<B>); -} - -/// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe) -/// * See the [poulpy-backend/src/cpu_fft64_ref/scratch.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/scratch.rs) reference implementation. -/// * See [crate::api::TakeVecZnxSlice] for corresponding public API. -/// # Safety [crate::doc::backend_safety] for safety contract. -pub unsafe trait TakeVecZnxSliceImpl<B: Backend> { - fn take_vec_znx_slice_impl( - scratch: &mut Scratch<B>, - len: usize, - n: usize, - cols: usize, - size: usize, - ) -> (Vec<VecZnx<&mut [u8]>>, &mut Scratch<B>); -} - -/// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe) -/// * See the [poulpy-backend/src/cpu_fft64_ref/scratch.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/scratch.rs) reference implementation. -/// * See [crate::api::TakeVecZnxBig] for corresponding public API. -/// # Safety [crate::doc::backend_safety] for safety contract. -pub unsafe trait TakeVecZnxBigImpl<B: Backend> { - fn take_vec_znx_big_impl( - scratch: &mut Scratch<B>, - n: usize, - cols: usize, - size: usize, - ) -> (VecZnxBig<&mut [u8], B>, &mut Scratch<B>); -} - -/// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe) -/// * See the [poulpy-backend/src/cpu_fft64_ref/scratch.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/scratch.rs) reference implementation. -/// * See [crate::api::TakeVecZnxDft] for corresponding public API. -/// # Safety [crate::doc::backend_safety] for safety contract. -pub unsafe trait TakeVecZnxDftImpl<B: Backend> { - fn take_vec_znx_dft_impl( - scratch: &mut Scratch<B>, - n: usize, - cols: usize, - size: usize, - ) -> (VecZnxDft<&mut [u8], B>, &mut Scratch<B>); -} - -/// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe) -/// * See the [poulpy-backend/src/cpu_fft64_ref/scratch.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/scratch.rs) reference implementation. -/// * See [crate::api::TakeVecZnxDftSlice] for corresponding public API. -/// # Safety [crate::doc::backend_safety] for safety contract. -pub unsafe trait TakeVecZnxDftSliceImpl<B: Backend> { - fn take_vec_znx_dft_slice_impl( - scratch: &mut Scratch<B>, - len: usize, - n: usize, - cols: usize, - size: usize, - ) -> (Vec<VecZnxDft<&mut [u8], B>>, &mut Scratch<B>); -} - -/// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe) -/// * See the [poulpy-backend/src/cpu_fft64_ref/scratch.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/scratch.rs) reference implementation. -/// * See [crate::api::TakeVmpPMat] for corresponding public API. -/// # Safety [crate::doc::backend_safety] for safety contract. -pub unsafe trait TakeVmpPMatImpl<B: Backend> { - fn take_vmp_pmat_impl( - scratch: &mut Scratch<B>, - n: usize, - rows: usize, - cols_in: usize, - cols_out: usize, - size: usize, - ) -> (VmpPMat<&mut [u8], B>, &mut Scratch<B>); -} - -/// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe) -/// * See the [poulpy-backend/src/cpu_fft64_ref/scratch.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/scratch.rs) reference implementation. -/// * See [crate::api::TakeMatZnx] for corresponding public API. -/// # Safety [crate::doc::backend_safety] for safety contract. -pub unsafe trait TakeMatZnxImpl<B: Backend> { - fn take_mat_znx_impl( - scratch: &mut Scratch<B>, - n: usize, - rows: usize, - cols_in: usize, - cols_out: usize, - size: usize, - ) -> (MatZnx<&mut [u8]>, &mut Scratch<B>); -}
@@ -23,7 +23,7 @@ /// * See the [poulpy-backend/src/cpu_fft64_ref/svp.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/svp.rs) reference implementation.
/// * See [crate::api::SvpPPolAllocBytes] for corresponding public API. /// # Safety [crate::doc::backend_safety] for safety contract. pub unsafe trait SvpPPolAllocBytesImpl<B: Backend> { - fn svp_ppol_alloc_bytes_impl(n: usize, cols: usize) -> usize; + fn svp_ppol_bytes_of_impl(n: usize, cols: usize) -> usize; } /// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe)
@@ -35,7 +35,7 @@ /// * See the [poulpy-backend/src/cpu_fft64_ref/vec_znx_big.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/vec_znx_big.rs) reference implementation.
/// * See [crate::api::VecZnxBigAllocBytes] for corresponding public API. /// # Safety [crate::doc::backend_safety] for safety contract. pub unsafe trait VecZnxBigAllocBytesImpl<B: Backend> { - fn vec_znx_big_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize; + fn vec_znx_big_bytes_of_impl(n: usize, cols: usize, size: usize) -> usize; } #[allow(clippy::too_many_arguments)]
@@ -42,7 +42,7 @@ /// * See the [poulpy-backend/src/cpu_fft64_ref/vec_znx_dft.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/vec_znx_dft.rs) reference implementation.
/// * See [crate::api::VecZnxDftAllocBytes] for corresponding public API. /// # Safety [crate::doc::backend_safety] for safety contract. pub unsafe trait VecZnxDftAllocBytesImpl<B: Backend> { - fn vec_znx_dft_alloc_bytes_impl(n: usize, cols: usize, size: usize) -> usize; + fn vec_znx_dft_bytes_of_impl(n: usize, cols: usize, size: usize) -> usize; } /// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe)
@@ -15,7 +15,7 @@ /// * See [poulpy-backend/src/cpu_fft64_ref/vmp.rs](https://github.com/phantomzone-org/poulpy/blob/main/poulpy-backend/src/cpu_fft64_ref/vmp.rs) for reference implementation.
/// * See [crate::api::VmpPMatAllocBytes] for corresponding public API. /// # Safety [crate::doc::backend_safety] for safety contract. pub unsafe trait VmpPMatAllocBytesImpl<B: Backend> { - fn vmp_pmat_alloc_bytes_impl(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize; + fn vmp_pmat_bytes_of_impl(n: usize, rows: usize, cols_in: usize, cols_out: usize, size: usize) -> usize; } /// # THIS TRAIT IS AN OPEN EXTENSION POINT (unsafe)
@@ -140,7 +140,7 @@ assert!(tmp_bytes.len() >= vmp_apply_dft_tmp_bytes(n, size, pmat.rows(), cols));
assert!(a.cols() <= cols); } - let (data, tmp_bytes) = tmp_bytes.split_at_mut(BE::vec_znx_dft_alloc_bytes_impl(n, cols, size)); + let (data, tmp_bytes) = tmp_bytes.split_at_mut(BE::vec_znx_dft_bytes_of_impl(n, cols, size)); let mut a_dft: VecZnxDft<&mut [u8], BE> = VecZnxDft::from_data(cast_mut(data), n, cols, size);
@@ -2,107 +2,46 @@ use std::hint::black_box;
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use poulpy_backend::{FFT64Avx, FFT64Ref, FFT64Spqlios}; -use poulpy_core::layouts::{ - Dsize, GGLWEAutomorphismKeyLayout, GGLWETensorKeyLayout, GGSWCiphertext, GGSWCiphertextLayout, GLWESecret, LWECiphertext, - LWECiphertextLayout, LWESecret, prepared::PrepareAlloc, +use poulpy_core::{ + GGSWNoise, GLWEDecrypt, GLWEEncryptSk, GLWEExternalProduct, LWEEncryptSk, ScratchTakeCore, + layouts::{ + Dsize, GGSW, GGSWLayout, GGSWPreparedFactory, GLWEAutomorphismKeyLayout, GLWESecret, GLWESecretPreparedFactory, + GLWETensorKeyLayout, LWE, LWELayout, LWESecret, + }, }; use poulpy_hal::{ - api::{ - ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, - SvpPPolAllocBytes, SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, - VecZnxAutomorphismInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes, - VecZnxBigAutomorphismInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, - VecZnxDftAddInplace, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxFillUniform, - VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, VecZnxRshInplace, VecZnxSub, - VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, - VmpPrepare, ZnAddNormal, ZnFillUniform, ZnNormalizeInplace, - }, - layouts::{Backend, Module, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeMatZnxImpl, TakeScalarZnxImpl, TakeSliceImpl, - TakeSvpPPolImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, - }, + api::{ModuleN, ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxRotateInplace}, + layouts::{Backend, Module, Scratch, ScratchOwned}, source::Source, }; use poulpy_schemes::tfhe::{ blind_rotation::{ - BlincRotationExecute, BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, - BlindRotationKeyInfos, BlindRotationKeyLayout, BlindRotationKeyPrepared, CGGI, + BlindRotationAlgo, BlindRotationKey, BlindRotationKeyFactory, BlindRotationKeyInfos, BlindRotationKeyLayout, CGGI, }, circuit_bootstrapping::{ CircuitBootstrappingKey, CircuitBootstrappingKeyEncryptSk, CircuitBootstrappingKeyLayout, - CircuitBootstrappingKeyPrepared, CirtuitBootstrappingExecute, + CircuitBootstrappingKeyPrepared, CircuitBootstrappingKeyPreparedFactory, CirtuitBootstrappingExecute, }, }; -pub fn benc_circuit_bootstrapping<B: Backend, BRA: BlindRotationAlgo>(c: &mut Criterion, label: &str) +pub fn benc_circuit_bootstrapping<BE: Backend, BRA: BlindRotationAlgo>(c: &mut Criterion, label: &str) where - Module<B>: ModuleNew<B> - + VecZnxFillUniform - + VecZnxAddNormal - + VecZnxNormalizeInplace<B> - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalize<B> - + VecZnxSub - + VecZnxAddScalarInplace - + VecZnxAutomorphism - + VecZnxSwitchRing - + VecZnxBigAllocBytes - + VecZnxIdftApplyTmpA<B> - + SvpApplyDftToDft<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VmpPMatAlloc<B> - + VmpPrepare<B> - + SvpPrepare<B> - + SvpPPolAlloc<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + SvpPPolAllocBytes - + VecZnxRotateInplace<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxRotateInplaceTmpBytes - + VecZnxBigAllocBytes - + VecZnxDftAddInplace<B> - + VecZnxRotate - + ZnFillUniform - + ZnAddNormal - + ZnNormalizeInplace<B>, - ScratchOwned<B>: ScratchOwnedAlloc<B> + ScratchOwnedBorrow<B>, - B: Backend - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + TakeVecZnxDftImpl<B> - + ScratchAvailableImpl<B> - + TakeVecZnxImpl<B> - + TakeScalarZnxImpl<B> - + TakeSvpPPolImpl<B> - + TakeVecZnxBigImpl<B> - + TakeVecZnxDftSliceImpl<B> - + TakeMatZnxImpl<B> - + TakeVecZnxSliceImpl<B> - + TakeSliceImpl<B>, - BlindRotationKey<Vec<u8>, BRA>: PrepareAlloc<B, BlindRotationKeyPrepared<Vec<u8>, BRA, B>>, - BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlincRotationExecute<B>, - BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>, + Module<BE>: ModuleNew<BE> + + ModuleN + + GLWESecretPreparedFactory<BE> + + GLWEExternalProduct<BE> + + GLWEDecrypt<BE> + + LWEEncryptSk<BE> + + CircuitBootstrappingKeyEncryptSk<BRA, BE> + + CircuitBootstrappingKeyPreparedFactory<BRA, BE> + + CirtuitBootstrappingExecute<BRA, BE> + + GGSWPreparedFactory<BE> + + GGSWNoise<BE> + + GLWEEncryptSk<BE> + + VecZnxRotateInplace<BE>, + BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, // TODO find a way to remove this bound or move it to CBT KEY + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { let group_name: String = format!("circuit_bootstrapping::{label}");@@ -113,86 +52,38 @@ name: String,
extension_factor: usize, k_pt: usize, block_size: usize, - lwe_infos: LWECiphertextLayout, - ggsw_infos: GGSWCiphertextLayout, + lwe_infos: LWELayout, + ggsw_infos: GGSWLayout, cbt_infos: CircuitBootstrappingKeyLayout, } - fn runner<B: Backend, BRA: BlindRotationAlgo>(params: &Params) -> impl FnMut() + fn runner<BE: Backend, BRA: BlindRotationAlgo>(params: &Params) -> impl FnMut() where - Module<B>: ModuleNew<B> - + VecZnxFillUniform - + VecZnxAddNormal - + VecZnxNormalizeInplace<B> - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalize<B> - + VecZnxSub - + VecZnxAddScalarInplace - + VecZnxAutomorphism - + VecZnxSwitchRing - + VecZnxBigAllocBytes - + VecZnxIdftApplyTmpA<B> - + SvpApplyDftToDft<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VmpPMatAlloc<B> - + VmpPrepare<B> - + SvpPrepare<B> - + SvpPPolAlloc<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + SvpPPolAllocBytes - + VecZnxRotateInplace<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxRotateInplaceTmpBytes - + VecZnxBigAllocBytes - + VecZnxDftAddInplace<B> - + VecZnxRotate - + ZnFillUniform - + ZnAddNormal - + ZnNormalizeInplace<B>, - B: Backend - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + TakeVecZnxDftImpl<B> - + ScratchAvailableImpl<B> - + TakeVecZnxImpl<B> - + TakeScalarZnxImpl<B> - + TakeSvpPPolImpl<B> - + TakeVecZnxBigImpl<B> - + TakeVecZnxDftSliceImpl<B> - + TakeMatZnxImpl<B> - + TakeVecZnxSliceImpl<B> - + TakeSliceImpl<B>, - BlindRotationKey<Vec<u8>, BRA>: PrepareAlloc<B, BlindRotationKeyPrepared<Vec<u8>, BRA, B>>, - BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlincRotationExecute<B>, - BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>, + Module<BE>: ModuleNew<BE> + + ModuleN + + GLWESecretPreparedFactory<BE> + + GLWEExternalProduct<BE> + + GLWEDecrypt<BE> + + LWEEncryptSk<BE> + + CircuitBootstrappingKeyEncryptSk<BRA, BE> + + CircuitBootstrappingKeyPreparedFactory<BRA, BE> + + CirtuitBootstrappingExecute<BRA, BE> + + GGSWPreparedFactory<BE> + + GGSWNoise<BE> + + GLWEEncryptSk<BE> + + VecZnxRotateInplace<BE>, + BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, /* TODO find a way to remove this bound or move it to CBT KEY */ + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { // Scratch space (4MB) - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(1 << 22); + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 22); let n_glwe: poulpy_core::layouts::Degree = params.cbt_infos.layout_brk.n_glwe(); let n_lwe: poulpy_core::layouts::Degree = params.cbt_infos.layout_brk.n_lwe(); let rank: poulpy_core::layouts::Rank = params.cbt_infos.layout_brk.rank; - let module: Module<B> = Module::<B>::new(n_glwe.as_u32() as u64); + let module: Module<BE> = Module::<BE>::new(n_glwe.as_u32() as u64); let mut source_xs: Source = Source::new([1u8; 32]); let mut source_xa: Source = Source::new([1u8; 32]);@@ -202,25 +93,26 @@ let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
sk_lwe.fill_binary_block(params.block_size, &mut source_xs); sk_lwe.fill_zero(); - let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n_glwe, rank); + let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n_glwe, rank); sk_glwe.fill_ternary_prob(0.5, &mut source_xs); - let ct_lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(¶ms.lwe_infos); + let ct_lwe: LWE<Vec<u8>> = LWE::alloc_from_infos(¶ms.lwe_infos); // Circuit bootstrapping evaluation key - let cbt_key: CircuitBootstrappingKey<Vec<u8>, BRA> = CircuitBootstrappingKey::encrypt_sk( + let mut cbt_key: CircuitBootstrappingKey<Vec<u8>, BRA> = CircuitBootstrappingKey::alloc_from_infos(¶ms.cbt_infos); + cbt_key.encrypt_sk( &module, &sk_lwe, &sk_glwe, - ¶ms.cbt_infos, &mut source_xa, &mut source_xe, scratch.borrow(), ); - let mut res: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(¶ms.ggsw_infos); - let cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, B> = cbt_key.prepare_alloc(&module, scratch.borrow()); - + let mut res: GGSW<Vec<u8>> = GGSW::alloc_from_infos(¶ms.ggsw_infos); + let mut cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, BE> = + CircuitBootstrappingKeyPrepared::alloc_from_infos(&module, ¶ms.cbt_infos); + cbt_prepared.prepare(&module, &cbt_key, scratch.borrow()); move || { cbt_prepared.execute_to_constant( &module,@@ -238,13 +130,13 @@ for params in [Params {
name: String::from("1-bit"), extension_factor: 1, k_pt: 1, - lwe_infos: LWECiphertextLayout { + lwe_infos: LWELayout { n: 574_u32.into(), k: 13_u32.into(), base2k: 13_u32.into(), }, block_size: 7, - ggsw_infos: GGSWCiphertextLayout { + ggsw_infos: GGSWLayout { n: 1024_u32.into(), base2k: 13_u32.into(), k: 26_u32.into(),@@ -261,7 +153,7 @@ k: 52_u32.into(),
dnum: 3_u32.into(), rank: 2_u32.into(), }, - layout_atk: GGLWEAutomorphismKeyLayout { + layout_atk: GLWEAutomorphismKeyLayout { n: 1024_u32.into(), base2k: 13_u32.into(), k: 52_u32.into(),@@ -269,7 +161,7 @@ dnum: 3_u32.into(),
dsize: Dsize(1), rank: 2_u32.into(), }, - layout_tsk: GGLWETensorKeyLayout { + layout_tsk: GLWETensorKeyLayout { n: 1024_u32.into(), base2k: 13_u32.into(), k: 52_u32.into(),@@ -280,7 +172,7 @@ },
}, }] { let id: BenchmarkId = BenchmarkId::from_parameter(params.name.clone()); - let mut runner = runner::<B, BRA>(¶ms); + let mut runner = runner::<BE, BRA>(¶ms); group.bench_with_input(id, &(), |b, _| b.iter(&mut runner)); }
@@ -1,9 +1,9 @@
use poulpy_core::{ - GLWEOperations, + GLWENormalize, layouts::{ - GGLWEAutomorphismKeyLayout, GGLWETensorKeyLayout, GGSWCiphertext, GGSWCiphertextLayout, GLWECiphertext, - GLWECiphertextLayout, GLWEPlaintext, GLWESecret, LWECiphertext, LWECiphertextLayout, LWEInfos, LWEPlaintext, LWESecret, - prepared::{GGSWCiphertextPrepared, GLWESecretPrepared, PrepareAlloc}, + GGSW, GGSWLayout, GLWE, GLWEAutomorphismKeyLayout, GLWELayout, GLWEPlaintext, GLWESecret, GLWETensorKeyLayout, LWE, + LWEInfos, LWELayout, LWEPlaintext, LWESecret, + prepared::{GGSWPrepared, GLWESecretPrepared}, }, }; use std::time::Instant;@@ -22,10 +22,7 @@ };
use poulpy_schemes::tfhe::{ blind_rotation::{BlindRotationKeyLayout, CGGI}, - circuit_bootstrapping::{ - CircuitBootstrappingKey, CircuitBootstrappingKeyEncryptSk, CircuitBootstrappingKeyLayout, - CircuitBootstrappingKeyPrepared, CirtuitBootstrappingExecute, - }, + circuit_bootstrapping::{CircuitBootstrappingKey, CircuitBootstrappingKeyLayout, CircuitBootstrappingKeyPrepared}, }; fn main() {@@ -89,7 +86,7 @@ k: k_brk.into(),
dnum: rows_brk.into(), rank: rank.into(), }, - layout_atk: GGLWEAutomorphismKeyLayout { + layout_atk: GLWEAutomorphismKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_trace.into(),@@ -97,7 +94,7 @@ dnum: rows_trace.into(),
dsize: 1_u32.into(), rank: rank.into(), }, - layout_tsk: GGLWETensorKeyLayout { + layout_tsk: GLWETensorKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_tsk.into(),@@ -107,7 +104,7 @@ rank: rank.into(),
}, }; - let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_infos: GGSWLayout = GGSWLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_ggsw_res.into(),@@ -116,7 +113,7 @@ dsize: 1_u32.into(),
rank: rank.into(), }; - let lwe_infos = LWECiphertextLayout { + let lwe_infos = LWELayout { n: n_lwe.into(), k: k_lwe_ct.into(), base2k: base2k.into(),@@ -140,18 +137,19 @@ sk_lwe.fill_binary_block(block_size, &mut source_xs);
sk_lwe.fill_zero(); // GLWE secret - let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n_glwe.into(), rank.into()); + let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n_glwe.into(), rank.into()); sk_glwe.fill_ternary_prob(0.5, &mut source_xs); // sk_glwe.fill_zero(); // GLWE secret prepared (opaque backend dependant write only struct) - let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BackendImpl> = sk_glwe.prepare_alloc(&module, scratch.borrow()); + let mut sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BackendImpl> = GLWESecretPrepared::alloc(&module, rank.into()); + sk_glwe_prepared.prepare(&module, &sk_glwe); // Plaintext value to circuit bootstrap let data: i64 = 1 % (1 << k_lwe_pt); // LWE plaintext - let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_with(base2k.into(), k_lwe_pt.into()); + let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(base2k.into(), k_lwe_pt.into()); // LWE plaintext(data * 2^{- (k_lwe_pt - 1)}) pt_lwe.encode_i64(data, (k_lwe_pt + 1).into()); // +1 for padding bit@@ -167,7 +165,7 @@ );
println!("pt_lwe: {pt_lwe}"); // LWE ciphertext - let mut ct_lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos); + let mut ct_lwe: LWE<Vec<u8>> = LWE::alloc_from_infos(&lwe_infos); // Encrypt LWE Plaintext ct_lwe.encrypt_sk(&module, &pt_lwe, &sk_lwe, &mut source_xa, &mut source_xe);@@ -175,23 +173,26 @@
let now: Instant = Instant::now(); // Circuit bootstrapping evaluation key - let cbt_key: CircuitBootstrappingKey<Vec<u8>, CGGI> = CircuitBootstrappingKey::encrypt_sk( + let mut cbt_key: CircuitBootstrappingKey<Vec<u8>, CGGI> = CircuitBootstrappingKey::alloc_from_infos(&cbt_infos); + + cbt_key.encrypt_sk( &module, &sk_lwe, &sk_glwe, - &cbt_infos, &mut source_xa, &mut source_xe, scratch.borrow(), ); + println!("CBT-KGEN: {} ms", now.elapsed().as_millis()); // Output GGSW - let mut res: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos); + let mut res: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_infos); // Circuit bootstrapping key prepared (opaque backend dependant write only struct) - let cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, CGGI, BackendImpl> = - cbt_key.prepare_alloc(&module, scratch.borrow()); + let mut cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, CGGI, BackendImpl> = + CircuitBootstrappingKeyPrepared::alloc_from_infos(&module, &cbt_infos); + cbt_prepared.prepare(&module, &cbt_key, scratch.borrow()); // Apply circuit bootstrapping: LWE(data * 2^{- (k_lwe_pt + 2)}) -> GGSW(data) let now: Instant = Instant::now();@@ -214,7 +215,7 @@ res.print_noise(&module, &sk_glwe_prepared, &pt_ggsw);
// Tests RLWE(1) * GGSW(data) - let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_infos: GLWELayout = GLWELayout { n: n_glwe.into(), base2k: base2k.into(), k: (k_ggsw_res - base2k).into(),@@ -222,11 +223,11 @@ rank: rank.into(),
}; // GLWE ciphertext modulus - let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos); + let mut ct_glwe: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos); // Some GLWE plaintext with signed data let k_glwe_pt: usize = 3; - let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos); + let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos); let mut data_vec: Vec<i64> = vec![0i64; n_glwe]; data_vec .iter_mut()@@ -234,7 +235,7 @@ .enumerate()
.for_each(|(x, y)| *y = (x % (1 << (k_glwe_pt - 1))) as i64 - (1 << (k_glwe_pt - 2))); pt_glwe.encode_vec_i64(&data_vec, (k_lwe_pt + 2).into()); - pt_glwe.normalize_inplace(&module, scratch.borrow()); + module.glwe_normalize_inplace(&mut pt_glwe, scratch.borrow()); println!("{}", pt_glwe);@@ -249,13 +250,14 @@ scratch.borrow(),
); // Prepare GGSW output of circuit bootstrapping (opaque backend dependant write only struct) - let res_prepared: GGSWCiphertextPrepared<Vec<u8>, BackendImpl> = res.prepare_alloc(&module, scratch.borrow()); + let mut res_prepared: GGSWPrepared<Vec<u8>, BackendImpl> = GGSWPrepared::alloc_from_infos(&module, &res); + res_prepared.prepare(&module, &res, scratch.borrow()); // Apply GLWE x GGSW ct_glwe.external_product_inplace(&module, &res_prepared, scratch.borrow()); // Decrypt - let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos); + let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos); ct_glwe.decrypt(&module, &mut pt_res, &sk_glwe_prepared, scratch.borrow()); println!("pt_res: {:?}", &pt_res.data.at(0, 0)[..64]);
@@ -1,78 +1,46 @@
use itertools::Itertools; -use poulpy_core::layouts::prepared::GGSWCiphertextPreparedToRef; +use poulpy_core::layouts::prepared::GGSWPreparedToRef; use poulpy_hal::layouts::{Backend, DataMut, DataRef, Module, Scratch}; use crate::tfhe::bdd_arithmetic::{ - BitCircuitInfo, Circuit, CircuitExecute, FheUintBlocks, FheUintBlocksPrep, UnsignedInteger, circuits, + ExecuteBDDCircuit, FheUintBlocks, FheUintBlocksPrepared, GetBitCircuitInfo, UnsignedInteger, circuits, }; -/// Operations Z x Z -> Z -pub(crate) struct Circuits2WTo1W<C: BitCircuitInfo + 'static, const WORD_SIZE: usize>(pub &'static Circuit<C, WORD_SIZE>); - -pub trait EvalBDD2WTo1W<BE: Backend, T: UnsignedInteger> { - fn eval_bdd_2w_to_1w<R, A, B>( - &self, - module: &Module<BE>, - out: &mut FheUintBlocks<R, T>, - a: &FheUintBlocksPrep<A, BE, T>, - b: &FheUintBlocksPrep<B, BE, T>, - scratch: &mut Scratch<BE>, - ) where - R: DataMut, - A: DataRef, - B: DataRef; -} +impl<T: UnsignedInteger, BE: Backend> ExecuteBDDCircuit2WTo1W<T, BE> for Module<BE> where Self: Sized + ExecuteBDDCircuit<T, BE> {} -impl<C: BitCircuitInfo + 'static, const WORD_SIZE: usize, BE: Backend, T: UnsignedInteger> EvalBDD2WTo1W<BE, T> - for Circuits2WTo1W<C, WORD_SIZE> +pub trait ExecuteBDDCircuit2WTo1W<T: UnsignedInteger, BE: Backend> where - Circuit<C, WORD_SIZE>: CircuitExecute<BE, T>, + Self: Sized + ExecuteBDDCircuit<T, BE>, { - fn eval_bdd_2w_to_1w<R, A, B>( + /// Operations Z x Z -> Z + fn execute_bdd_circuit_2w_to_1w<R, C, A, B>( &self, - module: &Module<BE>, out: &mut FheUintBlocks<R, T>, - a: &FheUintBlocksPrep<A, BE, T>, - b: &FheUintBlocksPrep<B, BE, T>, + circuit: &C, + a: &FheUintBlocksPrepared<A, T, BE>, + b: &FheUintBlocksPrepared<B, T, BE>, scratch: &mut Scratch<BE>, ) where + C: GetBitCircuitInfo<T>, R: DataMut, A: DataRef, B: DataRef, { - eval_bdd_2w_to_1w(module, self.0, out, a, b, scratch); - } -} - -pub fn eval_bdd_2w_to_1w<R: DataMut, A: DataRef, B: DataRef, T: UnsignedInteger, C: CircuitExecute<BE, T>, BE: Backend>( - module: &Module<BE>, - circuit: &C, - out: &mut FheUintBlocks<R, T>, - a: &FheUintBlocksPrep<A, BE, T>, - b: &FheUintBlocksPrep<B, BE, T>, - scratch: &mut Scratch<BE>, -) { - #[cfg(debug_assertions)] - { assert_eq!(out.blocks.len(), T::WORD_SIZE); assert_eq!(b.blocks.len(), T::WORD_SIZE); assert_eq!(b.blocks.len(), T::WORD_SIZE); - } - // Collects inputs into a single array - let inputs: Vec<&dyn GGSWCiphertextPreparedToRef<BE>> = a - .blocks - .iter() - .map(|x| x as &dyn GGSWCiphertextPreparedToRef<BE>) - .chain( - b.blocks - .iter() - .map(|x| x as &dyn GGSWCiphertextPreparedToRef<BE>), - ) - .collect_vec(); + // Collects inputs into a single array + let inputs: Vec<&dyn GGSWPreparedToRef<BE>> = a + .blocks + .iter() + .map(|x| x as &dyn GGSWPreparedToRef<BE>) + .chain(b.blocks.iter().map(|x| x as &dyn GGSWPreparedToRef<BE>)) + .collect_vec(); - // Evaluates out[i] = circuit[i](a, b) - circuit.execute(module, &mut out.blocks, &inputs, scratch); + // Evaluates out[i] = circuit[i](a, b) + self.execute_bdd_circuit(&mut out.blocks, &inputs, circuit, scratch); + } } #[macro_export]@@ -80,13 +48,14 @@ macro_rules! define_bdd_2w_to_1w_trait {
($(#[$meta:meta])* $vis:vis $trait_name:ident, $method_name:ident) => { $(#[$meta])* $vis trait $trait_name<T: UnsignedInteger, BE: Backend> { - fn $method_name<A, B>( + fn $method_name<A, M, B>( &mut self, - module: &Module<BE>, - a: &FheUintBlocksPrep<A, BE, T>, - b: &FheUintBlocksPrep<B, BE, T>, + module: &M, + a: &FheUintBlocksPrepared<A, T, BE>, + b: &FheUintBlocksPrepared<B, T, BE>, scratch: &mut Scratch<BE>, ) where + M: ExecuteBDDCircuit2WTo1W<T, BE>, A: DataRef, B: DataRef; }@@ -96,23 +65,19 @@
#[macro_export] macro_rules! impl_bdd_2w_to_1w_trait { ($trait_name:ident, $method_name:ident, $ty:ty, $n:literal, $circuit_ty:ty, $output_circuits:path) => { - impl<D: DataMut, BE: Backend> $trait_name<$ty, BE> for FheUintBlocks<D, $ty> - where - Circuits2WTo1W<$circuit_ty, $n>: EvalBDD2WTo1W<BE, $ty>, - { - fn $method_name<A, B>( + impl<D: DataMut, BE: Backend> $trait_name<$ty, BE> for FheUintBlocks<D, $ty> { + fn $method_name<A, M, B>( &mut self, - module: &Module<BE>, - a: &FheUintBlocksPrep<A, BE, $ty>, - b: &FheUintBlocksPrep<B, BE, $ty>, + module: &M, + a: &FheUintBlocksPrepared<A, $ty, BE>, + b: &FheUintBlocksPrepared<B, $ty, BE>, scratch: &mut Scratch<BE>, ) where + M: ExecuteBDDCircuit2WTo1W<$ty, BE>, A: DataRef, B: DataRef, { - const OP: Circuits2WTo1W<$circuit_ty, $n> = Circuits2WTo1W::<$circuit_ty, $n>(&$output_circuits); - - OP.eval_bdd_2w_to_1w(module, self, a, b, scratch); + module.execute_bdd_circuit_2w_to_1w(self, &$output_circuits, a, b, scratch) } } };
@@ -1,30 +1,23 @@
use std::marker::PhantomData; -use poulpy_core::layouts::{Base2K, GLWECiphertext, GLWEInfos, GLWEPlaintextLayout, LWEInfos, Rank, TorusPrecision}; +use poulpy_core::{ + GLWEDecrypt, GLWENoise, + layouts::{Base2K, GLWE, GLWEInfos, GLWEPlaintextLayout, GLWESecretPreparedToRef, LWEInfos, Rank, TorusPrecision}, +}; -use poulpy_core::{TakeGLWEPt, layouts::prepared::GLWESecretPrepared}; -use poulpy_hal::api::VecZnxBigAllocBytes; +#[cfg(test)] +use poulpy_core::GLWEEncryptSk; +use poulpy_core::ScratchTakeCore; +use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}; #[cfg(test)] -use poulpy_hal::api::{ - ScratchAvailable, TakeVecZnx, VecZnxAddInplace, VecZnxAddNormal, VecZnxFillUniform, VecZnxNormalize, VecZnxSub, -}; #[cfg(test)] use poulpy_hal::source::Source; -use poulpy_hal::{ - api::{ - TakeVecZnxBig, TakeVecZnxDft, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxDftAllocBytes, - VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalizeTmpBytes, - }, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, -}; - -use poulpy_hal::api::{SvpApplyDftToDftInplace, VecZnxNormalizeInplace, VecZnxSubInplace}; use crate::tfhe::bdd_arithmetic::{FromBits, ToBits, UnsignedInteger}; /// An FHE ciphertext encrypting the bits of an [UnsignedInteger]. pub struct FheUintBlocks<D: Data, T: UnsignedInteger> { - pub(crate) blocks: Vec<GLWECiphertext<D>>, + pub(crate) blocks: Vec<GLWE<D>>, pub(crate) _base: u8, pub(crate) _phantom: PhantomData<T>, }@@ -62,7 +55,7 @@ #[allow(dead_code)]
pub(crate) fn alloc_with<BE: Backend>(module: &Module<BE>, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self { Self { blocks: (0..T::WORD_SIZE) - .map(|_| GLWECiphertext::alloc_with(module.n().into(), base2k, k, rank)) + .map(|_| GLWE::alloc(module.n().into(), base2k, k, rank)) .collect(), _base: 1, _phantom: PhantomData,@@ -77,26 +70,14 @@ pub(crate) fn encrypt_sk<S, BE: Backend>(
&mut self, module: &Module<BE>, value: T, - sk: &GLWESecretPrepared<S, BE>, + sk: &S, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch<BE>, ) where - S: DataRef, - Module<BE>: VecZnxDftAllocBytes - + VecZnxBigNormalize<BE> - + VecZnxDftApply<BE> - + SvpApplyDftToDftInplace<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<BE> - + VecZnxAddNormal - + VecZnxNormalize<BE> - + VecZnxSub, - Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGLWEPt<BE>, + S: GLWESecretPreparedToRef<BE> + GLWEInfos, + Module<BE>: GLWEEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { use poulpy_core::layouts::GLWEPlaintextLayout;@@ -113,30 +94,21 @@ base2k: self.base2k(),
k: 1_usize.into(), }; - let (mut pt, scratch_1) = scratch.take_glwe_pt(&pt_infos); + let (mut pt, scratch_1) = scratch.take_glwe_plaintext(&pt_infos); for i in 0..T::WORD_SIZE { - pt.encode_coeff_i64(value.bit(i) as i64, TorusPrecision(1), 0); - self.blocks[i].encrypt_sk(&module, &pt, sk, source_xa, source_xe, scratch_1); + pt.encode_coeff_i64(value.bit(i) as i64, TorusPrecision(2), 0); + self.blocks[i].encrypt_sk(module, &pt, sk, source_xa, source_xe, scratch_1); } } } impl<D: DataRef, T: UnsignedInteger + FromBits + ToBits> FheUintBlocks<D, T> { - pub fn decrypt<S: DataRef, BE: Backend>( - &self, - module: &Module<BE>, - sk: &GLWESecretPrepared<S, BE>, - scratch: &mut Scratch<BE>, - ) -> T + pub fn decrypt<S, BE: Backend>(&self, module: &Module<BE>, sk: &S, scratch: &mut Scratch<BE>) -> T where - Module<BE>: VecZnxDftApply<BE> - + SvpApplyDftToDftInplace<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxBigAddInplace<BE> - + VecZnxBigAddSmallInplace<BE> - + VecZnxBigNormalize<BE>, - Scratch<BE>: TakeVecZnxDft<BE> + TakeVecZnxBig<BE> + TakeGLWEPt<BE>, + Module<BE>: GLWEDecrypt<BE>, + S: GLWESecretPreparedToRef<BE> + GLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { #[cfg(debug_assertions)] {@@ -151,7 +123,7 @@ base2k: self.base2k(),
k: self.k(), }; - let (mut pt, scratch_1) = scratch.take_glwe_pt(&pt_infos); + let (mut pt, scratch_1) = scratch.take_glwe_plaintext(&pt_infos); let mut bits: Vec<u8> = vec![0u8; T::WORD_SIZE];@@ -167,26 +139,11 @@
T::from_bits(&bits) } - pub fn noise<S: DataRef, BE: Backend>( - &self, - module: &Module<BE>, - sk: &GLWESecretPrepared<S, BE>, - want: T, - scratch: &mut Scratch<BE>, - ) -> Vec<f64> + pub fn noise<S, BE: Backend>(&self, module: &Module<BE>, sk: &S, want: T, scratch: &mut Scratch<BE>) -> Vec<f64> where - Module<BE>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<BE> - + SvpApplyDftToDftInplace<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxBigAddInplace<BE> - + VecZnxBigAddSmallInplace<BE> - + VecZnxBigNormalize<BE> - + VecZnxNormalizeTmpBytes - + VecZnxSubInplace - + VecZnxNormalizeInplace<BE>, - Scratch<BE>: TakeGLWEPt<BE> + TakeVecZnxDft<BE> + TakeVecZnxBig<BE>, + Module<BE>: GLWENoise<BE>, + S: GLWESecretPreparedToRef<BE> + GLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { #[cfg(debug_assertions)] {@@ -201,7 +158,7 @@ base2k: self.base2k(),
k: 1_usize.into(), }; - let (mut pt_want, scratch_1) = scratch.take_glwe_pt(&pt_infos); + let (mut pt_want, scratch_1) = scratch.take_glwe_plaintext(&pt_infos); let mut noise: Vec<f64> = vec![0f64; T::WORD_SIZE];
@@ -0,0 +1,147 @@
+use std::marker::PhantomData; + +use crate::tfhe::bdd_arithmetic::{BDDKeyPrepared, FheUintBlockDebugPrepare, ToBits}; +use crate::tfhe::{ + bdd_arithmetic::{FheUintBlocks, UnsignedInteger}, + blind_rotation::BlindRotationAlgo, + circuit_bootstrapping::CirtuitBootstrappingExecute, +}; +use poulpy_core::GGSWNoise; +#[cfg(test)] +use poulpy_core::layouts::{Base2K, Dnum, Dsize, Rank, TorusPrecision}; +use poulpy_core::layouts::{GGSW, GLWESecretPreparedToRef}; +use poulpy_core::{ + LWEFromGLWE, ScratchTakeCore, + layouts::{GGSWInfos, GGSWPreparedFactory, GLWEInfos, LWE, LWEInfos}, +}; +#[cfg(test)] +use poulpy_hal::api::ModuleN; +use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}; + +pub(crate) struct FheUintBlocksPreparedDebug<D: Data, T: UnsignedInteger> { + pub(crate) blocks: Vec<GGSW<D>>, + pub(crate) _base: u8, + pub(crate) _phantom: PhantomData<T>, +} + +#[cfg(test)] +impl<T: UnsignedInteger> FheUintBlocksPreparedDebug<Vec<u8>, T> { + #[allow(dead_code)] + pub(crate) fn alloc<A, M>(module: &M, infos: &A) -> Self + where + M: ModuleN, + A: GGSWInfos, + { + Self::alloc_with( + module, + infos.base2k(), + infos.k(), + infos.dnum(), + infos.dsize(), + infos.rank(), + ) + } + + #[allow(dead_code)] + pub(crate) fn alloc_with<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self + where + M: ModuleN, + { + Self { + blocks: (0..T::WORD_SIZE) + .map(|_| GGSW::alloc(module.n().into(), base2k, k, rank, dnum, dsize)) + .collect(), + _base: 1, + _phantom: PhantomData, + } + } +} + +impl<D: DataRef, T: UnsignedInteger> LWEInfos for FheUintBlocksPreparedDebug<D, T> { + fn base2k(&self) -> poulpy_core::layouts::Base2K { + self.blocks[0].base2k() + } + + fn k(&self) -> poulpy_core::layouts::TorusPrecision { + self.blocks[0].k() + } + + fn n(&self) -> poulpy_core::layouts::Degree { + self.blocks[0].n() + } +} + +impl<D: DataRef, T: UnsignedInteger> GLWEInfos for FheUintBlocksPreparedDebug<D, T> { + fn rank(&self) -> poulpy_core::layouts::Rank { + self.blocks[0].rank() + } +} + +impl<D: DataRef, T: UnsignedInteger> GGSWInfos for FheUintBlocksPreparedDebug<D, T> { + fn dsize(&self) -> poulpy_core::layouts::Dsize { + self.blocks[0].dsize() + } + + fn dnum(&self) -> poulpy_core::layouts::Dnum { + self.blocks[0].dnum() + } +} + +impl<D: DataRef, T: UnsignedInteger + ToBits> FheUintBlocksPreparedDebug<D, T> { + pub(crate) fn noise<S, M, BE: Backend>(&self, module: &M, sk: &S, want: T) + where + S: GLWESecretPreparedToRef<BE>, + M: GGSWNoise<BE>, + { + for (i, ggsw) in self.blocks.iter().enumerate() { + use poulpy_hal::layouts::{ScalarZnx, ZnxViewMut}; + let mut pt_want = ScalarZnx::alloc(self.n().into(), 1); + pt_want.at_mut(0, 0)[0] = want.bit(i) as i64; + ggsw.print_noise(module, sk, &pt_want); + } + } +} + +impl<BRA: BlindRotationAlgo, BE: Backend, T: UnsignedInteger> FheUintBlockDebugPrepare<BRA, T, BE> for Module<BE> +where + Self: LWEFromGLWE<BE> + CirtuitBootstrappingExecute<BRA, BE> + GGSWPreparedFactory<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn fhe_uint_block_debug_prepare<DM, DR0, DR1>( + &self, + res: &mut FheUintBlocksPreparedDebug<DM, T>, + bits: &FheUintBlocks<DR0, T>, + key: &BDDKeyPrepared<DR1, BRA, BE>, + scratch: &mut Scratch<BE>, + ) where + DM: DataMut, + DR0: DataRef, + DR1: DataRef, + { + assert_eq!(res.blocks.len(), bits.blocks.len()); + + let mut lwe: LWE<Vec<u8>> = LWE::alloc_from_infos(&bits.blocks[0]); //TODO: add TakeLWE + for (dst, src) in res.blocks.iter_mut().zip(bits.blocks.iter()) { + lwe.from_glwe(self, src, &key.ks, scratch); + key.cbt.execute_to_constant(self, dst, &lwe, 1, 1, scratch); + } + } +} + +impl<D: DataMut, T: UnsignedInteger> FheUintBlocksPreparedDebug<D, T> { + pub fn prepare<BRA, M, O, K, BE: Backend>( + &mut self, + module: &M, + other: &FheUintBlocks<O, T>, + key: &BDDKeyPrepared<K, BRA, BE>, + scratch: &mut Scratch<BE>, + ) where + BRA: BlindRotationAlgo, + O: DataRef, + K: DataRef, + M: FheUintBlockDebugPrepare<BRA, T, BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.fhe_uint_block_debug_prepare(self, other, key, scratch); + } +}
@@ -1,93 +1,60 @@
use std::marker::PhantomData; use poulpy_core::layouts::{ - Base2K, Dnum, Dsize, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::GGSWCiphertextPrepared, + Base2K, Dnum, Dsize, GGSWInfos, GGSWPreparedFactory, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::GGSWPrepared, }; #[cfg(test)] -use poulpy_core::{ - TakeGGSW, - layouts::{GGSWCiphertext, prepared::GLWESecretPrepared}, -}; -use poulpy_hal::{ - api::VmpPMatAlloc, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, -}; +use poulpy_core::{GGSWEncryptSk, ScratchTakeCore, layouts::GLWESecretPreparedToRef}; +use poulpy_hal::layouts::{Backend, Data, DataRef, Module}; #[cfg(test)] use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, - VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes, - VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, - VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, - VecZnxSubInplace, VmpPrepare, - }, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl}, + api::ModuleN, + layouts::{DataMut, Scratch}, source::Source, }; -use crate::tfhe::bdd_arithmetic::{FheUintBlocks, FheUintPrepare, ToBits, UnsignedInteger}; +#[cfg(test)] +use crate::tfhe::bdd_arithmetic::ToBits; +use crate::tfhe::bdd_arithmetic::UnsignedInteger; -#[cfg(test)] -pub(crate) struct FheUintBlocksPrepDebug<D: Data, T: UnsignedInteger> { - pub(crate) blocks: Vec<GGSWCiphertext<D>>, +/// A prepared FHE ciphertext encrypting the bits of an [UnsignedInteger]. +pub struct FheUintBlocksPrepared<D: Data, T: UnsignedInteger, B: Backend> { + pub(crate) blocks: Vec<GGSWPrepared<D, B>>, pub(crate) _base: u8, pub(crate) _phantom: PhantomData<T>, } -#[cfg(test)] -impl<T: UnsignedInteger> FheUintBlocksPrepDebug<Vec<u8>, T> { - #[allow(dead_code)] - pub(crate) fn alloc<A, BE: Backend>(module: &Module<BE>, infos: &A) -> Self - where - A: GGSWInfos, - { - Self::alloc_with( - module, - infos.base2k(), - infos.k(), - infos.dnum(), - infos.dsize(), - infos.rank(), - ) - } +impl<T: UnsignedInteger, BE: Backend> FheUintBlocksPreparedFactory<T, BE> for Module<BE> where + Self: Sized + GGSWPreparedFactory<BE> +{ +} - #[allow(dead_code)] - pub(crate) fn alloc_with<BE: Backend>( - module: &Module<BE>, +pub trait FheUintBlocksPreparedFactory<T: UnsignedInteger, BE: Backend> +where + Self: Sized + GGSWPreparedFactory<BE>, +{ + fn alloc_fhe_uint_blocks_prepared( + &self, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank, - ) -> Self { - Self { + ) -> FheUintBlocksPrepared<Vec<u8>, T, BE> { + FheUintBlocksPrepared { blocks: (0..T::WORD_SIZE) - .map(|_| GGSWCiphertext::alloc_with(module.n().into(), base2k, k, rank, dnum, dsize)) + .map(|_| GGSWPrepared::alloc(self, base2k, k, dnum, dsize, rank)) .collect(), _base: 1, _phantom: PhantomData, } } -} -/// A prepared FHE ciphertext encrypting the bits of an [UnsignedInteger]. -pub struct FheUintBlocksPrep<D: Data, B: Backend, T: UnsignedInteger> { - pub(crate) blocks: Vec<GGSWCiphertextPrepared<D, B>>, - pub(crate) _base: u8, - pub(crate) _phantom: PhantomData<T>, -} - -impl<T: UnsignedInteger, BE: Backend> FheUintBlocksPrep<Vec<u8>, BE, T> -where - Module<BE>: VmpPMatAlloc<BE>, -{ - #[allow(dead_code)] - pub(crate) fn alloc<A>(module: &Module<BE>, infos: &A) -> Self + fn alloc_fhe_uint_blocks_prepared_from_infos<A>(&self, infos: &A) -> FheUintBlocksPrepared<Vec<u8>, T, BE> where A: GGSWInfos, { - Self::alloc_with( - module, + self.alloc_fhe_uint_blocks_prepared( infos.base2k(), infos.k(), infos.dnum(),@@ -95,130 +62,90 @@ infos.dsize(),
infos.rank(), ) } +} +impl<T: UnsignedInteger, BE: Backend> FheUintBlocksPrepared<Vec<u8>, T, BE> { #[allow(dead_code)] - pub(crate) fn alloc_with(module: &Module<BE>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self + pub(crate) fn alloc<A, M>(module: &M, infos: &A) -> Self + where + A: GGSWInfos, + M: FheUintBlocksPreparedFactory<T, BE>, + { + module.alloc_fhe_uint_blocks_prepared_from_infos(infos) + } + + #[allow(dead_code)] + pub(crate) fn alloc_with<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self where - Module<BE>: VmpPMatAlloc<BE>, + M: FheUintBlocksPreparedFactory<T, BE>, { - Self { - blocks: (0..T::WORD_SIZE) - .map(|_| GGSWCiphertextPrepared::alloc_with(module, base2k, k, dnum, dsize, rank)) - .collect(), - _base: 1, - _phantom: PhantomData, - } + module.alloc_fhe_uint_blocks_prepared(base2k, k, dnum, dsize, rank) } } -impl<D: DataMut, T: UnsignedInteger + ToBits, BE: Backend> FheUintBlocksPrep<D, BE, T> { - #[allow(dead_code)] - #[cfg(test)] - pub(crate) fn encrypt_sk<S>( - &mut self, - module: &Module<BE>, +#[cfg(test)] +impl<T: UnsignedInteger + ToBits, BE: Backend> FheUintBlocksPreparedEncryptSk<T, BE> for Module<BE> where + Self: Sized + ModuleN + GGSWEncryptSk<BE> + GGSWPreparedFactory<BE> +{ +} + +#[cfg(test)] +pub trait FheUintBlocksPreparedEncryptSk<T: UnsignedInteger + ToBits, BE: Backend> +where + Self: Sized + ModuleN + GGSWEncryptSk<BE> + GGSWPreparedFactory<BE>, +{ + fn fhe_uint_blocks_prepared_encrypt_sk<DM, S>( + &self, + res: &mut FheUintBlocksPrepared<DM, T, BE>, value: T, - sk: &GLWESecretPrepared<S, BE>, + sk: &S, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch<BE>, ) where - S: DataRef, - Module<BE>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<BE> - + VecZnxDftApply<BE> - + SvpApplyDftToDftInplace<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<BE> - + VecZnxAddNormal - + VecZnxNormalize<BE> - + VecZnxSub - + VmpPrepare<BE>, - Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGGSW + TakeScalarZnx, + DM: DataMut, + S: GLWESecretPreparedToRef<BE> + GLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - assert!(module.n().is_multiple_of(T::WORD_SIZE)); - assert_eq!(self.n(), module.n() as u32); - assert_eq!(sk.n(), module.n() as u32); - } + use poulpy_hal::api::ScratchTakeBasic; + + assert!(self.n().is_multiple_of(T::WORD_SIZE)); + assert_eq!(res.n(), self.n() as u32); + assert_eq!(sk.n(), self.n() as u32); - let (mut tmp_ggsw, scratch_1) = scratch.take_ggsw(self); - let (mut pt, scratch_2) = scratch_1.take_scalar_znx(module.n(), 1); + let (mut tmp_ggsw, scratch_1) = scratch.take_ggsw(res); + let (mut pt, scratch_2) = scratch_1.take_scalar_znx(self.n(), 1); for i in 0..T::WORD_SIZE { - use poulpy_core::layouts::prepared::Prepare; use poulpy_hal::layouts::ZnxViewMut; pt.at_mut(0, 0)[0] = value.bit(i) as i64; - tmp_ggsw.encrypt_sk(&module, &pt, sk, source_xa, source_xe, scratch_2); - self.blocks[i].prepare(module, &tmp_ggsw, scratch_2); + tmp_ggsw.encrypt_sk(self, &pt, sk, source_xa, source_xe, scratch_2); + res.blocks[i].prepare(self, &tmp_ggsw, scratch_2); } } - - /// Prepares [FheUintBits] to [FheUintBitsPrep]. - pub fn prepare<BIT, KEY>(&mut self, module: &Module<BE>, bits: &FheUintBlocks<BIT, T>, key: &KEY, scratch: &mut Scratch<BE>) - where - BIT: DataRef, - KEY: FheUintPrepare<BE, FheUintBlocksPrep<D, BE, T>, FheUintBlocks<BIT, T>>, - { - key.prepare(module, self, bits, scratch); - } } #[cfg(test)] -impl<D: DataMut, T: UnsignedInteger + ToBits> FheUintBlocksPrepDebug<D, T> { - pub(crate) fn prepare<BIT, KEY, BE: Backend>( +impl<D: DataMut, T: UnsignedInteger + ToBits, BE: Backend> FheUintBlocksPrepared<D, T, BE> { + pub(crate) fn encrypt_sk<M, S>( &mut self, - module: &Module<BE>, - bits: &FheUintBlocks<BIT, T>, - key: &KEY, + module: &M, + value: T, + sk: &S, + source_xa: &mut Source, + source_xe: &mut Source, scratch: &mut Scratch<BE>, ) where - BIT: DataRef, - KEY: FheUintPrepare<BE, FheUintBlocksPrepDebug<D, T>, FheUintBlocks<BIT, T>>, - { - key.prepare(module, self, bits, scratch); - } -} - -#[cfg(test)] -impl<D: DataRef, T: UnsignedInteger + ToBits> FheUintBlocksPrepDebug<D, T> { - #[allow(dead_code)] - pub(crate) fn noise<S: DataRef, BE: Backend>(&self, module: &Module<BE>, sk: &GLWESecretPrepared<S, BE>, want: T) - where - Module<BE>: VecZnxDftAllocBytes - + VecZnxBigAllocBytes - + VecZnxDftApply<BE> - + SvpApplyDftToDftInplace<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxBigAddInplace<BE> - + VecZnxBigAddSmallInplace<BE> - + VecZnxBigNormalize<BE> - + VecZnxNormalizeTmpBytes - + VecZnxBigAlloc<BE> - + VecZnxDftAlloc<BE> - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpA<BE> - + VecZnxAddScalarInplace - + VecZnxSubInplace, - BE: Backend + TakeVecZnxDftImpl<BE> + TakeVecZnxBigImpl<BE> + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE>, + S: GLWESecretPreparedToRef<BE> + GLWEInfos, + M: FheUintBlocksPreparedEncryptSk<T, BE>, + Scratch<BE>: ScratchTakeCore<BE>, { - for (i, ggsw) in self.blocks.iter().enumerate() { - use poulpy_hal::layouts::{ScalarZnx, ZnxViewMut}; - let mut pt_want = ScalarZnx::alloc(self.n().into(), 1); - pt_want.at_mut(0, 0)[0] = want.bit(i) as i64; - ggsw.print_noise(module, sk, &pt_want); - } + module.fhe_uint_blocks_prepared_encrypt_sk(self, value, sk, source_xa, source_xe, scratch); } } -impl<D: DataRef, T: UnsignedInteger, B: Backend> LWEInfos for FheUintBlocksPrep<D, B, T> { +impl<D: DataRef, T: UnsignedInteger, B: Backend> LWEInfos for FheUintBlocksPrepared<D, T, B> { fn base2k(&self) -> poulpy_core::layouts::Base2K { self.blocks[0].base2k() }@@ -232,46 +159,13 @@ self.blocks[0].n()
} } -impl<D: DataRef, T: UnsignedInteger, B: Backend> GLWEInfos for FheUintBlocksPrep<D, B, T> { +impl<D: DataRef, T: UnsignedInteger, B: Backend> GLWEInfos for FheUintBlocksPrepared<D, T, B> { fn rank(&self) -> poulpy_core::layouts::Rank { self.blocks[0].rank() } } -impl<D: DataRef, T: UnsignedInteger, B: Backend> GGSWInfos for FheUintBlocksPrep<D, B, T> { - fn dsize(&self) -> poulpy_core::layouts::Dsize { - self.blocks[0].dsize() - } - - fn dnum(&self) -> poulpy_core::layouts::Dnum { - self.blocks[0].dnum() - } -} - -#[cfg(test)] -impl<D: DataRef, T: UnsignedInteger> LWEInfos for FheUintBlocksPrepDebug<D, T> { - fn base2k(&self) -> poulpy_core::layouts::Base2K { - self.blocks[0].base2k() - } - - fn k(&self) -> poulpy_core::layouts::TorusPrecision { - self.blocks[0].k() - } - - fn n(&self) -> poulpy_core::layouts::Degree { - self.blocks[0].n() - } -} - -#[cfg(test)] -impl<D: DataRef, T: UnsignedInteger> GLWEInfos for FheUintBlocksPrepDebug<D, T> { - fn rank(&self) -> poulpy_core::layouts::Rank { - self.blocks[0].rank() - } -} - -#[cfg(test)] -impl<D: DataRef, T: UnsignedInteger> GGSWInfos for FheUintBlocksPrepDebug<D, T> { +impl<D: DataRef, T: UnsignedInteger, B: Backend> GGSWInfos for FheUintBlocksPrepared<D, T, B> { fn dsize(&self) -> poulpy_core::layouts::Dsize { self.blocks[0].dsize() }
@@ -2,6 +2,11 @@ mod block;
mod block_prepared; mod word; +#[cfg(test)] +mod block_debug; +#[cfg(test)] +pub(crate) use block_debug::*; + pub use block::*; pub use block_prepared::*; pub use word::*;
@@ -1,22 +1,14 @@
use itertools::Itertools; use poulpy_core::{ - GLWEOperations, TakeGLWECtSlice, TakeGLWEPt, glwe_packing, + GLWECopy, GLWEDecrypt, GLWEEncryptSk, GLWEPacking, ScratchTakeCore, layouts::{ - GLWECiphertext, GLWEInfos, GLWEPlaintextLayout, LWEInfos, TorusPrecision, - prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared}, + GLWE, GLWEInfos, GLWEPlaintextLayout, GLWESecretPreparedToRef, LWEInfos, TorusPrecision, + prepared::GLWEAutomorphismKeyPrepared, }, }; use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, - VecZnxAddScalarInplace, VecZnxAutomorphismInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAutomorphismInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, - VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, - VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, + api::ModuleN, + layouts::{Backend, Data, DataMut, DataRef, Scratch}, source::Source, }; use std::{collections::HashMap, marker::PhantomData};@@ -24,57 +16,33 @@
use crate::tfhe::bdd_arithmetic::{FromBits, ToBits, UnsignedInteger}; /// A FHE ciphertext encrypting a [UnsignedInteger]. -pub struct FheUintWord<D: Data, T: UnsignedInteger>(pub(crate) GLWECiphertext<D>, pub(crate) PhantomData<T>); +pub struct FheUintWord<D: Data, T: UnsignedInteger>(pub(crate) GLWE<D>, pub(crate) PhantomData<T>); impl<D: DataMut, T: UnsignedInteger> FheUintWord<D, T> { #[allow(dead_code)] - fn post_process<ATK, BE: Backend>( + fn post_process<ATK, M, BE: Backend>( &mut self, - module: &Module<BE>, - mut tmp_res: Vec<GLWECiphertext<&mut [u8]>>, - auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<ATK, BE>>, + module: &M, + mut tmp_res: Vec<GLWE<&mut [u8]>>, + auto_keys: &HashMap<i64, GLWEAutomorphismKeyPrepared<ATK, BE>>, scratch: &mut Scratch<BE>, ) where ATK: DataRef, - Module<BE>: VecZnxSub - + VecZnxCopy - + VecZnxNegateInplace - + VecZnxDftAllocBytes - + VecZnxAddInplace - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply<BE> - + VmpApplyDftToDft<BE> - + VmpApplyDftToDftAdd<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxBigNormalize<BE> - + VecZnxNormalize<BE> - + VecZnxRotateInplace<BE> - + VecZnxNormalizeInplace<BE> - + VecZnxSwitchRing - + VecZnxBigAutomorphismInplace<BE> - + VecZnxRshInplace<BE> - + VecZnxDftCopy<BE> - + VecZnxIdftApplyTmpA<BE> - + VecZnxSubInplace - + VecZnxBigNormalizeTmpBytes - + VecZnxBigAddSmallInplace<BE> - + VecZnxAutomorphismInplace<BE> - + VecZnxBigSubSmallNegateInplace<BE> - + VecZnxRotate, - Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGLWECtSlice, + M: GLWEPacking<BE> + GLWECopy, + Scratch<BE>: ScratchTakeCore<BE>, { // Repacks the GLWE ciphertexts bits let gap: usize = module.n() / T::WORD_SIZE; let log_gap: usize = (usize::BITS - (gap - 1).leading_zeros()) as usize; - let mut cts: HashMap<usize, &mut GLWECiphertext<&mut [u8]>> = HashMap::new(); + let mut cts: HashMap<usize, &mut GLWE<&mut [u8]>> = HashMap::new(); for (i, ct) in tmp_res.iter_mut().enumerate().take(T::WORD_SIZE) { cts.insert(i * gap, ct); } - glwe_packing(module, &mut cts, log_gap, auto_keys, scratch); + + module.glwe_pack(&mut cts, log_gap, auto_keys, scratch); // And copies the repacked ciphertext on the receiver. - self.0.copy(module, cts.remove(&0).unwrap()) + module.glwe_copy(&mut self.0, cts.remove(&0).unwrap()); } }@@ -99,30 +67,18 @@ }
} impl<D: DataMut, T: UnsignedInteger + ToBits> FheUintWord<D, T> { - pub fn encrypt_sk<S: DataRef, BE: Backend>( + pub fn encrypt_sk<S, M, BE: Backend>( &mut self, - module: &Module<BE>, + module: &M, data: T, - sk: &GLWESecretPrepared<S, BE>, + sk: &S, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch<BE>, ) where - Module<BE>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<BE> - + VecZnxDftApply<BE> - + SvpApplyDftToDftInplace<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<BE> - + VecZnxAddNormal - + VecZnxNormalize<BE> - + VecZnxSub, - Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGLWEPt<BE>, + S: GLWESecretPreparedToRef<BE> + GLWEInfos, + M: ModuleN + GLWEEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { #[cfg(debug_assertions)] {@@ -145,7 +101,7 @@ base2k: self.base2k(),
k: 1_usize.into(), }; - let (mut pt, scratch_1) = scratch.take_glwe_pt(&pt_infos); + let (mut pt, scratch_1) = scratch.take_glwe_plaintext(&pt_infos); pt.encode_vec_i64(&data_bits, TorusPrecision(1)); self.0@@ -154,20 +110,11 @@ }
} impl<D: DataRef, T: UnsignedInteger + FromBits> FheUintWord<D, T> { - pub fn decrypt<S: DataRef, BE: Backend>( - &self, - module: &Module<BE>, - sk: &GLWESecretPrepared<S, BE>, - scratch: &mut Scratch<BE>, - ) -> T + pub fn decrypt<S, M, BE: Backend>(&self, module: &M, sk: &S, scratch: &mut Scratch<BE>) -> T where - Module<BE>: VecZnxDftApply<BE> - + SvpApplyDftToDftInplace<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxBigAddInplace<BE> - + VecZnxBigAddSmallInplace<BE> - + VecZnxBigNormalize<BE>, - Scratch<BE>: TakeVecZnxDft<BE> + TakeVecZnxBig<BE> + TakeGLWEPt<BE>, + S: GLWESecretPreparedToRef<BE> + GLWEInfos, + M: GLWEDecrypt<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { #[cfg(debug_assertions)] {@@ -184,7 +131,7 @@ base2k: self.base2k(),
k: 1_usize.into(), }; - let (mut pt, scratch_1) = scratch.take_glwe_pt(&pt_infos); + let (mut pt, scratch_1) = scratch.take_glwe_plaintext(&pt_infos); self.0.decrypt(module, &mut pt, sk, scratch_1);
@@ -1,15 +1,12 @@
use itertools::Itertools; use poulpy_core::{ - GLWEExternalProductInplace, GLWEOperations, TakeGLWECtSlice, + GLWEAdd, GLWECopy, GLWEExternalProduct, GLWESub, ScratchTakeCore, layouts::{ - GLWECiphertext, GLWECiphertextToMut, LWEInfos, - prepared::{GGSWCiphertextPrepared, GGSWCiphertextPreparedToRef}, + GLWE, LWEInfos, + prepared::{GGSWPrepared, GGSWPreparedToRef}, }, }; -use poulpy_hal::{ - api::{VecZnxAddInplace, VecZnxCopy, VecZnxNegateInplace, VecZnxSub}, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, -}; +use poulpy_hal::layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}; use crate::tfhe::bdd_arithmetic::UnsignedInteger;@@ -31,45 +28,43 @@ }
pub struct Circuit<C: BitCircuitInfo, const N: usize>(pub [C; N]); -pub trait CircuitExecute<BE: Backend, T: UnsignedInteger> -where - Self: GetBitCircuitInfo<T>, -{ - fn execute<O>( +pub trait ExecuteBDDCircuit<T: UnsignedInteger, BE: Backend> { + fn execute_bdd_circuit<C, O>( &self, - module: &Module<BE>, - out: &mut [GLWECiphertext<O>], - inputs: &[&dyn GGSWCiphertextPreparedToRef<BE>], + out: &mut [GLWE<O>], + inputs: &[&dyn GGSWPreparedToRef<BE>], + circuit: &C, scratch: &mut Scratch<BE>, ) where + C: GetBitCircuitInfo<T>, O: DataMut; } -impl<C: BitCircuitInfo, const N: usize, T: UnsignedInteger, BE: Backend> CircuitExecute<BE, T> for Circuit<C, N> +impl<T: UnsignedInteger, BE: Backend> ExecuteBDDCircuit<T, BE> for Module<BE> where - Self: GetBitCircuitInfo<T>, - Module<BE>: Cmux<BE> + VecZnxCopy, - Scratch<BE>: TakeGLWECtSlice, + Self: Cmux<BE> + GLWECopy, + Scratch<BE>: ScratchTakeCore<BE>, { - fn execute<O>( + fn execute_bdd_circuit<C, O>( &self, - module: &Module<BE>, - out: &mut [GLWECiphertext<O>], - inputs: &[&dyn GGSWCiphertextPreparedToRef<BE>], + out: &mut [GLWE<O>], + inputs: &[&dyn GGSWPreparedToRef<BE>], + circuit: &C, scratch: &mut Scratch<BE>, ) where + C: GetBitCircuitInfo<T>, O: DataMut, { #[cfg(debug_assertions)] { - assert_eq!(inputs.len(), self.input_size()); - assert!(out.len() >= self.output_size()); + assert_eq!(inputs.len(), circuit.input_size()); + assert!(out.len() >= circuit.output_size()); } - for (i, out_i) in out.iter_mut().enumerate().take(self.output_size()) { - let (nodes, levels, max_inter_state) = self.get_circuit(i); + for (i, out_i) in out.iter_mut().enumerate().take(circuit.output_size()) { + let (nodes, levels, max_inter_state) = circuit.get_circuit(i); - let (mut level, scratch_1) = scratch.take_glwe_ct_slice(max_inter_state * 2, out_i); + let (mut level, scratch_1) = scratch.take_glwe_slice(max_inter_state * 2, out_i); level.iter_mut().for_each(|ct| ct.data_mut().zero());@@ -89,9 +84,9 @@ let nodes_lvl: &[Node] = &nodes[start..end];
for (j, node) in nodes_lvl.iter().enumerate() { if node.low_index == node.high_index { - next_level[j].copy(module, prev_level[node.low_index]); + self.glwe_copy(next_level[j], prev_level[node.low_index]); } else { - module.cmux( + self.cmux( next_level[j], prev_level[node.high_index], prev_level[node.low_index],@@ -107,7 +102,7 @@
// handle last output // there's always only 1 node at last level let node: &Node = nodes.last().unwrap(); - module.cmux( + self.cmux( out_i, prev_level[node.high_index], prev_level[node.low_index],@@ -116,7 +111,7 @@ scratch_1,
); } - for out_i in out.iter_mut().skip(self.output_size()) { + for out_i in out.iter_mut().skip(circuit.output_size()) { out_i.data_mut().zero(); } }@@ -159,14 +154,8 @@ }
} pub trait Cmux<BE: Backend> { - fn cmux<O, T, F, S>( - &self, - out: &mut GLWECiphertext<O>, - t: &GLWECiphertext<T>, - f: &GLWECiphertext<F>, - s: &GGSWCiphertextPrepared<S, BE>, - scratch: &mut Scratch<BE>, - ) where + fn cmux<O, T, F, S>(&self, out: &mut GLWE<O>, t: &GLWE<T>, f: &GLWE<F>, s: &GGSWPrepared<S, BE>, scratch: &mut Scratch<BE>) + where O: DataMut, T: DataRef, F: DataRef,@@ -175,24 +164,19 @@ }
impl<BE: Backend> Cmux<BE> for Module<BE> where - Module<BE>: GLWEExternalProductInplace<BE> + VecZnxSub + VecZnxCopy + VecZnxNegateInplace + VecZnxAddInplace, + Module<BE>: GLWEExternalProduct<BE> + GLWESub + GLWEAdd, + Scratch<BE>: ScratchTakeCore<BE>, { - fn cmux<O, T, F, S>( - &self, - out: &mut GLWECiphertext<O>, - t: &GLWECiphertext<T>, - f: &GLWECiphertext<F>, - s: &GGSWCiphertextPrepared<S, BE>, - scratch: &mut Scratch<BE>, - ) where + fn cmux<O, T, F, S>(&self, out: &mut GLWE<O>, t: &GLWE<T>, f: &GLWE<F>, s: &GGSWPrepared<S, BE>, scratch: &mut Scratch<BE>) + where O: DataMut, T: DataRef, F: DataRef, S: DataRef, { // let mut out: GLWECiphertext<&mut [u8]> = out.to_mut(); - out.sub(self, t, f); - out.external_product_inplace(self, s, scratch); - out.to_mut().add_inplace(self, f); + self.glwe_sub(out, t, f); + self.glwe_external_product_inplace(out, s, scratch); + self.glwe_add_inplace(out, f); } }
@@ -1,29 +1,21 @@
#[cfg(test)] -use crate::tfhe::bdd_arithmetic::FheUintBlocksPrepDebug; +use crate::tfhe::bdd_arithmetic::FheUintBlocksPreparedDebug; use crate::tfhe::{ - bdd_arithmetic::{FheUintBlocks, FheUintBlocksPrep, UnsignedInteger}, - blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk}, + bdd_arithmetic::{FheUintBlocks, FheUintBlocksPrepared, UnsignedInteger}, + blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyFactory}, circuit_bootstrapping::{ CircuitBootstrappingKey, CircuitBootstrappingKeyEncryptSk, CircuitBootstrappingKeyLayout, - CircuitBootstrappingKeyPrepared, CirtuitBootstrappingExecute, + CircuitBootstrappingKeyPrepared, CircuitBootstrappingKeyPreparedFactory, CirtuitBootstrappingExecute, }, }; use poulpy_core::{ - TakeGGSW, TakeGLWECt, + GLWEToLWESwitchingKeyEncryptSk, GetDistribution, LWEFromGLWE, ScratchTakeCore, layouts::{ - GLWESecret, GLWEToLWEKey, GLWEToLWEKeyLayout, LWECiphertext, LWESecret, - prepared::{GLWEToLWESwitchingKeyPrepared, Prepare, PrepareAlloc}, + GGSWInfos, GGSWPreparedFactory, GLWEInfos, GLWESecretToRef, GLWEToLWEKeyLayout, GLWEToLWESwitchingKey, + GLWEToLWESwitchingKeyPreparedFactory, LWE, LWEInfos, LWESecretToRef, prepared::GLWEToLWESwitchingKeyPrepared, }, }; use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, - TakeSvpPPol, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, - VecZnxAutomorphism, VecZnxAutomorphismInplace, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, - VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPrepare, - }, layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, source::Source, };@@ -49,193 +41,256 @@ self.ks
} } -pub struct BDDKey<CBT, LWE, BRA> +pub struct BDDKey<D, BRA> where - CBT: Data, - LWE: Data, + D: Data, BRA: BlindRotationAlgo, { - cbt: CircuitBootstrappingKey<CBT, BRA>, - ks: GLWEToLWEKey<LWE>, + cbt: CircuitBootstrappingKey<D, BRA>, + ks: GLWEToLWESwitchingKey<D>, +} + +impl<BRA: BlindRotationAlgo> BDDKey<Vec<u8>, BRA> +where + BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, +{ + pub fn alloc_from_infos<A>(infos: &A) -> Self + where + A: BDDKeyInfos, + { + Self { + cbt: CircuitBootstrappingKey::alloc_from_infos(&infos.cbt_infos()), + ks: GLWEToLWESwitchingKey::alloc_from_infos(&infos.ks_infos()), + } + } +} + +pub trait BDDKeyEncryptSk<BRA: BlindRotationAlgo, BE: Backend> { + fn bdd_key_encrypt_sk<D, S0, S1>( + &self, + res: &mut BDDKey<D, BRA>, + sk_lwe: &S0, + sk_glwe: &S1, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + D: DataMut, + S0: LWESecretToRef + GetDistribution + LWEInfos, + S1: GLWESecretToRef + GetDistribution + GLWEInfos; } -impl<BRA: BlindRotationAlgo> BDDKey<Vec<u8>, Vec<u8>, BRA> { - pub fn encrypt_sk<DLwe, DGlwe, A, BE: Backend>( - module: &Module<BE>, - sk_lwe: &LWESecret<DLwe>, - sk_glwe: &GLWESecret<DGlwe>, - infos: &A, +impl<BE: Backend, BRA: BlindRotationAlgo> BDDKeyEncryptSk<BRA, BE> for Module<BE> +where + Self: CircuitBootstrappingKeyEncryptSk<BRA, BE> + GLWEToLWESwitchingKeyEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn bdd_key_encrypt_sk<D, S0, S1>( + &self, + res: &mut BDDKey<D, BRA>, + sk_lwe: &S0, + sk_glwe: &S1, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch<BE>, - ) -> Self - where - A: BDDKeyInfos, - DLwe: DataRef, - DGlwe: DataRef, - BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<BE>, - Module<BE>: SvpApplyDftToDft<BE> - + VecZnxIdftApplyTmpA<BE> - + VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<BE> - + VecZnxDftApply<BE> - + SvpApplyDftToDftInplace<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<BE> - + VecZnxAddNormal - + VecZnxNormalize<BE> - + VecZnxSub - + SvpPrepare<BE> - + VecZnxSwitchRing - + SvpPPolAllocBytes - + SvpPPolAlloc<BE> - + VecZnxAutomorphism - + VecZnxAutomorphismInplace<BE>, - Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeSvpPPol<BE> + TakeVecZnxBig<BE>, + ) where + D: DataMut, + S0: LWESecretToRef + GetDistribution + LWEInfos, + S1: GLWESecretToRef + GetDistribution + GLWEInfos, { - let mut ks: GLWEToLWEKey<Vec<u8>> = GLWEToLWEKey::alloc(&infos.ks_infos()); - ks.encrypt_sk(module, sk_lwe, sk_glwe, source_xa, source_xe, scratch); + res.ks + .encrypt_sk(self, sk_lwe, sk_glwe, source_xa, source_xe, scratch); + res.cbt + .encrypt_sk(self, sk_lwe, sk_glwe, source_xa, source_xe, scratch); + } +} - Self { - cbt: CircuitBootstrappingKey::encrypt_sk( - module, - sk_lwe, - sk_glwe, - &infos.cbt_infos(), - source_xa, - source_xe, - scratch, - ), - ks, - } +impl<D: DataMut, BRA: BlindRotationAlgo> BDDKey<D, BRA> { + pub fn encrypt_sk<S0, S1, M, BE: Backend>( + &mut self, + module: &M, + sk_lwe: &S0, + sk_glwe: &S1, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S0: LWESecretToRef + GetDistribution + LWEInfos, + S1: GLWESecretToRef + GetDistribution + GLWEInfos, + M: BDDKeyEncryptSk<BRA, BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.bdd_key_encrypt_sk(self, sk_lwe, sk_glwe, source_xa, source_xe, scratch); } } -pub struct BDDKeyPrepared<CBT, LWE, BRA, BE> +pub struct BDDKeyPrepared<D, BRA, BE> where - CBT: Data, - LWE: Data, + D: Data, BRA: BlindRotationAlgo, BE: Backend, { - cbt: CircuitBootstrappingKeyPrepared<CBT, BRA, BE>, - ks: GLWEToLWESwitchingKeyPrepared<LWE, BE>, + pub(crate) cbt: CircuitBootstrappingKeyPrepared<D, BRA, BE>, + pub(crate) ks: GLWEToLWESwitchingKeyPrepared<D, BE>, } -impl<CBT: DataMut, LWE: DataMut, BRA: BlindRotationAlgo, BE: Backend> PrepareAlloc<BE, BDDKeyPrepared<CBT, LWE, BRA, BE>> - for BDDKey<CBT, LWE, BRA> +pub trait BDDKeyPreparedFactory<BRA: BlindRotationAlgo, BE: Backend> where - CircuitBootstrappingKey<CBT, BRA>: PrepareAlloc<BE, CircuitBootstrappingKeyPrepared<CBT, BRA, BE>>, - GLWEToLWEKey<LWE>: PrepareAlloc<BE, GLWEToLWESwitchingKeyPrepared<LWE, BE>>, + Self: Sized + CircuitBootstrappingKeyPreparedFactory<BRA, BE> + GLWEToLWESwitchingKeyPreparedFactory<BE>, { - fn prepare_alloc(&self, module: &Module<BE>, scratch: &mut Scratch<BE>) -> BDDKeyPrepared<CBT, LWE, BRA, BE> { + fn alloc_bdd_key_from_infos<A>(&self, infos: &A) -> BDDKeyPrepared<Vec<u8>, BRA, BE> + where + A: BDDKeyInfos, + { BDDKeyPrepared { - cbt: self.cbt.prepare_alloc(module, scratch), - ks: self.ks.prepare_alloc(module, scratch), + cbt: CircuitBootstrappingKeyPrepared::alloc_from_infos(self, &infos.cbt_infos()), + ks: GLWEToLWESwitchingKeyPrepared::alloc_from_infos(self, &infos.ks_infos()), } } + + fn prepare_bdd_key_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: BDDKeyInfos, + { + self.circuit_bootstrapping_key_prepare_tmp_bytes(&infos.cbt_infos()) + .max(self.prepare_glwe_to_lwe_switching_key_tmp_bytes(&infos.ks_infos())) + } + + fn prepare_bdd_key<DM, DR>(&self, res: &mut BDDKeyPrepared<DM, BRA, BE>, other: &BDDKey<DR, BRA>, scratch: &mut Scratch<BE>) + where + DM: DataMut, + DR: DataRef, + Scratch<BE>: ScratchTakeCore<BE>, + { + res.cbt.prepare(self, &other.cbt, scratch); + res.ks.prepare(self, &other.ks, scratch); + } +} +impl<BRA: BlindRotationAlgo, BE: Backend> BDDKeyPreparedFactory<BRA, BE> for Module<BE> where + Self: Sized + CircuitBootstrappingKeyPreparedFactory<BRA, BE> + GLWEToLWESwitchingKeyPreparedFactory<BE> +{ } -pub trait FheUintPrepare<BE: Backend, OUT, IN> { - fn prepare(&self, module: &Module<BE>, out: &mut OUT, bits: &IN, scratch: &mut Scratch<BE>); +impl<BRA: BlindRotationAlgo, BE: Backend> BDDKeyPrepared<Vec<u8>, BRA, BE> { + pub fn alloc_from_infos<M, A>(module: &M, infos: &A) -> Self + where + M: BDDKeyPreparedFactory<BRA, BE>, + A: BDDKeyInfos, + { + module.alloc_bdd_key_from_infos(infos) + } } -impl<CBT, OUT, IN, LWE, BRA, BE, T> FheUintPrepare<BE, FheUintBlocksPrep<OUT, BE, T>, FheUintBlocks<IN, T>> - for BDDKeyPrepared<CBT, LWE, BRA, BE> +impl<D: DataMut, BRA: BlindRotationAlgo, BE: Backend> BDDKeyPrepared<D, BRA, BE> { + pub fn prepare<DR, M>(&mut self, module: &M, other: &BDDKey<DR, BRA>, scratch: &mut Scratch<BE>) + where + DR: DataRef, + M: BDDKeyPreparedFactory<BRA, BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.prepare_bdd_key(self, other, scratch); + } +} + +pub trait FheUintBlocksPrepare<BRA: BlindRotationAlgo, T: UnsignedInteger, BE: Backend> { + fn fhe_uint_blocks_prepare_tmp_bytes<R, A>( + &self, + block_size: usize, + extension_factor: usize, + res_infos: &R, + infos: &A, + ) -> usize + where + R: GGSWInfos, + A: BDDKeyInfos; + fn fhe_uint_blocks_prepare<DM, DR0, DR1>( + &self, + res: &mut FheUintBlocksPrepared<DM, T, BE>, + bits: &FheUintBlocks<DR0, T>, + key: &BDDKeyPrepared<DR1, BRA, BE>, + scratch: &mut Scratch<BE>, + ) where + DM: DataMut, + DR0: DataRef, + DR1: DataRef; +} + +impl<BRA: BlindRotationAlgo, BE: Backend, T: UnsignedInteger> FheUintBlocksPrepare<BRA, T, BE> for Module<BE> where - T: UnsignedInteger, - CBT: DataRef, - OUT: DataMut, - IN: DataRef, - LWE: DataRef, - BRA: BlindRotationAlgo, - BE: Backend, - Module<BE>: VmpPrepare<BE> - + VecZnxRotate - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<BE> - + VmpApplyDftToDftAdd<BE> - + VecZnxDftApply<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxBigAddSmallInplace<BE> - + VecZnxBigNormalize<BE> - + VecZnxNormalize<BE> - + VecZnxNormalizeTmpBytes, - Scratch<BE>: ScratchAvailable + TakeVecZnxDft<BE> + TakeGLWECt + TakeVecZnx + TakeGGSW, - CircuitBootstrappingKeyPrepared<CBT, BRA, BE>: CirtuitBootstrappingExecute<BE>, + Self: LWEFromGLWE<BE> + CirtuitBootstrappingExecute<BRA, BE> + GGSWPreparedFactory<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { - fn prepare( + fn fhe_uint_blocks_prepare_tmp_bytes<R, A>( &self, - module: &Module<BE>, - out: &mut FheUintBlocksPrep<OUT, BE, T>, - bits: &FheUintBlocks<IN, T>, + block_size: usize, + extension_factor: usize, + res_infos: &R, + bdd_infos: &A, + ) -> usize + where + R: GGSWInfos, + A: BDDKeyInfos, + { + self.circuit_bootstrapping_execute_tmp_bytes( + block_size, + extension_factor, + res_infos, + &bdd_infos.cbt_infos(), + ) + } + + fn fhe_uint_blocks_prepare<DM, DR0, DR1>( + &self, + res: &mut FheUintBlocksPrepared<DM, T, BE>, + bits: &FheUintBlocks<DR0, T>, + key: &BDDKeyPrepared<DR1, BRA, BE>, scratch: &mut Scratch<BE>, - ) { - #[cfg(debug_assertions)] - { - assert_eq!(out.blocks.len(), bits.blocks.len()); - } - let mut lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&bits.blocks[0]); //TODO: add TakeLWE - let (mut tmp_ggsw, scratch_1) = scratch.take_ggsw(out); - for (dst, src) in out.blocks.iter_mut().zip(bits.blocks.iter()) { - lwe.from_glwe(module, src, &self.ks, scratch_1); - self.cbt - .execute_to_constant(module, &mut tmp_ggsw, &lwe, 1, 1, scratch_1); - dst.prepare(module, &tmp_ggsw, scratch_1); + ) where + DM: DataMut, + DR0: DataRef, + DR1: DataRef, + { + assert_eq!(res.blocks.len(), bits.blocks.len()); + + let mut lwe: LWE<Vec<u8>> = LWE::alloc_from_infos(&bits.blocks[0]); //TODO: add TakeLWE + let (mut tmp_ggsw, scratch_1) = scratch.take_ggsw(res); + for (dst, src) in res.blocks.iter_mut().zip(bits.blocks.iter()) { + lwe.from_glwe(self, src, &key.ks, scratch_1); + key.cbt + .execute_to_constant(self, &mut tmp_ggsw, &lwe, 1, 1, scratch_1); + dst.prepare(self, &tmp_ggsw, scratch_1); } } } +impl<D: DataMut, T: UnsignedInteger, BE: Backend> FheUintBlocksPrepared<D, T, BE> { + pub fn prepare<BRA, M, O, K>( + &mut self, + module: &M, + other: &FheUintBlocks<O, T>, + key: &BDDKeyPrepared<K, BRA, BE>, + scratch: &mut Scratch<BE>, + ) where + BRA: BlindRotationAlgo, + O: DataRef, + K: DataRef, + M: FheUintBlocksPrepare<BRA, T, BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.fhe_uint_blocks_prepare(self, other, key, scratch); + } +} + #[cfg(test)] -impl<CBT, OUT, IN, LWE, BRA, BE, T> FheUintPrepare<BE, FheUintBlocksPrepDebug<OUT, T>, FheUintBlocks<IN, T>> - for BDDKeyPrepared<CBT, LWE, BRA, BE> -where - T: UnsignedInteger, - CBT: DataRef, - OUT: DataMut, - IN: DataRef, - LWE: DataRef, - BRA: BlindRotationAlgo, - BE: Backend, - Module<BE>: VmpPrepare<BE> - + VecZnxRotate - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<BE> - + VmpApplyDftToDftAdd<BE> - + VecZnxDftApply<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxBigAddSmallInplace<BE> - + VecZnxBigNormalize<BE> - + VecZnxNormalize<BE> - + VecZnxNormalizeTmpBytes, - Scratch<BE>: ScratchAvailable + TakeVecZnxDft<BE> + TakeGLWECt + TakeVecZnx + TakeGGSW, - CircuitBootstrappingKeyPrepared<CBT, BRA, BE>: CirtuitBootstrappingExecute<BE>, -{ - fn prepare( +pub(crate) trait FheUintBlockDebugPrepare<BRA: BlindRotationAlgo, T: UnsignedInteger, BE: Backend> { + fn fhe_uint_block_debug_prepare<DM, DR0, DR1>( &self, - module: &Module<BE>, - out: &mut FheUintBlocksPrepDebug<OUT, T>, - bits: &FheUintBlocks<IN, T>, + res: &mut FheUintBlocksPreparedDebug<DM, T>, + bits: &FheUintBlocks<DR0, T>, + key: &BDDKeyPrepared<DR1, BRA, BE>, scratch: &mut Scratch<BE>, - ) { - #[cfg(debug_assertions)] - { - assert_eq!(out.blocks.len(), bits.blocks.len()); - } - let mut lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&bits.blocks[0]); //TODO: add TakeLWE - for (dst, src) in out.blocks.iter_mut().zip(bits.blocks.iter()) { - lwe.from_glwe(module, src, &self.ks, scratch); - self.cbt - .execute_to_constant(module, dst, &lwe, 1, 1, scratch); - } - } + ) where + DM: DataMut, + DR0: DataRef, + DR1: DataRef; }
@@ -1,7 +1,7 @@
#[cfg(test)] use poulpy_core::layouts::{ - Base2K, Degree, Dnum, Dsize, GGLWEAutomorphismKeyLayout, GGLWETensorKeyLayout, GGSWCiphertextLayout, GLWECiphertextLayout, - GLWEToLWEKeyLayout, Rank, TorusPrecision, + Base2K, Degree, Dnum, Dsize, GGSWLayout, GLWEAutomorphismKeyLayout, GLWELayout, GLWETensorKeyLayout, GLWEToLWEKeyLayout, + Rank, TorusPrecision, }; #[cfg(test)]@@ -25,7 +25,7 @@ #[cfg(test)]
pub(crate) const TEST_RANK: u32 = 2; #[cfg(test)] -pub(crate) static TEST_GLWE_INFOS: GLWECiphertextLayout = GLWECiphertextLayout { +pub(crate) static TEST_GLWE_INFOS: GLWELayout = GLWELayout { n: Degree(TEST_N_GLWE), base2k: Base2K(TEST_BASE2K), k: TorusPrecision(TEST_K_GLWE),@@ -33,7 +33,7 @@ rank: Rank(TEST_RANK),
}; #[cfg(test)] -pub(crate) static TEST_GGSW_INFOS: GGSWCiphertextLayout = GGSWCiphertextLayout { +pub(crate) static TEST_GGSW_INFOS: GGSWLayout = GGSWLayout { n: Degree(TEST_N_GLWE), base2k: Base2K(TEST_BASE2K), k: TorusPrecision(TEST_K_GGSW),@@ -53,7 +53,7 @@ k: TorusPrecision(52),
dnum: Dnum(3), rank: Rank(TEST_RANK), }, - layout_atk: GGLWEAutomorphismKeyLayout { + layout_atk: GLWEAutomorphismKeyLayout { n: Degree(TEST_N_GLWE), base2k: Base2K(TEST_BASE2K), k: TorusPrecision(52),@@ -61,7 +61,7 @@ rank: Rank(TEST_RANK),
dnum: Dnum(3), dsize: Dsize(1), }, - layout_tsk: GGLWETensorKeyLayout { + layout_tsk: GLWETensorKeyLayout { n: Degree(TEST_N_GLWE), base2k: Base2K(TEST_BASE2K), k: TorusPrecision(52),
@@ -2,43 +2,24 @@ use std::time::Instant;
use poulpy_backend::FFT64Ref; use poulpy_core::{ - TakeGGSW, TakeGLWEPt, - layouts::{ - GGSWCiphertextLayout, GLWECiphertextLayout, GLWESecret, LWEInfos, LWESecret, - prepared::{GLWESecretPrepared, PrepareAlloc}, - }, + GGSWNoise, GLWEDecrypt, GLWENoise, ScratchTakeCore, + layouts::{GGSWLayout, GLWELayout, GLWESecret, GLWESecretPreparedFactory, LWEInfos, LWESecret, prepared::GLWESecretPrepared}, }; use poulpy_hal::{ - api::{ - ModuleNew, ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, - SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeSlice, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, - VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, - VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, - VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAddInplace, - VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxFillUniform, VecZnxIdftApplyConsume, - VecZnxIdftApplyTmpA, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, - VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, ZnAddNormal, ZnFillUniform, - ZnNormalizeInplace, - }, + api::{ModuleNew, ScratchOwnedAlloc, ScratchOwnedBorrow}, layouts::{Backend, Module, Scratch, ScratchOwned}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeMatZnxImpl, TakeScalarZnxImpl, TakeSvpPPolImpl, - TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, - }, source::Source, }; use rand::RngCore; use crate::tfhe::{ bdd_arithmetic::{ - Add, BDDKey, BDDKeyLayout, BDDKeyPrepared, FheUintBlocks, FheUintBlocksPrep, FheUintBlocksPrepDebug, Sub, - TEST_BDD_KEY_LAYOUT, TEST_BLOCK_SIZE, TEST_GGSW_INFOS, TEST_GLWE_INFOS, TEST_N_LWE, - }, - blind_rotation::{ - BlincRotationExecute, BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, - BlindRotationKeyPrepared, CGGI, + Add, BDDKey, BDDKeyEncryptSk, BDDKeyLayout, BDDKeyPrepared, BDDKeyPreparedFactory, ExecuteBDDCircuit2WTo1W, + FheUintBlockDebugPrepare, FheUintBlocks, FheUintBlocksPrepare, FheUintBlocksPrepared, FheUintBlocksPreparedDebug, + FheUintBlocksPreparedEncryptSk, FheUintBlocksPreparedFactory, Sub, TEST_BDD_KEY_LAYOUT, TEST_BLOCK_SIZE, TEST_GGSW_INFOS, + TEST_GLWE_INFOS, TEST_N_LWE, }, + blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyFactory, CGGI}, }; #[test]@@ -48,67 +29,24 @@ }
fn test_bdd_2w_to_1w<BE: Backend, BRA: BlindRotationAlgo>() where - Module<BE>: ModuleNew<BE> + SvpPPolAlloc<BE> + SvpPrepare<BE> + VmpPMatAlloc<BE>, + Module<BE>: ModuleNew<BE> + + GLWESecretPreparedFactory<BE> + + GLWEDecrypt<BE> + + GLWENoise<BE> + + FheUintBlocksPreparedFactory<u32, BE> + + FheUintBlocksPreparedEncryptSk<u32, BE> + + FheUintBlockDebugPrepare<BRA, u32, BE> + + BDDKeyEncryptSk<BRA, BE> + + BDDKeyPreparedFactory<BRA, BE> + + GGSWNoise<BE> + + FheUintBlocksPrepare<BRA, u32, BE> + + ExecuteBDDCircuit2WTo1W<u32, BE>, + BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, - Module<BE>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<BE> - + VecZnxDftApply<BE> - + SvpApplyDftToDftInplace<BE> - + VecZnxIdftApplyConsume<BE> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<BE> - + VecZnxAddNormal - + VecZnxNormalize<BE> - + VecZnxSub - + VmpPrepare<BE>, - Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGGSW + TakeScalarZnx + TakeSlice, - Module<BE>: VecZnxCopy + VecZnxNegateInplace + VmpApplyDftToDftTmpBytes + VmpApplyDftToDft<BE> + VmpApplyDftToDftAdd<BE>, - Module<BE>: VecZnxBigAddInplace<BE> + VecZnxBigAddSmallInplace<BE> + VecZnxBigNormalize<BE>, - Scratch<BE>: TakeVecZnxDft<BE> + TakeVecZnxBig<BE> + TakeGLWEPt<BE>, - Module<BE>: VecZnxAutomorphism - + VecZnxSwitchRing - + VecZnxBigAllocBytes - + VecZnxIdftApplyTmpA<BE> - + SvpApplyDftToDft<BE> - + VecZnxBigAlloc<BE> - + VecZnxDftAlloc<BE> - + VecZnxBigNormalizeTmpBytes - + SvpPPolAllocBytes - + VecZnxRotateInplace<BE> - + VecZnxBigAutomorphismInplace<BE> - + VecZnxRshInplace<BE> - + VecZnxDftCopy<BE> - + VecZnxAutomorphismInplace<BE> - + VecZnxBigSubSmallNegateInplace<BE> - + VecZnxRotateInplaceTmpBytes - + VecZnxBigAllocBytes - + VecZnxDftAddInplace<BE> - + VecZnxRotate - + ZnFillUniform - + ZnAddNormal - + ZnNormalizeInplace<BE>, - BE: Backend - + ScratchOwnedAllocImpl<BE> - + ScratchOwnedBorrowImpl<BE> - + TakeVecZnxDftImpl<BE> - + ScratchAvailableImpl<BE> - + TakeVecZnxImpl<BE> - + TakeScalarZnxImpl<BE> - + TakeSvpPPolImpl<BE> - + TakeVecZnxBigImpl<BE> - + TakeVecZnxDftSliceImpl<BE> - + TakeMatZnxImpl<BE> - + TakeVecZnxSliceImpl<BE>, - BlindRotationKey<Vec<u8>, BRA>: PrepareAlloc<BE, BlindRotationKeyPrepared<Vec<u8>, BRA, BE>>, - BlindRotationKeyPrepared<Vec<u8>, BRA, BE>: BlincRotationExecute<BE>, - BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { - let glwe_infos: GLWECiphertextLayout = TEST_GLWE_INFOS; - let ggsw_infos: GGSWCiphertextLayout = TEST_GGSW_INFOS; + let glwe_infos: GLWELayout = TEST_GLWE_INFOS; + let ggsw_infos: GGSWLayout = TEST_GGSW_INFOS; let n_glwe: usize = glwe_infos.n().into();@@ -120,9 +58,10 @@ let mut source_xe: Source = Source::new([3u8; 32]);
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 22); - let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos); + let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos); sk_glwe.fill_ternary_prob(0.5, &mut source_xs); - let sk_glwe_prep: GLWESecretPrepared<Vec<u8>, BE> = sk_glwe.prepare_alloc(&module, scratch.borrow()); + let mut sk_glwe_prep: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(&module, &glwe_infos); + sk_glwe_prep.prepare(&module, &sk_glwe); let a: u32 = source.next_u32(); let b: u32 = source.next_u32();@@ -130,12 +69,15 @@
println!("a: {a}"); println!("b: {b}"); - let mut a_enc_prep: FheUintBlocksPrep<Vec<u8>, BE, u32> = FheUintBlocksPrep::<Vec<u8>, BE, u32>::alloc(&module, &ggsw_infos); - let mut b_enc_prep: FheUintBlocksPrep<Vec<u8>, BE, u32> = FheUintBlocksPrep::<Vec<u8>, BE, u32>::alloc(&module, &ggsw_infos); + let mut a_enc_prep: FheUintBlocksPrepared<Vec<u8>, u32, BE> = + FheUintBlocksPrepared::<Vec<u8>, u32, BE>::alloc(&module, &ggsw_infos); + let mut b_enc_prep: FheUintBlocksPrepared<Vec<u8>, u32, BE> = + FheUintBlocksPrepared::<Vec<u8>, u32, BE>::alloc(&module, &ggsw_infos); let mut c_enc: FheUintBlocks<Vec<u8>, u32> = FheUintBlocks::<Vec<u8>, u32>::alloc(&module, &glwe_infos); - let mut c_enc_prep_debug: FheUintBlocksPrepDebug<Vec<u8>, u32> = - FheUintBlocksPrepDebug::<Vec<u8>, u32>::alloc(&module, &ggsw_infos); - let mut c_enc_prep: FheUintBlocksPrep<Vec<u8>, BE, u32> = FheUintBlocksPrep::<Vec<u8>, BE, u32>::alloc(&module, &ggsw_infos); + let mut c_enc_prep_debug: FheUintBlocksPreparedDebug<Vec<u8>, u32> = + FheUintBlocksPreparedDebug::<Vec<u8>, u32>::alloc(&module, &ggsw_infos); + let mut c_enc_prep: FheUintBlocksPrepared<Vec<u8>, u32, BE> = + FheUintBlocksPrepared::<Vec<u8>, u32, BE>::alloc(&module, &ggsw_infos); a_enc_prep.encrypt_sk( &module,@@ -178,17 +120,19 @@ sk_lwe.fill_binary_block(block_size as usize, &mut source_xs);
let bdd_key_infos: BDDKeyLayout = TEST_BDD_KEY_LAYOUT; + let mut bdd_key: BDDKey<Vec<u8>, BRA> = BDDKey::alloc_from_infos(&bdd_key_infos); + let now: Instant = Instant::now(); - let bdd_key: BDDKey<Vec<u8>, Vec<u8>, BRA> = BDDKey::encrypt_sk( + bdd_key.encrypt_sk( &module, &sk_lwe, &sk_glwe, - &bdd_key_infos, &mut source_xa, &mut source_xe, scratch.borrow(), ); - let bdd_key_prepared: BDDKeyPrepared<Vec<u8>, Vec<u8>, BRA, BE> = bdd_key.prepare_alloc(&module, scratch.borrow()); + let mut bdd_key_prepared: BDDKeyPrepared<Vec<u8>, BRA, BE> = BDDKeyPrepared::alloc_from_infos(&module, &bdd_key_infos); + bdd_key_prepared.prepare(&module, &bdd_key, scratch.borrow()); println!("BDD-KGEN: {} ms", now.elapsed().as_millis()); let now: Instant = Instant::now();
@@ -0,0 +1,469 @@
+use itertools::izip; +use poulpy_hal::{ + api::{ + ModuleN, ScratchTakeBasic, SvpApplyDftToDft, VecZnxBigAddSmallInplace, VecZnxBigBytesOf, VecZnxBigNormalize, + VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAddInplace, VecZnxDftApply, VecZnxDftBytesOf, VecZnxDftSubInplace, + VecZnxDftZero, VecZnxIdftApply, VecZnxIdftApplyTmpBytes, VecZnxRotate, VmpApplyDftToDft, VmpApplyDftToDftTmpBytes, + }, + layouts::{Backend, DataMut, DataRef, Module, Scratch, SvpPPol, VecZnx, ZnxZero}, +}; + +use poulpy_core::{ + Distribution, GLWEAdd, GLWEExternalProduct, GLWEMulXpMinusOne, GLWENormalize, ScratchTakeCore, + layouts::{GGSWInfos, GLWE, GLWEInfos, GLWEToMut, LWE, LWEInfos, LWEToRef}, +}; + +use crate::tfhe::blind_rotation::{ + BlindRotationExecute, BlindRotationKeyInfos, BlindRotationKeyPrepared, CGGI, LookupTable, mod_switch_2n, +}; + +impl<BE: Backend> BlindRotationExecute<CGGI, BE> for Module<BE> +where + Self: VecZnxDftBytesOf + + VecZnxBigBytesOf + + VmpApplyDftToDftTmpBytes + + VecZnxBigNormalizeTmpBytes + + VecZnxIdftApplyTmpBytes + + GLWEExternalProduct<BE> + + ModuleN + + VecZnxRotate + + VecZnxDftApply<BE> + + VecZnxDftZero<BE> + + VmpApplyDftToDft<BE> + + SvpApplyDftToDft<BE> + + VecZnxDftAddInplace<BE> + + VecZnxDftSubInplace<BE> + + VecZnxIdftApply<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxCopy + + GLWEMulXpMinusOne<BE> + + GLWEAdd + + GLWENormalize<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn blind_rotation_execute_tmp_bytes<G, B>( + &self, + block_size: usize, + extension_factor: usize, + glwe_infos: &G, + brk_infos: &B, + ) -> usize + where + G: GLWEInfos, + B: GGSWInfos, + { + let brk_size: usize = brk_infos.size(); + + if block_size > 1 { + let cols: usize = (brk_infos.rank() + 1).into(); + let dnum: usize = brk_infos.dnum().into(); + let acc_dft: usize = self.bytes_of_vec_znx_dft(cols, dnum) * extension_factor; + let acc_big: usize = self.bytes_of_vec_znx_big(1, brk_size); + let vmp_res: usize = self.bytes_of_vec_znx_dft(cols, brk_size) * extension_factor; + let vmp_xai: usize = self.bytes_of_vec_znx_dft(1, brk_size); + let acc_dft_add: usize = vmp_res; + let vmp: usize = self.vmp_apply_dft_to_dft_tmp_bytes(brk_size, dnum, dnum, 2, 2, brk_size); // GGSW product: (1 x 2) x (2 x 2) + let acc: usize = if extension_factor > 1 { + VecZnx::bytes_of(self.n(), cols, glwe_infos.size()) * extension_factor + } else { + 0 + }; + + acc + acc_dft + + acc_dft_add + + vmp_res + + vmp_xai + + (vmp + | (acc_big + + (self + .vec_znx_big_normalize_tmp_bytes() + .max(self.vec_znx_idft_apply_tmp_bytes())))) + } else { + GLWE::bytes_of_from_infos(glwe_infos) + GLWE::external_product_tmp_bytes(self, glwe_infos, glwe_infos, brk_infos) + } + } + + fn blind_rotation_execute<DR, DL, DB>( + &self, + res: &mut GLWE<DR>, + lwe: &LWE<DL>, + lut: &LookupTable, + brk: &BlindRotationKeyPrepared<DB, CGGI, BE>, + scratch: &mut Scratch<BE>, + ) where + DR: DataMut, + DL: DataRef, + DB: DataRef, + { + match brk.dist { + Distribution::BinaryBlock(_) | Distribution::BinaryFixed(_) | Distribution::BinaryProb(_) | Distribution::ZERO => { + if lut.extension_factor() > 1 { + execute_block_binary_extended(self, res, lwe, lut, brk, scratch) + } else if brk.block_size() > 1 { + execute_block_binary(self, res, lwe, lut, brk, scratch); + } else { + execute_standard(self, res, lwe, lut, brk, scratch); + } + } + _ => panic!("invalid CGGI distribution (have you prepared the key?)"), + } + } +} + +fn execute_block_binary_extended<DataRes, DataIn, DataBrk, M, BE: Backend>( + module: &M, + res: &mut GLWE<DataRes>, + lwe: &LWE<DataIn>, + lut: &LookupTable, + brk: &BlindRotationKeyPrepared<DataBrk, CGGI, BE>, + scratch: &mut Scratch<BE>, +) where + DataRes: DataMut, + DataIn: DataRef, + DataBrk: DataRef, + M: VecZnxDftBytesOf + + ModuleN + + VecZnxRotate + + VecZnxDftApply<BE> + + VecZnxDftZero<BE> + + VmpApplyDftToDft<BE> + + SvpApplyDftToDft<BE> + + VecZnxDftAddInplace<BE> + + VecZnxDftSubInplace<BE> + + VecZnxIdftApply<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxCopy + + VecZnxBigBytesOf, + Scratch<BE>: ScratchTakeCore<BE>, +{ + let n_glwe: usize = brk.n_glwe().into(); + let extension_factor: usize = lut.extension_factor(); + let base2k: usize = res.base2k().into(); + let dnum: usize = brk.dnum().into(); + let cols: usize = (res.rank() + 1).into(); + + let (mut acc, scratch_1) = scratch.take_vec_znx_slice(extension_factor, n_glwe, cols, res.size()); + let (mut acc_dft, scratch_2) = scratch_1.take_vec_znx_dft_slice(module, extension_factor, cols, dnum); + let (mut vmp_res, scratch_3) = scratch_2.take_vec_znx_dft_slice(module, extension_factor, cols, brk.size()); + let (mut acc_add_dft, scratch_4) = scratch_3.take_vec_znx_dft_slice(module, extension_factor, cols, brk.size()); + let (mut vmp_xai, scratch_5) = scratch_4.take_vec_znx_dft(module, 1, brk.size()); + + (0..extension_factor).for_each(|i| { + acc[i].zero(); + }); + + let x_pow_a: &Vec<SvpPPol<Vec<u8>, BE>>; + if let Some(b) = &brk.x_pow_a { + x_pow_a = b + } else { + panic!("invalid key: x_pow_a has not been initialized") + } + + let mut lwe_2n: Vec<i64> = vec![0i64; (lwe.n() + 1).as_usize()]; // TODO: from scratch space + let lwe_ref: LWE<&[u8]> = lwe.to_ref(); + + let two_n: usize = 2 * n_glwe; + let two_n_ext: usize = 2 * lut.domain_size(); + + mod_switch_2n(two_n_ext, &mut lwe_2n, &lwe_ref, lut.rotation_direction()); + + let a: &[i64] = &lwe_2n[1..]; + let b_pos: usize = ((lwe_2n[0] + two_n_ext as i64) & (two_n_ext - 1) as i64) as usize; + + let b_hi: usize = b_pos / extension_factor; + let b_lo: usize = b_pos & (extension_factor - 1); + + for (i, j) in (0..b_lo).zip(extension_factor - b_lo..extension_factor) { + module.vec_znx_rotate(b_hi as i64 + 1, &mut acc[i], 0, &lut.data[j], 0); + } + for (i, j) in (b_lo..extension_factor).zip(0..extension_factor - b_lo) { + module.vec_znx_rotate(b_hi as i64, &mut acc[i], 0, &lut.data[j], 0); + } + + let block_size: usize = brk.block_size(); + + izip!( + a.chunks_exact(block_size), + brk.data.chunks_exact(block_size) + ) + .for_each(|(ai, ski)| { + (0..extension_factor).for_each(|i| { + (0..cols).for_each(|j| { + module.vec_znx_dft_apply(1, 0, &mut acc_dft[i], j, &acc[i], j); + }); + module.vec_znx_dft_zero(&mut acc_add_dft[i]) + }); + + // TODO: first & last iterations can be optimized + izip!(ai.iter(), ski.iter()).for_each(|(aii, skii)| { + let ai_pos: usize = ((aii + two_n_ext as i64) & (two_n_ext - 1) as i64) as usize; + let ai_hi: usize = ai_pos / extension_factor; + let ai_lo: usize = ai_pos & (extension_factor - 1); + + // vmp_res = DFT(acc) * BRK[i] + (0..extension_factor).for_each(|i| { + module.vmp_apply_dft_to_dft(&mut vmp_res[i], &acc_dft[i], skii.data(), scratch_5); + }); + + // Trivial case: no rotation between polynomials, we can directly multiply with (X^{-ai} - 1) + if ai_lo == 0 { + // Sets acc_add_dft[i] = (acc[i] * sk) * X^{-ai} - (acc[i] * sk) + if ai_hi != 0 { + // DFT X^{-ai} + (0..extension_factor).for_each(|j| { + (0..cols).for_each(|i| { + module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_hi], 0, &vmp_res[j], i); + module.vec_znx_dft_add_inplace(&mut acc_add_dft[j], i, &vmp_xai, 0); + module.vec_znx_dft_sub_inplace(&mut acc_add_dft[j], i, &vmp_res[j], i); + }); + }); + } + + // Non trivial case: rotation between polynomials + // In this case we can't directly multiply with (X^{-ai} - 1) because of the + // ring homomorphism R^{N} -> prod R^{N/extension_factor}, so we split the + // computation in two steps: acc_add_dft = (acc * sk) * (-1) + (acc * sk) * X^{-ai} + } else { + // Sets acc_add_dft[0..ai_lo] += (acc[extension_factor - ai_lo..extension_factor] * sk) * X^{-ai+1} + if (ai_hi + 1) & (two_n - 1) != 0 { + for (i, j) in (0..ai_lo).zip(extension_factor - ai_lo..extension_factor) { + (0..cols).for_each(|k| { + module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_hi + 1], 0, &vmp_res[j], k); + module.vec_znx_dft_add_inplace(&mut acc_add_dft[i], k, &vmp_xai, 0); + module.vec_znx_dft_sub_inplace(&mut acc_add_dft[i], k, &vmp_res[i], k); + }); + } + } + + // Sets acc_add_dft[ai_lo..extension_factor] += (acc[0..extension_factor - ai_lo] * sk) * X^{-ai} + if ai_hi != 0 { + // Sets acc_add_dft[ai_lo..extension_factor] += (acc[0..extension_factor - ai_lo] * sk) * X^{-ai} + for (i, j) in (ai_lo..extension_factor).zip(0..extension_factor - ai_lo) { + (0..cols).for_each(|k| { + module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_hi], 0, &vmp_res[j], k); + module.vec_znx_dft_add_inplace(&mut acc_add_dft[i], k, &vmp_xai, 0); + module.vec_znx_dft_sub_inplace(&mut acc_add_dft[i], k, &vmp_res[i], k); + }); + } + } + } + }); + + { + let (mut acc_add_big, scratch7) = scratch_5.take_vec_znx_big(module, 1, brk.size()); + + (0..extension_factor).for_each(|j| { + (0..cols).for_each(|i| { + module.vec_znx_idft_apply(&mut acc_add_big, 0, &acc_add_dft[j], i, scratch7); + module.vec_znx_big_add_small_inplace(&mut acc_add_big, 0, &acc[j], i); + module.vec_znx_big_normalize(base2k, &mut acc[j], i, base2k, &acc_add_big, 0, scratch7); + }); + }); + } + }); + + (0..cols).for_each(|i| { + module.vec_znx_copy(res.data_mut(), i, &acc[0], i); + }); +} + +fn execute_block_binary<DataRes, DataIn, DataBrk, M, BE: Backend>( + module: &M, + res: &mut GLWE<DataRes>, + lwe: &LWE<DataIn>, + lut: &LookupTable, + brk: &BlindRotationKeyPrepared<DataBrk, CGGI, BE>, + scratch: &mut Scratch<BE>, +) where + DataRes: DataMut, + DataIn: DataRef, + DataBrk: DataRef, + M: VecZnxDftBytesOf + + ModuleN + + VecZnxRotate + + VecZnxDftApply<BE> + + VecZnxDftZero<BE> + + VmpApplyDftToDft<BE> + + SvpApplyDftToDft<BE> + + VecZnxDftAddInplace<BE> + + VecZnxDftSubInplace<BE> + + VecZnxIdftApply<BE> + + VecZnxBigAddSmallInplace<BE> + + VecZnxBigNormalize<BE> + + VecZnxCopy + + VecZnxBigBytesOf, + Scratch<BE>: ScratchTakeCore<BE>, +{ + let n_glwe: usize = brk.n_glwe().into(); + let mut lwe_2n: Vec<i64> = vec![0i64; (lwe.n() + 1).into()]; // TODO: from scratch space + let mut out_mut: GLWE<&mut [u8]> = res.to_mut(); + let lwe_ref: LWE<&[u8]> = lwe.to_ref(); + let two_n: usize = n_glwe << 1; + let base2k: usize = brk.base2k().into(); + let dnum: usize = brk.dnum().into(); + + let cols: usize = (out_mut.rank() + 1).into(); + + mod_switch_2n( + 2 * lut.domain_size(), + &mut lwe_2n, + &lwe_ref, + lut.rotation_direction(), + ); + + let a: &[i64] = &lwe_2n[1..]; + let b: i64 = lwe_2n[0]; + + out_mut.data_mut().zero(); + + // Initialize out to X^{b} * LUT(X) + module.vec_znx_rotate(b, out_mut.data_mut(), 0, &lut.data[0], 0); + + let block_size: usize = brk.block_size(); + + // ACC + [sum DFT(X^ai -1) * (DFT(ACC) x BRKi)] + + let (mut acc_dft, scratch_1) = scratch.take_vec_znx_dft(module, cols, dnum); + let (mut vmp_res, scratch_2) = scratch_1.take_vec_znx_dft(module, cols, brk.size()); + let (mut acc_add_dft, scratch_3) = scratch_2.take_vec_znx_dft(module, cols, brk.size()); + let (mut vmp_xai, scratch_4) = scratch_3.take_vec_znx_dft(module, 1, brk.size()); + + let x_pow_a: &Vec<SvpPPol<Vec<u8>, BE>>; + if let Some(b) = &brk.x_pow_a { + x_pow_a = b + } else { + panic!("invalid key: x_pow_a has not been initialized") + } + + izip!( + a.chunks_exact(block_size), + brk.data.chunks_exact(block_size) + ) + .for_each(|(ai, ski)| { + (0..cols).for_each(|j| { + module.vec_znx_dft_apply(1, 0, &mut acc_dft, j, out_mut.data_mut(), j); + }); + + module.vec_znx_dft_zero(&mut acc_add_dft); + + izip!(ai.iter(), ski.iter()).for_each(|(aii, skii)| { + let ai_pos: usize = ((aii + two_n as i64) & (two_n - 1) as i64) as usize; + + // vmp_res = DFT(acc) * BRK[i] + module.vmp_apply_dft_to_dft(&mut vmp_res, &acc_dft, skii.data(), scratch_4); + + // DFT(X^ai -1) * (DFT(acc) * BRK[i]) + (0..cols).for_each(|i| { + module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_pos], 0, &vmp_res, i); + module.vec_znx_dft_add_inplace(&mut acc_add_dft, i, &vmp_xai, 0); + module.vec_znx_dft_sub_inplace(&mut acc_add_dft, i, &vmp_res, i); + }); + }); + + { + let (mut acc_add_big, scratch_5) = scratch_4.take_vec_znx_big(module, 1, brk.size()); + + (0..cols).for_each(|i| { + module.vec_znx_idft_apply(&mut acc_add_big, 0, &acc_add_dft, i, scratch_5); + module.vec_znx_big_add_small_inplace(&mut acc_add_big, 0, out_mut.data_mut(), i); + module.vec_znx_big_normalize( + base2k, + out_mut.data_mut(), + i, + base2k, + &acc_add_big, + 0, + scratch_5, + ); + }); + } + }); +} + +fn execute_standard<DataRes, DataIn, DataBrk, M, BE: Backend>( + module: &M, + res: &mut GLWE<DataRes>, + lwe: &LWE<DataIn>, + lut: &LookupTable, + brk: &BlindRotationKeyPrepared<DataBrk, CGGI, BE>, + scratch: &mut Scratch<BE>, +) where + DataRes: DataMut, + DataIn: DataRef, + DataBrk: DataRef, + M: VecZnxRotate + GLWEExternalProduct<BE> + GLWEMulXpMinusOne<BE> + GLWEAdd + GLWENormalize<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + #[cfg(debug_assertions)] + { + assert_eq!( + res.n(), + brk.n(), + "res.n(): {} != brk.n(): {}", + res.n(), + brk.n() + ); + assert_eq!( + lut.domain_size(), + brk.n_glwe().as_usize(), + "lut.n(): {} != brk.n(): {}", + lut.domain_size(), + brk.n_glwe().as_usize() + ); + assert_eq!( + res.rank(), + brk.rank(), + "res.rank(): {} != brk.rank(): {}", + res.rank(), + brk.rank() + ); + assert_eq!( + lwe.n(), + brk.n_lwe(), + "lwe.n(): {} != brk.data.len(): {}", + lwe.n(), + brk.n_lwe() + ); + } + + let mut lwe_2n: Vec<i64> = vec![0i64; (lwe.n() + 1).into()]; // TODO: from scratch space + let mut out_mut: GLWE<&mut [u8]> = res.to_mut(); + let lwe_ref: LWE<&[u8]> = lwe.to_ref(); + + mod_switch_2n( + 2 * lut.domain_size(), + &mut lwe_2n, + &lwe_ref, + lut.rotation_direction(), + ); + + let a: &[i64] = &lwe_2n[1..]; + let b: i64 = lwe_2n[0]; + + out_mut.data_mut().zero(); + + // Initialize out to X^{b} * LUT(X) + module.vec_znx_rotate(b, out_mut.data_mut(), 0, &lut.data[0], 0); + + // ACC + [sum DFT(X^ai -1) * (DFT(ACC) x BRKi)] + let (mut acc_tmp, scratch_1) = scratch.take_glwe(&out_mut); + + // TODO: see if faster by skipping normalization in external product and keeping acc in big coeffs + // TODO: first iteration can be optimized to be a gglwe product + izip!(a.iter(), brk.data.iter()).for_each(|(ai, ski)| { + // acc_tmp = sk[i] * acc + acc_tmp.external_product(module, &out_mut, ski, scratch_1); + + // acc_tmp = (sk[i] * acc) * (X^{ai} - 1) + module.glwe_mul_xp_minus_one_inplace(*ai, &mut acc_tmp, scratch_1); + + // acc = acc + (sk[i] * acc) * (X^{ai} - 1) + module.glwe_add_inplace(&mut out_mut, &acc_tmp); + }); + + // We can normalize only at the end because we add normalized values in [-2^{base2k-1}, 2^{base2k-1}] + // on top of each others, thus ~ 2^{63-base2k} additions are supported before overflow. + module.glwe_normalize_inplace(&mut out_mut, scratch_1); +}
@@ -0,0 +1,79 @@
+use poulpy_hal::{ + layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxView, ZnxViewMut}, + source::Source, +}; + +use std::marker::PhantomData; + +use poulpy_core::{ + Distribution, GGSWEncryptSk, GetDistribution, ScratchTakeCore, + layouts::{GGSW, GGSWInfos, GLWEInfos, GLWESecretPreparedToRef, LWEInfos, LWESecret, LWESecretToRef}, +}; + +use crate::tfhe::blind_rotation::{ + BlindRotationKey, BlindRotationKeyEncryptSk, BlindRotationKeyFactory, BlindRotationKeyInfos, CGGI, +}; + +impl<D: DataRef> BlindRotationKeyFactory<CGGI> for BlindRotationKey<D, CGGI> { + fn blind_rotation_key_alloc<A>(infos: &A) -> BlindRotationKey<Vec<u8>, CGGI> + where + A: BlindRotationKeyInfos, + { + BlindRotationKey { + keys: (0..infos.n_lwe().as_usize()) + .map(|_| GGSW::alloc_from_infos(infos)) + .collect(), + dist: Distribution::NONE, + _phantom: PhantomData, + } + } +} + +impl<BE: Backend> BlindRotationKeyEncryptSk<CGGI, BE> for Module<BE> +where + Self: GGSWEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn blind_rotation_key_encrypt_sk_tmp_bytes<A: GGSWInfos>(&self, infos: &A) -> usize { + self.ggsw_encrypt_sk_tmp_bytes(infos) + } + + fn blind_rotation_key_encrypt_sk<D, S0, S1>( + &self, + res: &mut BlindRotationKey<D, CGGI>, + sk_glwe: &S0, + sk_lwe: &S1, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + D: DataMut, + S0: GLWESecretPreparedToRef<BE> + GLWEInfos, + S1: LWESecretToRef + LWEInfos + GetDistribution, + { + assert_eq!(res.keys.len() as u32, sk_lwe.n()); + assert!(sk_glwe.n() <= self.n() as u32); + assert_eq!(sk_glwe.rank(), res.rank()); + + match sk_lwe.dist() { + Distribution::BinaryBlock(_) | Distribution::BinaryFixed(_) | Distribution::BinaryProb(_) | Distribution::ZERO => {} + _ => { + panic!("invalid GLWESecret distribution: must be BinaryBlock, BinaryFixed or BinaryProb (or ZERO for debugging)") + } + } + + { + let sk_lwe: &LWESecret<&[u8]> = &sk_lwe.to_ref(); + + res.dist = sk_lwe.dist(); + + let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n().into(), 1); + let sk_ref: ScalarZnx<&[u8]> = sk_lwe.data().to_ref(); + + for (i, ggsw) in res.keys.iter_mut().enumerate() { + pt.at_mut(0, 0)[0] = sk_ref.at(0, 0)[i]; + ggsw.encrypt_sk(self, &pt, sk_glwe, source_xa, source_xe, scratch); + } + } + } +}
@@ -0,0 +1,84 @@
+use std::marker::PhantomData; + +use poulpy_core::{ + Distribution, GGSWCompressedEncryptSk, GetDistribution, ScratchTakeCore, + layouts::{GGSWCompressed, GGSWInfos, GLWEInfos, GLWESecretPreparedToRef, LWEInfos, LWESecret, LWESecretToRef}, +}; +use poulpy_hal::{ + layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxView, ZnxViewMut}, + source::Source, +}; + +use crate::tfhe::blind_rotation::{ + BlindRotationKeyCompressed, BlindRotationKeyCompressedEncryptSk, BlindRotationKeyCompressedFactory, BlindRotationKeyInfos, + CGGI, +}; + +impl<D: DataRef> BlindRotationKeyCompressedFactory<CGGI> for BlindRotationKeyCompressed<D, CGGI> { + fn blind_rotation_key_compressed_alloc<A>(infos: &A) -> BlindRotationKeyCompressed<Vec<u8>, CGGI> + where + A: BlindRotationKeyInfos, + { + let mut data: Vec<GGSWCompressed<Vec<u8>>> = Vec::with_capacity(infos.n_lwe().into()); + (0..infos.n_lwe().as_usize()).for_each(|_| data.push(GGSWCompressed::alloc_from_infos(infos))); + BlindRotationKeyCompressed { + keys: data, + dist: Distribution::NONE, + _phantom: PhantomData, + } + } +} + +impl<BE: Backend> BlindRotationKeyCompressedEncryptSk<BE, CGGI> for Module<BE> +where + Self: GGSWCompressedEncryptSk<BE>, + Scratch<BE>: ScratchTakeCore<BE>, +{ + fn blind_rotation_key_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGSWInfos, + { + self.ggsw_compressed_encrypt_sk_tmp_bytes(infos) + } + + fn blind_rotation_key_compressed_encrypt_sk<D, S0, S1>( + &self, + res: &mut BlindRotationKeyCompressed<D, CGGI>, + sk_glwe: &S0, + sk_lwe: &S1, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + D: DataMut, + S0: GLWESecretPreparedToRef<BE> + GLWEInfos, + S1: LWESecretToRef + LWEInfos + GetDistribution, + { + assert_eq!(res.keys.len() as u32, sk_lwe.n()); + assert!(sk_glwe.n() <= self.n() as u32); + assert_eq!(sk_glwe.rank(), res.rank()); + + match sk_lwe.dist() { + Distribution::BinaryBlock(_) | Distribution::BinaryFixed(_) | Distribution::BinaryProb(_) | Distribution::ZERO => {} + _ => { + panic!("invalid GLWESecret distribution: must be BinaryBlock, BinaryFixed or BinaryProb (or ZERO for debugging)") + } + } + + { + let sk_lwe: &LWESecret<&[u8]> = &sk_lwe.to_ref(); + + let mut source_xa: Source = Source::new(seed_xa); + + res.dist = sk_lwe.dist(); + + let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n().into(), 1); + let sk_ref: ScalarZnx<&[u8]> = sk_lwe.data().to_ref(); + + for (i, ggsw) in res.keys.iter_mut().enumerate() { + pt.at_mut(0, 0)[0] = sk_ref.at(0, 0)[i]; + ggsw.encrypt_sk(self, &pt, sk_glwe, source_xa.new_seed(), source_xe, scratch); + } + } + } +}
@@ -0,0 +1,76 @@
+use poulpy_hal::{ + api::{SvpPPolAlloc, SvpPrepare}, + layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, Scratch, SvpPPol}, +}; + +use std::marker::PhantomData; + +use poulpy_core::{ + Distribution, + layouts::{GGSWPreparedFactory, LWEInfos, prepared::GGSWPrepared}, +}; + +use crate::tfhe::blind_rotation::{ + BlindRotationKey, BlindRotationKeyInfos, BlindRotationKeyPrepared, BlindRotationKeyPreparedFactory, CGGI, + utils::set_xai_plus_y, +}; + +impl<BE: Backend> BlindRotationKeyPreparedFactory<CGGI, BE> for Module<BE> +where + Self: GGSWPreparedFactory<BE> + SvpPPolAlloc<BE> + SvpPrepare<BE>, +{ + fn blind_rotation_key_prepared_alloc<A>(&self, infos: &A) -> BlindRotationKeyPrepared<Vec<u8>, CGGI, BE> + where + A: BlindRotationKeyInfos, + { + BlindRotationKeyPrepared { + data: (0..infos.n_lwe().as_usize()) + .map(|_| GGSWPrepared::alloc_from_infos(self, infos)) + .collect(), + dist: Distribution::NONE, + x_pow_a: None, + _phantom: PhantomData, + } + } + + fn blind_rotation_key_prepare_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: BlindRotationKeyInfos, + { + self.ggsw_prepare_tmp_bytes(infos) + } + + fn prepare_blind_rotation_key<DM, DR>( + &self, + res: &mut BlindRotationKeyPrepared<DM, CGGI, BE>, + other: &BlindRotationKey<DR, CGGI>, + scratch: &mut Scratch<BE>, + ) where + DM: DataMut, + DR: DataRef, + { + #[cfg(debug_assertions)] + { + assert_eq!(res.data.len(), other.keys.len()); + } + + let n: usize = other.n().as_usize(); + + for (a, b) in res.data.iter_mut().zip(other.keys.iter()) { + a.prepare(self, b, scratch); + } + + res.dist = other.dist; + + if let Distribution::BinaryBlock(_) = other.dist { + let mut x_pow_a: Vec<SvpPPol<Vec<u8>, BE>> = Vec::with_capacity(n << 1); + let mut buf: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1); + (0..n << 1).for_each(|i| { + let mut res: SvpPPol<Vec<u8>, BE> = self.svp_ppol_alloc(1); + set_xai_plus_y(self, i, 0, &mut res, &mut buf); + x_pow_a.push(res); + }); + res.x_pow_a = Some(x_pow_a); + } + } +}
@@ -0,0 +1,10 @@
+mod algorithm; +mod key; +mod key_compressed; +mod key_prepared; + +use crate::tfhe::blind_rotation::BlindRotationAlgo; + +#[derive(Clone)] +pub struct CGGI {} +impl BlindRotationAlgo for CGGI {}
@@ -0,0 +1,116 @@
+mod cggi; + +pub use cggi::*; + +use itertools::izip; +use poulpy_core::{ + ScratchTakeCore, + layouts::{GGSWInfos, GLWE, GLWEInfos, LWE, LWEInfos}, +}; +use poulpy_hal::layouts::{Backend, DataMut, DataRef, Scratch, ZnxView}; + +use crate::tfhe::blind_rotation::{BlindRotationKeyInfos, BlindRotationKeyPrepared, LookUpTableRotationDirection, LookupTable}; + +pub trait BlindRotationAlgo {} + +pub trait BlindRotationExecute<BRA: BlindRotationAlgo, BE: Backend> { + fn blind_rotation_execute_tmp_bytes<G, B>( + &self, + block_size: usize, + extension_factor: usize, + glwe_infos: &G, + brk_infos: &B, + ) -> usize + where + G: GLWEInfos, + B: GGSWInfos; + + fn blind_rotation_execute<DR, DL, DB>( + &self, + res: &mut GLWE<DR>, + lwe: &LWE<DL>, + lut: &LookupTable, + brk: &BlindRotationKeyPrepared<DB, BRA, BE>, + scratch: &mut Scratch<BE>, + ) where + DR: DataMut, + DL: DataRef, + DB: DataRef; +} + +impl<D: DataRef, BRA: BlindRotationAlgo, BE: Backend> BlindRotationKeyPrepared<D, BRA, BE> +where + Scratch<BE>: ScratchTakeCore<BE>, +{ + pub fn execute<DR: DataMut, DI: DataRef, M>( + &self, + module: &M, + res: &mut GLWE<DR>, + lwe: &LWE<DI>, + lut: &LookupTable, + scratch: &mut Scratch<BE>, + ) where + M: BlindRotationExecute<BRA, BE>, + { + module.blind_rotation_execute(res, lwe, lut, self, scratch); + } +} + +impl<BE: Backend, BRA: BlindRotationAlgo> BlindRotationKeyPrepared<Vec<u8>, BRA, BE> { + pub fn execute_tmp_bytes<A, B, M>( + module: &M, + block_size: usize, + extension_factor: usize, + glwe_infos: &A, + brk_infos: &B, + ) -> usize + where + A: GLWEInfos, + B: BlindRotationKeyInfos, + M: BlindRotationExecute<BRA, BE>, + { + module.blind_rotation_execute_tmp_bytes(block_size, extension_factor, glwe_infos, brk_infos) + } +} + +pub fn mod_switch_2n(n: usize, res: &mut [i64], lwe: &LWE<&[u8]>, rot_dir: LookUpTableRotationDirection) { + let base2k: usize = lwe.base2k().into(); + + let log2n: usize = usize::BITS as usize - (n - 1).leading_zeros() as usize + 1; + + res.copy_from_slice(lwe.data().at(0, 0)); + + match rot_dir { + LookUpTableRotationDirection::Left => { + res.iter_mut().for_each(|x| *x = -*x); + } + LookUpTableRotationDirection::Right => {} + } + + if base2k > log2n { + let diff: usize = base2k - (log2n - 1); // additional -1 because we map to [-N/2, N/2) instead of [0, N) + res.iter_mut().for_each(|x| { + *x = div_round_by_pow2(x, diff); + }) + } else { + let rem: usize = base2k - (log2n % base2k); + let size: usize = log2n.div_ceil(base2k); + (1..size).for_each(|i| { + if i == size - 1 && rem != base2k { + let k_rem: usize = base2k - rem; + izip!(lwe.data().at(0, i).iter(), res.iter_mut()).for_each(|(x, y)| { + *y = (*y << k_rem) + (x >> rem); + }); + } else { + izip!(lwe.data().at(0, i).iter(), res.iter_mut()).for_each(|(x, y)| { + *y = (*y << base2k) + x; + }); + } + }) + } +} + +#[inline(always)] +fn div_round_by_pow2(x: &i64, k: usize) -> i64 { + (x + (1 << (k - 1))) >> k +}
@@ -1,562 +0,0 @@
-use itertools::izip; -use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDft, SvpPPolAllocBytes, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, TakeVecZnxDftSlice, - TakeVecZnxSlice, VecZnxAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, - VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAdd, VecZnxDftAddInplace, VecZnxDftAllocBytes, VecZnxDftApply, - VecZnxDftSubInplace, VecZnxDftZero, VecZnxIdftApply, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpBytes, - VecZnxMulXpMinusOneInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, - VecZnxSubInplace, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, SvpPPol, VecZnx, ZnxView, ZnxZero}, -}; - -use poulpy_core::{ - Distribution, GLWEOperations, TakeGLWECt, - layouts::{GGSWInfos, GLWECiphertext, GLWECiphertextToMut, GLWEInfos, LWECiphertext, LWECiphertextToRef, LWEInfos}, -}; - -use crate::tfhe::blind_rotation::{ - BlincRotationExecute, BlindRotationKeyInfos, BlindRotationKeyPrepared, CGGI, LookUpTable, LookUpTableRotationDirection, -}; - -#[allow(clippy::too_many_arguments)] -pub fn cggi_blind_rotate_scratch_space<B: Backend, OUT, GGSW>( - module: &Module<B>, - block_size: usize, - extension_factor: usize, - glwe_infos: &OUT, - brk_infos: &GGSW, -) -> usize -where - OUT: GLWEInfos, - GGSW: GGSWInfos, - Module<B>: VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxBigAllocBytes - + VecZnxIdftApplyTmpBytes - + VecZnxBigNormalizeTmpBytes, -{ - let brk_size: usize = brk_infos.size(); - - if block_size > 1 { - let cols: usize = (brk_infos.rank() + 1).into(); - let dnum: usize = brk_infos.dnum().into(); - let acc_dft: usize = module.vec_znx_dft_alloc_bytes(cols, dnum) * extension_factor; - let acc_big: usize = module.vec_znx_big_alloc_bytes(1, brk_size); - let vmp_res: usize = module.vec_znx_dft_alloc_bytes(cols, brk_size) * extension_factor; - let vmp_xai: usize = module.vec_znx_dft_alloc_bytes(1, brk_size); - let acc_dft_add: usize = vmp_res; - let vmp: usize = module.vmp_apply_dft_to_dft_tmp_bytes(brk_size, dnum, dnum, 2, 2, brk_size); // GGSW product: (1 x 2) x (2 x 2) - let acc: usize = if extension_factor > 1 { - VecZnx::alloc_bytes(module.n(), cols, glwe_infos.size()) * extension_factor - } else { - 0 - }; - - acc + acc_dft - + acc_dft_add - + vmp_res - + vmp_xai - + (vmp | (acc_big + (module.vec_znx_big_normalize_tmp_bytes() | module.vec_znx_idft_apply_tmp_bytes()))) - } else { - GLWECiphertext::alloc_bytes(glwe_infos) - + GLWECiphertext::external_product_inplace_scratch_space(module, glwe_infos, brk_infos) - } -} - -impl<D: DataRef, B: Backend> BlincRotationExecute<B> for BlindRotationKeyPrepared<D, CGGI, B> -where - Module<B>: VecZnxBigAllocBytes - + VecZnxDftAllocBytes - + SvpPPolAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpBytes - + VecZnxIdftApply<B> - + VecZnxDftAdd<B> - + VecZnxDftAddInplace<B> - + VecZnxDftApply<B> - + VecZnxDftZero<B> - + SvpApplyDftToDft<B> - + VecZnxDftSubInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxRotate - + VecZnxAddInplace - + VecZnxSubInplace - + VecZnxNormalize<B> - + VecZnxNormalizeInplace<B> - + VecZnxCopy - + VecZnxMulXpMinusOneInplace<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: TakeVecZnxDftSlice<B> + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnxSlice + TakeVecZnx + ScratchAvailable, -{ - fn execute<DR: DataMut, DI: DataRef>( - &self, - module: &Module<B>, - res: &mut GLWECiphertext<DR>, - lwe: &LWECiphertext<DI>, - lut: &LookUpTable, - scratch: &mut Scratch<B>, - ) { - match self.dist { - Distribution::BinaryBlock(_) | Distribution::BinaryFixed(_) | Distribution::BinaryProb(_) | Distribution::ZERO => { - if lut.extension_factor() > 1 { - execute_block_binary_extended(module, res, lwe, lut, self, scratch) - } else if self.block_size() > 1 { - execute_block_binary(module, res, lwe, lut, self, scratch); - } else { - execute_standard(module, res, lwe, lut, self, scratch); - } - } - _ => panic!("invalid CGGI distribution"), - } - } -} - -fn execute_block_binary_extended<DataRes, DataIn, DataBrk, B: Backend>( - module: &Module<B>, - res: &mut GLWECiphertext<DataRes>, - lwe: &LWECiphertext<DataIn>, - lut: &LookUpTable, - brk: &BlindRotationKeyPrepared<DataBrk, CGGI, B>, - scratch: &mut Scratch<B>, -) where - DataRes: DataMut, - DataIn: DataRef, - DataBrk: DataRef, - Module<B>: VecZnxBigAllocBytes - + VecZnxDftAllocBytes - + SvpPPolAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpBytes - + VecZnxIdftApply<B> - + VecZnxDftAdd<B> - + VecZnxDftAddInplace<B> - + VecZnxDftApply<B> - + VecZnxDftZero<B> - + SvpApplyDftToDft<B> - + VecZnxDftSubInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxRotate - + VecZnxAddInplace - + VecZnxSubInplace - + VecZnxNormalize<B> - + VecZnxNormalizeInplace<B> - + VecZnxCopy - + VecZnxMulXpMinusOneInplace<B> - + VecZnxBigNormalize<B> - + VmpApplyDftToDft<B>, - Scratch<B>: TakeVecZnxDftSlice<B> + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnxSlice + ScratchAvailable + TakeVecZnx, -{ - let n_glwe: usize = brk.n_glwe().into(); - let extension_factor: usize = lut.extension_factor(); - let base2k: usize = res.base2k().into(); - let dnum: usize = brk.dnum().into(); - let cols: usize = (res.rank() + 1).into(); - - let (mut acc, scratch_1) = scratch.take_vec_znx_slice(extension_factor, n_glwe, cols, res.size()); - let (mut acc_dft, scratch_2) = scratch_1.take_vec_znx_dft_slice(extension_factor, n_glwe, cols, dnum); - let (mut vmp_res, scratch_3) = scratch_2.take_vec_znx_dft_slice(extension_factor, n_glwe, cols, brk.size()); - let (mut acc_add_dft, scratch_4) = scratch_3.take_vec_znx_dft_slice(extension_factor, n_glwe, cols, brk.size()); - let (mut vmp_xai, scratch_5) = scratch_4.take_vec_znx_dft(n_glwe, 1, brk.size()); - - (0..extension_factor).for_each(|i| { - acc[i].zero(); - }); - - let x_pow_a: &Vec<SvpPPol<Vec<u8>, B>>; - if let Some(b) = &brk.x_pow_a { - x_pow_a = b - } else { - panic!("invalid key: x_pow_a has not been initialized") - } - - let mut lwe_2n: Vec<i64> = vec![0i64; (lwe.n() + 1).as_usize()]; // TODO: from scratch space - let lwe_ref: LWECiphertext<&[u8]> = lwe.to_ref(); - - let two_n: usize = 2 * n_glwe; - let two_n_ext: usize = 2 * lut.domain_size(); - - mod_switch_2n(two_n_ext, &mut lwe_2n, &lwe_ref, lut.rotation_direction()); - - let a: &[i64] = &lwe_2n[1..]; - let b_pos: usize = ((lwe_2n[0] + two_n_ext as i64) & (two_n_ext - 1) as i64) as usize; - - let b_hi: usize = b_pos / extension_factor; - let b_lo: usize = b_pos & (extension_factor - 1); - - for (i, j) in (0..b_lo).zip(extension_factor - b_lo..extension_factor) { - module.vec_znx_rotate(b_hi as i64 + 1, &mut acc[i], 0, &lut.data[j], 0); - } - for (i, j) in (b_lo..extension_factor).zip(0..extension_factor - b_lo) { - module.vec_znx_rotate(b_hi as i64, &mut acc[i], 0, &lut.data[j], 0); - } - - let block_size: usize = brk.block_size(); - - izip!( - a.chunks_exact(block_size), - brk.data.chunks_exact(block_size) - ) - .for_each(|(ai, ski)| { - (0..extension_factor).for_each(|i| { - (0..cols).for_each(|j| { - module.vec_znx_dft_apply(1, 0, &mut acc_dft[i], j, &acc[i], j); - }); - module.vec_znx_dft_zero(&mut acc_add_dft[i]) - }); - - // TODO: first & last iterations can be optimized - izip!(ai.iter(), ski.iter()).for_each(|(aii, skii)| { - let ai_pos: usize = ((aii + two_n_ext as i64) & (two_n_ext - 1) as i64) as usize; - let ai_hi: usize = ai_pos / extension_factor; - let ai_lo: usize = ai_pos & (extension_factor - 1); - - // vmp_res = DFT(acc) * BRK[i] - (0..extension_factor).for_each(|i| { - module.vmp_apply_dft_to_dft(&mut vmp_res[i], &acc_dft[i], skii.data(), scratch_5); - }); - - // Trivial case: no rotation between polynomials, we can directly multiply with (X^{-ai} - 1) - if ai_lo == 0 { - // Sets acc_add_dft[i] = (acc[i] * sk) * X^{-ai} - (acc[i] * sk) - if ai_hi != 0 { - // DFT X^{-ai} - (0..extension_factor).for_each(|j| { - (0..cols).for_each(|i| { - module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_hi], 0, &vmp_res[j], i); - module.vec_znx_dft_add_inplace(&mut acc_add_dft[j], i, &vmp_xai, 0); - module.vec_znx_dft_sub_inplace(&mut acc_add_dft[j], i, &vmp_res[j], i); - }); - }); - } - - // Non trivial case: rotation between polynomials - // In this case we can't directly multiply with (X^{-ai} - 1) because of the - // ring homomorphism R^{N} -> prod R^{N/extension_factor}, so we split the - // computation in two steps: acc_add_dft = (acc * sk) * (-1) + (acc * sk) * X^{-ai} - } else { - // Sets acc_add_dft[0..ai_lo] += (acc[extension_factor - ai_lo..extension_factor] * sk) * X^{-ai+1} - if (ai_hi + 1) & (two_n - 1) != 0 { - for (i, j) in (0..ai_lo).zip(extension_factor - ai_lo..extension_factor) { - (0..cols).for_each(|k| { - module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_hi + 1], 0, &vmp_res[j], k); - module.vec_znx_dft_add_inplace(&mut acc_add_dft[i], k, &vmp_xai, 0); - module.vec_znx_dft_sub_inplace(&mut acc_add_dft[i], k, &vmp_res[i], k); - }); - } - } - - // Sets acc_add_dft[ai_lo..extension_factor] += (acc[0..extension_factor - ai_lo] * sk) * X^{-ai} - if ai_hi != 0 { - // Sets acc_add_dft[ai_lo..extension_factor] += (acc[0..extension_factor - ai_lo] * sk) * X^{-ai} - for (i, j) in (ai_lo..extension_factor).zip(0..extension_factor - ai_lo) { - (0..cols).for_each(|k| { - module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_hi], 0, &vmp_res[j], k); - module.vec_znx_dft_add_inplace(&mut acc_add_dft[i], k, &vmp_xai, 0); - module.vec_znx_dft_sub_inplace(&mut acc_add_dft[i], k, &vmp_res[i], k); - }); - } - } - } - }); - - { - let (mut acc_add_big, scratch7) = scratch_5.take_vec_znx_big(n_glwe, 1, brk.size()); - - (0..extension_factor).for_each(|j| { - (0..cols).for_each(|i| { - module.vec_znx_idft_apply(&mut acc_add_big, 0, &acc_add_dft[j], i, scratch7); - module.vec_znx_big_add_small_inplace(&mut acc_add_big, 0, &acc[j], i); - module.vec_znx_big_normalize(base2k, &mut acc[j], i, base2k, &acc_add_big, 0, scratch7); - }); - }); - } - }); - - (0..cols).for_each(|i| { - module.vec_znx_copy(res.data_mut(), i, &acc[0], i); - }); -} - -fn execute_block_binary<DataRes, DataIn, DataBrk, B: Backend>( - module: &Module<B>, - res: &mut GLWECiphertext<DataRes>, - lwe: &LWECiphertext<DataIn>, - lut: &LookUpTable, - brk: &BlindRotationKeyPrepared<DataBrk, CGGI, B>, - scratch: &mut Scratch<B>, -) where - DataRes: DataMut, - DataIn: DataRef, - DataBrk: DataRef, - Module<B>: VecZnxBigAllocBytes - + VecZnxDftAllocBytes - + SvpPPolAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpBytes - + VecZnxIdftApply<B> - + VecZnxDftAdd<B> - + VecZnxDftAddInplace<B> - + VecZnxDftApply<B> - + VecZnxDftZero<B> - + SvpApplyDftToDft<B> - + VecZnxDftSubInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxRotate - + VecZnxAddInplace - + VecZnxSubInplace - + VecZnxNormalize<B> - + VecZnxNormalizeInplace<B> - + VecZnxCopy - + VecZnxMulXpMinusOneInplace<B> - + VmpApplyDftToDft<B> - + VecZnxBigNormalize<B>, - Scratch<B>: TakeVecZnxDftSlice<B> + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnxSlice + ScratchAvailable + TakeVecZnx, -{ - let n_glwe: usize = brk.n_glwe().into(); - let mut lwe_2n: Vec<i64> = vec![0i64; (lwe.n() + 1).into()]; // TODO: from scratch space - let mut out_mut: GLWECiphertext<&mut [u8]> = res.to_mut(); - let lwe_ref: LWECiphertext<&[u8]> = lwe.to_ref(); - let two_n: usize = n_glwe << 1; - let base2k: usize = brk.base2k().into(); - let dnum: usize = brk.dnum().into(); - - let cols: usize = (out_mut.rank() + 1).into(); - - mod_switch_2n( - 2 * lut.domain_size(), - &mut lwe_2n, - &lwe_ref, - lut.rotation_direction(), - ); - - let a: &[i64] = &lwe_2n[1..]; - let b: i64 = lwe_2n[0]; - - out_mut.data_mut().zero(); - - // Initialize out to X^{b} * LUT(X) - module.vec_znx_rotate(b, out_mut.data_mut(), 0, &lut.data[0], 0); - - let block_size: usize = brk.block_size(); - - // ACC + [sum DFT(X^ai -1) * (DFT(ACC) x BRKi)] - - let (mut acc_dft, scratch_1) = scratch.take_vec_znx_dft(n_glwe, cols, dnum); - let (mut vmp_res, scratch_2) = scratch_1.take_vec_znx_dft(n_glwe, cols, brk.size()); - let (mut acc_add_dft, scratch_3) = scratch_2.take_vec_znx_dft(n_glwe, cols, brk.size()); - let (mut vmp_xai, scratch_4) = scratch_3.take_vec_znx_dft(n_glwe, 1, brk.size()); - - let x_pow_a: &Vec<SvpPPol<Vec<u8>, B>>; - if let Some(b) = &brk.x_pow_a { - x_pow_a = b - } else { - panic!("invalid key: x_pow_a has not been initialized") - } - - izip!( - a.chunks_exact(block_size), - brk.data.chunks_exact(block_size) - ) - .for_each(|(ai, ski)| { - (0..cols).for_each(|j| { - module.vec_znx_dft_apply(1, 0, &mut acc_dft, j, out_mut.data_mut(), j); - }); - - module.vec_znx_dft_zero(&mut acc_add_dft); - - izip!(ai.iter(), ski.iter()).for_each(|(aii, skii)| { - let ai_pos: usize = ((aii + two_n as i64) & (two_n - 1) as i64) as usize; - - // vmp_res = DFT(acc) * BRK[i] - module.vmp_apply_dft_to_dft(&mut vmp_res, &acc_dft, skii.data(), scratch_4); - - // DFT(X^ai -1) * (DFT(acc) * BRK[i]) - (0..cols).for_each(|i| { - module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_pos], 0, &vmp_res, i); - module.vec_znx_dft_add_inplace(&mut acc_add_dft, i, &vmp_xai, 0); - module.vec_znx_dft_sub_inplace(&mut acc_add_dft, i, &vmp_res, i); - }); - }); - - { - let (mut acc_add_big, scratch_5) = scratch_4.take_vec_znx_big(n_glwe, 1, brk.size()); - - (0..cols).for_each(|i| { - module.vec_znx_idft_apply(&mut acc_add_big, 0, &acc_add_dft, i, scratch_5); - module.vec_znx_big_add_small_inplace(&mut acc_add_big, 0, out_mut.data_mut(), i); - module.vec_znx_big_normalize( - base2k, - out_mut.data_mut(), - i, - base2k, - &acc_add_big, - 0, - scratch_5, - ); - }); - } - }); -} - -fn execute_standard<DataRes, DataIn, DataBrk, B: Backend>( - module: &Module<B>, - res: &mut GLWECiphertext<DataRes>, - lwe: &LWECiphertext<DataIn>, - lut: &LookUpTable, - brk: &BlindRotationKeyPrepared<DataBrk, CGGI, B>, - scratch: &mut Scratch<B>, -) where - DataRes: DataMut, - DataIn: DataRef, - DataBrk: DataRef, - Module<B>: VecZnxBigAllocBytes - + VecZnxDftAllocBytes - + SvpPPolAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpBytes - + VecZnxIdftApply<B> - + VecZnxDftAdd<B> - + VecZnxDftAddInplace<B> - + VecZnxDftApply<B> - + VecZnxDftZero<B> - + SvpApplyDftToDft<B> - + VecZnxDftSubInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxRotate - + VecZnxAddInplace - + VecZnxSubInplace - + VecZnxNormalize<B> - + VecZnxNormalizeInplace<B> - + VecZnxCopy - + VecZnxMulXpMinusOneInplace<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: TakeVecZnxDftSlice<B> + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnxSlice + ScratchAvailable + TakeVecZnx, -{ - #[cfg(debug_assertions)] - { - assert_eq!( - res.n(), - brk.n(), - "res.n(): {} != brk.n(): {}", - res.n(), - brk.n() - ); - assert_eq!( - lut.domain_size(), - brk.n_glwe().as_usize(), - "lut.n(): {} != brk.n(): {}", - lut.domain_size(), - brk.n_glwe().as_usize() - ); - assert_eq!( - res.rank(), - brk.rank(), - "res.rank(): {} != brk.rank(): {}", - res.rank(), - brk.rank() - ); - assert_eq!( - lwe.n(), - brk.n_lwe(), - "lwe.n(): {} != brk.data.len(): {}", - lwe.n(), - brk.n_lwe() - ); - } - - let mut lwe_2n: Vec<i64> = vec![0i64; (lwe.n() + 1).into()]; // TODO: from scratch space - let mut out_mut: GLWECiphertext<&mut [u8]> = res.to_mut(); - let lwe_ref: LWECiphertext<&[u8]> = lwe.to_ref(); - - mod_switch_2n( - 2 * lut.domain_size(), - &mut lwe_2n, - &lwe_ref, - lut.rotation_direction(), - ); - - let a: &[i64] = &lwe_2n[1..]; - let b: i64 = lwe_2n[0]; - - out_mut.data_mut().zero(); - - // Initialize out to X^{b} * LUT(X) - module.vec_znx_rotate(b, out_mut.data_mut(), 0, &lut.data[0], 0); - - // ACC + [sum DFT(X^ai -1) * (DFT(ACC) x BRKi)] - let (mut acc_tmp, scratch_1) = scratch.take_glwe_ct(&out_mut); - - // TODO: see if faster by skipping normalization in external product and keeping acc in big coeffs - // TODO: first iteration can be optimized to be a gglwe product - izip!(a.iter(), brk.data.iter()).for_each(|(ai, ski)| { - // acc_tmp = sk[i] * acc - acc_tmp.external_product(module, &out_mut, ski, scratch_1); - - // acc_tmp = (sk[i] * acc) * (X^{ai} - 1) - acc_tmp.mul_xp_minus_one_inplace(module, *ai, scratch_1); - - // acc = acc + (sk[i] * acc) * (X^{ai} - 1) - out_mut.add_inplace(module, &acc_tmp); - }); - - // We can normalize only at the end because we add normalized values in [-2^{base2k-1}, 2^{base2k-1}] - // on top of each others, thus ~ 2^{63-base2k} additions are supported before overflow. - out_mut.normalize_inplace(module, scratch_1); -} - -pub fn mod_switch_2n(n: usize, res: &mut [i64], lwe: &LWECiphertext<&[u8]>, rot_dir: LookUpTableRotationDirection) { - let base2k: usize = lwe.base2k().into(); - - let log2n: usize = usize::BITS as usize - (n - 1).leading_zeros() as usize + 1; - - res.copy_from_slice(lwe.data().at(0, 0)); - - match rot_dir { - LookUpTableRotationDirection::Left => { - res.iter_mut().for_each(|x| *x = -*x); - } - LookUpTableRotationDirection::Right => {} - } - - if base2k > log2n { - let diff: usize = base2k - (log2n - 1); // additional -1 because we map to [-N/2, N/2) instead of [0, N) - res.iter_mut().for_each(|x| { - *x = div_round_by_pow2(x, diff); - }) - } else { - let rem: usize = base2k - (log2n % base2k); - let size: usize = log2n.div_ceil(base2k); - (1..size).for_each(|i| { - if i == size - 1 && rem != base2k { - let k_rem: usize = base2k - rem; - izip!(lwe.data().at(0, i).iter(), res.iter_mut()).for_each(|(x, y)| { - *y = (*y << k_rem) + (x >> rem); - }); - } else { - izip!(lwe.data().at(0, i).iter(), res.iter_mut()).for_each(|(x, y)| { - *y = (*y << base2k) + x; - }); - } - }) - } -} - -#[inline(always)] -fn div_round_by_pow2(x: &i64, k: usize) -> i64 { - (x + (1 << (k - 1))) >> k -}
@@ -1,224 +0,0 @@
-use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDftInplace, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, - VecZnxAddScalarInplace, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, - VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxView, ZnxViewMut}, - source::Source, -}; - -use std::marker::PhantomData; - -use poulpy_core::{ - Distribution, - layouts::{ - GGSWCiphertext, GGSWInfos, LWESecret, - compressed::GGSWCiphertextCompressed, - prepared::{GGSWCiphertextPrepared, GLWESecretPrepared}, - }, -}; - -use crate::tfhe::blind_rotation::{ - BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyCompressed, BlindRotationKeyEncryptSk, BlindRotationKeyInfos, - BlindRotationKeyPrepared, BlindRotationKeyPreparedAlloc, CGGI, -}; - -impl BlindRotationKeyAlloc for BlindRotationKey<Vec<u8>, CGGI> { - fn alloc<A>(infos: &A) -> Self - where - A: BlindRotationKeyInfos, - { - let mut data: Vec<GGSWCiphertext<Vec<u8>>> = Vec::with_capacity(infos.n_lwe().into()); - for _ in 0..infos.n_lwe().as_usize() { - data.push(GGSWCiphertext::alloc(infos)); - } - - Self { - keys: data, - dist: Distribution::NONE, - _phantom: PhantomData, - } - } -} - -impl BlindRotationKey<Vec<u8>, CGGI> { - pub fn generate_from_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGSWInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes, - { - GGSWCiphertext::encrypt_sk_scratch_space(module, infos) - } -} - -impl<D: DataMut, B: Backend> BlindRotationKeyEncryptSk<B> for BlindRotationKey<D, CGGI> -where - Module<B>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, -{ - fn encrypt_sk<DataSkGLWE, DataSkLWE>( - &mut self, - module: &Module<B>, - sk_glwe: &GLWESecretPrepared<DataSkGLWE, B>, - sk_lwe: &LWESecret<DataSkLWE>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - DataSkGLWE: DataRef, - DataSkLWE: DataRef, - { - #[cfg(debug_assertions)] - { - use poulpy_core::layouts::{GLWEInfos, LWEInfos}; - - assert_eq!(self.keys.len() as u32, sk_lwe.n()); - assert!(sk_glwe.n() <= module.n() as u32); - assert_eq!(sk_glwe.rank(), self.rank()); - match sk_lwe.dist() { - Distribution::BinaryBlock(_) - | Distribution::BinaryFixed(_) - | Distribution::BinaryProb(_) - | Distribution::ZERO => {} - _ => panic!( - "invalid GLWESecret distribution: must be BinaryBlock, BinaryFixed or BinaryProb (or ZERO for debugging)" - ), - } - } - - self.dist = sk_lwe.dist(); - - let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n().into(), 1); - let sk_ref: ScalarZnx<&[u8]> = sk_lwe.data().to_ref(); - - self.keys.iter_mut().enumerate().for_each(|(i, ggsw)| { - pt.at_mut(0, 0)[0] = sk_ref.at(0, 0)[i]; - ggsw.encrypt_sk(module, &pt, sk_glwe, source_xa, source_xe, scratch); - }); - } -} - -impl<B: Backend> BlindRotationKeyPreparedAlloc<B> for BlindRotationKeyPrepared<Vec<u8>, CGGI, B> -where - Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>, -{ - fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: BlindRotationKeyInfos, - { - let mut data: Vec<GGSWCiphertextPrepared<Vec<u8>, B>> = Vec::with_capacity(infos.n_lwe().into()); - (0..infos.n_lwe().as_usize()).for_each(|_| data.push(GGSWCiphertextPrepared::alloc(module, infos))); - Self { - data, - dist: Distribution::NONE, - x_pow_a: None, - _phantom: PhantomData, - } - } -} - -impl BlindRotationKeyCompressed<Vec<u8>, CGGI> { - pub fn alloc<A>(infos: &A) -> Self - where - A: BlindRotationKeyInfos, - { - let mut data: Vec<GGSWCiphertextCompressed<Vec<u8>>> = Vec::with_capacity(infos.n_lwe().into()); - (0..infos.n_lwe().as_usize()).for_each(|_| data.push(GGSWCiphertextCompressed::alloc(infos))); - Self { - keys: data, - dist: Distribution::NONE, - _phantom: PhantomData, - } - } - - pub fn generate_from_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize - where - A: GGSWInfos, - Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes, - { - GGSWCiphertextCompressed::encrypt_sk_scratch_space(module, infos) - } -} - -impl<D: DataMut> BlindRotationKeyCompressed<D, CGGI> { - #[allow(clippy::too_many_arguments)] - pub fn encrypt_sk<DataSkGLWE, DataSkLWE, B: Backend>( - &mut self, - module: &Module<B>, - sk_glwe: &GLWESecretPrepared<DataSkGLWE, B>, - sk_lwe: &LWESecret<DataSkLWE>, - seed_xa: [u8; 32], - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - DataSkGLWE: DataRef, - DataSkLWE: DataRef, - Module<B>: VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, - { - #[cfg(debug_assertions)] - { - use poulpy_core::layouts::{GLWEInfos, LWEInfos}; - - assert_eq!(self.n_lwe(), sk_lwe.n()); - assert!(sk_glwe.n() <= module.n() as u32); - assert_eq!(sk_glwe.rank(), self.rank()); - match sk_lwe.dist() { - Distribution::BinaryBlock(_) - | Distribution::BinaryFixed(_) - | Distribution::BinaryProb(_) - | Distribution::ZERO => {} - _ => panic!( - "invalid GLWESecret distribution: must be BinaryBlock, BinaryFixed or BinaryProb (or ZERO for debugging)" - ), - } - } - - self.dist = sk_lwe.dist(); - - let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n().into(), 1); - let sk_ref: ScalarZnx<&[u8]> = sk_lwe.data().to_ref(); - - let mut source_xa: Source = Source::new(seed_xa); - - self.keys.iter_mut().enumerate().for_each(|(i, ggsw)| { - pt.at_mut(0, 0)[0] = sk_ref.at(0, 0)[i]; - ggsw.encrypt_sk( - module, - &pt, - sk_glwe, - source_xa.new_seed(), - source_xe, - scratch, - ); - }); - } -}
@@ -0,0 +1,60 @@
+use poulpy_hal::{ + layouts::{Backend, DataMut, Scratch}, + source::Source, +}; + +use poulpy_core::{ + GetDistribution, ScratchTakeCore, + layouts::{GGSWInfos, GLWEInfos, GLWESecretPreparedToRef, LWEInfos, LWESecretToRef}, +}; + +use crate::tfhe::blind_rotation::{BlindRotationAlgo, BlindRotationKey}; + +pub trait BlindRotationKeyEncryptSk<BRA: BlindRotationAlgo, B: Backend> { + fn blind_rotation_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGSWInfos; + + #[allow(clippy::too_many_arguments)] + fn blind_rotation_key_encrypt_sk<D, S0, S1>( + &self, + res: &mut BlindRotationKey<D, BRA>, + sk_glwe: &S0, + sk_lwe: &S1, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<B>, + ) where + D: DataMut, + S0: GLWESecretPreparedToRef<B> + GLWEInfos, + S1: LWESecretToRef + LWEInfos + GetDistribution; +} + +impl<D: DataMut, BRA: BlindRotationAlgo> BlindRotationKey<D, BRA> { + pub fn encrypt_sk<M, S0, S1, BE: Backend>( + &mut self, + module: &M, + sk_glwe: &S0, + sk_lwe: &S1, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S0: GLWESecretPreparedToRef<BE> + GLWEInfos, + S1: LWESecretToRef + LWEInfos + GetDistribution, + Scratch<BE>: ScratchTakeCore<BE>, + M: BlindRotationKeyEncryptSk<BRA, BE>, + { + module.blind_rotation_key_encrypt_sk(self, sk_glwe, sk_lwe, source_xa, source_xe, scratch); + } +} + +impl<BRA: BlindRotationAlgo> BlindRotationKey<Vec<u8>, BRA> { + pub fn encrypt_sk_tmp_bytes<A, M, BE: Backend>(module: &M, infos: &A) -> usize + where + A: GGSWInfos, + M: BlindRotationKeyEncryptSk<BRA, BE>, + { + module.blind_rotation_key_encrypt_sk_tmp_bytes(infos) + } +}
@@ -0,0 +1,30 @@
+use poulpy_core::{ + GetDistribution, + layouts::{GGSWInfos, GLWEInfos, GLWESecretPreparedToRef, LWEInfos, LWESecretToRef}, +}; +use poulpy_hal::{ + layouts::{Backend, DataMut, Scratch}, + source::Source, +}; + +use crate::tfhe::blind_rotation::{BlindRotationAlgo, BlindRotationKeyCompressed}; + +pub trait BlindRotationKeyCompressedEncryptSk<B: Backend, BRA: BlindRotationAlgo> { + fn blind_rotation_key_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: GGSWInfos; + + #[allow(clippy::too_many_arguments)] + fn blind_rotation_key_compressed_encrypt_sk<D, S0, S1>( + &self, + res: &mut BlindRotationKeyCompressed<D, BRA>, + sk_glwe: &S0, + sk_lwe: &S1, + seed_xa: [u8; 32], + source_xe: &mut Source, + scratch: &mut Scratch<B>, + ) where + D: DataMut, + S0: GLWESecretPreparedToRef<B> + GLWEInfos, + S1: LWESecretToRef + LWEInfos + GetDistribution; +}
@@ -0,0 +1,5 @@
+mod key; +mod key_compressed; + +pub use key::*; +pub use key_compressed::*;
@@ -1,5 +1,5 @@
use poulpy_hal::{ - layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, Scratch, WriterTo}, + layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo}, source::Source, };@@ -7,10 +7,7 @@ use std::{fmt, marker::PhantomData};
use poulpy_core::{ Distribution, - layouts::{ - Base2K, Degree, Dnum, Dsize, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, LWESecret, Rank, TorusPrecision, - prepared::GLWESecretPrepared, - }, + layouts::{Base2K, Degree, Dnum, Dsize, GGSW, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision}, }; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};@@ -81,26 +78,29 @@ where
A: BlindRotationKeyInfos; } -pub trait BlindRotationKeyEncryptSk<B: Backend> { - #[allow(clippy::too_many_arguments)] - fn encrypt_sk<DataSkGLWE, DataSkLWE>( - &mut self, - module: &Module<B>, - sk_glwe: &GLWESecretPrepared<DataSkGLWE, B>, - sk_lwe: &LWESecret<DataSkLWE>, - source_xa: &mut Source, - source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) where - DataSkGLWE: DataRef, - DataSkLWE: DataRef; -} - #[derive(Clone)] pub struct BlindRotationKey<D: Data, BRT: BlindRotationAlgo> { - pub(crate) keys: Vec<GGSWCiphertext<D>>, + pub(crate) keys: Vec<GGSW<D>>, pub(crate) dist: Distribution, pub(crate) _phantom: PhantomData<BRT>, +} + +pub trait BlindRotationKeyFactory<BRA: BlindRotationAlgo> { + fn blind_rotation_key_alloc<A>(infos: &A) -> BlindRotationKey<Vec<u8>, BRA> + where + A: BlindRotationKeyInfos; +} + +impl<BRA: BlindRotationAlgo> BlindRotationKey<Vec<u8>, BRA> +where + Self: BlindRotationKeyFactory<BRA>, +{ + pub fn alloc<A>(infos: &A) -> BlindRotationKey<Vec<u8>, BRA> + where + A: BlindRotationKeyInfos, + { + Self::blind_rotation_key_alloc(infos) + } } impl<D: DataRef, BRT: BlindRotationAlgo> fmt::Debug for BlindRotationKey<D, BRT> {
@@ -8,16 +8,34 @@
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use poulpy_core::{ Distribution, - layouts::{Base2K, Degree, Dsize, GGSWInfos, GLWEInfos, LWEInfos, TorusPrecision, compressed::GGSWCiphertextCompressed}, + layouts::{Base2K, Degree, Dsize, GGSWInfos, GLWEInfos, LWEInfos, TorusPrecision, compressed::GGSWCompressed}, }; use crate::tfhe::blind_rotation::{BlindRotationAlgo, BlindRotationKeyInfos}; #[derive(Clone)] pub struct BlindRotationKeyCompressed<D: Data, BRT: BlindRotationAlgo> { - pub(crate) keys: Vec<GGSWCiphertextCompressed<D>>, + pub(crate) keys: Vec<GGSWCompressed<D>>, pub(crate) dist: Distribution, pub(crate) _phantom: PhantomData<BRT>, +} + +pub trait BlindRotationKeyCompressedFactory<BRA: BlindRotationAlgo> { + fn blind_rotation_key_compressed_alloc<A>(infos: &A) -> BlindRotationKeyCompressed<Vec<u8>, BRA> + where + A: BlindRotationKeyInfos; +} + +impl<BRA: BlindRotationAlgo> BlindRotationKeyCompressed<Vec<u8>, BRA> +where + Self: BlindRotationKeyCompressedFactory<BRA>, +{ + pub fn alloc<A>(infos: &A) -> BlindRotationKeyCompressed<Vec<u8>, BRA> + where + A: BlindRotationKeyInfos, + { + Self::blind_rotation_key_compressed_alloc(infos) + } } impl<D: DataRef, BRT: BlindRotationAlgo> fmt::Debug for BlindRotationKeyCompressed<D, BRT> {
@@ -1,130 +0,0 @@
-use poulpy_hal::{ - api::{SvpPPolAlloc, SvpPrepare, VmpPMatAlloc, VmpPrepare}, - layouts::{Backend, Data, DataMut, DataRef, Module, ScalarZnx, Scratch, SvpPPol}, -}; - -use std::marker::PhantomData; - -use poulpy_core::{ - Distribution, - layouts::{ - Base2K, Degree, Dnum, Dsize, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, - prepared::{GGSWCiphertextPrepared, Prepare, PrepareAlloc}, - }, -}; - -use crate::tfhe::blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyInfos, utils::set_xai_plus_y}; - -pub trait BlindRotationKeyPreparedAlloc<B: Backend> { - fn alloc<A>(module: &Module<B>, infos: &A) -> Self - where - A: BlindRotationKeyInfos; -} - -#[derive(PartialEq, Eq)] -pub struct BlindRotationKeyPrepared<D: Data, BRT: BlindRotationAlgo, B: Backend> { - pub(crate) data: Vec<GGSWCiphertextPrepared<D, B>>, - pub(crate) dist: Distribution, - pub(crate) x_pow_a: Option<Vec<SvpPPol<Vec<u8>, B>>>, - pub(crate) _phantom: PhantomData<BRT>, -} - -impl<D: Data, BRT: BlindRotationAlgo, B: Backend> BlindRotationKeyInfos for BlindRotationKeyPrepared<D, BRT, B> { - fn n_glwe(&self) -> Degree { - self.n() - } - - fn n_lwe(&self) -> Degree { - Degree(self.data.len() as u32) - } -} - -impl<D: Data, BRT: BlindRotationAlgo, B: Backend> LWEInfos for BlindRotationKeyPrepared<D, BRT, B> { - fn base2k(&self) -> Base2K { - self.data[0].base2k() - } - - fn k(&self) -> TorusPrecision { - self.data[0].k() - } - - fn n(&self) -> Degree { - self.data[0].n() - } - - fn size(&self) -> usize { - self.data[0].size() - } -} - -impl<D: Data, BRT: BlindRotationAlgo, B: Backend> GLWEInfos for BlindRotationKeyPrepared<D, BRT, B> { - fn rank(&self) -> Rank { - self.data[0].rank() - } -} -impl<D: Data, BRT: BlindRotationAlgo, B: Backend> GGSWInfos for BlindRotationKeyPrepared<D, BRT, B> { - fn dsize(&self) -> poulpy_core::layouts::Dsize { - Dsize(1) - } - - fn dnum(&self) -> Dnum { - self.data[0].dnum() - } -} - -impl<D: Data, BRT: BlindRotationAlgo, B: Backend> BlindRotationKeyPrepared<D, BRT, B> { - pub fn block_size(&self) -> usize { - match self.dist { - Distribution::BinaryBlock(value) => value, - _ => 1, - } - } -} - -impl<D: DataRef, BRA: BlindRotationAlgo, B: Backend> PrepareAlloc<B, BlindRotationKeyPrepared<Vec<u8>, BRA, B>> - for BlindRotationKey<D, BRA> -where - BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlindRotationKeyPreparedAlloc<B>, - BlindRotationKeyPrepared<Vec<u8>, BRA, B>: Prepare<B, BlindRotationKey<D, BRA>>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> BlindRotationKeyPrepared<Vec<u8>, BRA, B> { - let mut brk: BlindRotationKeyPrepared<Vec<u8>, BRA, B> = BlindRotationKeyPrepared::alloc(module, self); - brk.prepare(module, self, scratch); - brk - } -} - -impl<DM: DataMut, DR: DataRef, BRA: BlindRotationAlgo, B: Backend> Prepare<B, BlindRotationKey<DR, BRA>> - for BlindRotationKeyPrepared<DM, BRA, B> -where - Module<B>: VmpPMatAlloc<B> + VmpPrepare<B> + SvpPPolAlloc<B> + SvpPrepare<B>, -{ - fn prepare(&mut self, module: &Module<B>, other: &BlindRotationKey<DR, BRA>, scratch: &mut Scratch<B>) { - #[cfg(debug_assertions)] - { - assert_eq!(self.data.len(), other.keys.len()); - } - - let n: usize = other.n().as_usize(); - - self.data - .iter_mut() - .zip(other.keys.iter()) - .for_each(|(ggsw_prepared, other)| { - ggsw_prepared.prepare(module, other, scratch); - }); - - self.dist = other.dist; - - if let Distribution::BinaryBlock(_) = other.dist { - let mut x_pow_a: Vec<SvpPPol<Vec<u8>, B>> = Vec::with_capacity(n << 1); - let mut buf: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1); - (0..n << 1).for_each(|i| { - let mut res: SvpPPol<Vec<u8>, B> = module.svp_ppol_alloc(1); - set_xai_plus_y(module, i, 0, &mut res, &mut buf); - x_pow_a.push(res); - }); - self.x_pow_a = Some(x_pow_a); - } - } -}
@@ -0,0 +1,116 @@
+use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Scratch, SvpPPol}; + +use std::marker::PhantomData; + +use poulpy_core::{ + Distribution, + layouts::{Base2K, Degree, Dnum, Dsize, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::GGSWPrepared}, +}; + +use crate::tfhe::blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyInfos}; + +pub trait BlindRotationKeyPreparedFactory<BRA: BlindRotationAlgo, BE: Backend> { + fn blind_rotation_key_prepared_alloc<A>(&self, infos: &A) -> BlindRotationKeyPrepared<Vec<u8>, BRA, BE> + where + A: BlindRotationKeyInfos; + + fn blind_rotation_key_prepare_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: BlindRotationKeyInfos; + + fn prepare_blind_rotation_key<DM, DR>( + &self, + res: &mut BlindRotationKeyPrepared<DM, BRA, BE>, + other: &BlindRotationKey<DR, BRA>, + scratch: &mut Scratch<BE>, + ) where + DM: DataMut, + DR: DataRef; +} + +impl<BE: Backend, BRA: BlindRotationAlgo> BlindRotationKeyPrepared<Vec<u8>, BRA, BE> { + pub fn alloc<A, M>(module: &M, infos: &A) -> Self + where + A: BlindRotationKeyInfos, + M: BlindRotationKeyPreparedFactory<BRA, BE>, + { + module.blind_rotation_key_prepared_alloc(infos) + } + + pub fn prepare_tmp_bytes<M, A>(module: &M, infos: &A) -> usize + where + A: BlindRotationKeyInfos, + M: BlindRotationKeyPreparedFactory<BRA, BE>, + { + module.blind_rotation_key_prepare_tmp_bytes(infos) + } +} + +impl<D: DataMut, BRA: BlindRotationAlgo, BE: Backend> BlindRotationKeyPrepared<D, BRA, BE> { + pub fn prepare<DR: DataRef, M>(&mut self, module: &M, other: &BlindRotationKey<DR, BRA>, scratch: &mut Scratch<BE>) + where + M: BlindRotationKeyPreparedFactory<BRA, BE>, + { + module.prepare_blind_rotation_key(self, other, scratch); + } +} + +#[derive(PartialEq, Eq)] +pub struct BlindRotationKeyPrepared<D: Data, BRT: BlindRotationAlgo, B: Backend> { + pub(crate) data: Vec<GGSWPrepared<D, B>>, + pub(crate) dist: Distribution, + pub(crate) x_pow_a: Option<Vec<SvpPPol<Vec<u8>, B>>>, + pub(crate) _phantom: PhantomData<BRT>, +} + +impl<D: Data, BRT: BlindRotationAlgo, B: Backend> BlindRotationKeyInfos for BlindRotationKeyPrepared<D, BRT, B> { + fn n_glwe(&self) -> Degree { + self.n() + } + + fn n_lwe(&self) -> Degree { + Degree(self.data.len() as u32) + } +} + +impl<D: Data, BRT: BlindRotationAlgo, B: Backend> LWEInfos for BlindRotationKeyPrepared<D, BRT, B> { + fn base2k(&self) -> Base2K { + self.data[0].base2k() + } + + fn k(&self) -> TorusPrecision { + self.data[0].k() + } + + fn n(&self) -> Degree { + self.data[0].n() + } + + fn size(&self) -> usize { + self.data[0].size() + } +} + +impl<D: Data, BRT: BlindRotationAlgo, B: Backend> GLWEInfos for BlindRotationKeyPrepared<D, BRT, B> { + fn rank(&self) -> Rank { + self.data[0].rank() + } +} +impl<D: Data, BRT: BlindRotationAlgo, B: Backend> GGSWInfos for BlindRotationKeyPrepared<D, BRT, B> { + fn dsize(&self) -> poulpy_core::layouts::Dsize { + Dsize(1) + } + + fn dnum(&self) -> Dnum { + self.data[0].dnum() + } +} + +impl<D: Data, BRT: BlindRotationAlgo, B: Backend> BlindRotationKeyPrepared<D, BRT, B> { + pub fn block_size(&self) -> usize { + match self.dist { + Distribution::BinaryBlock(value) => value, + _ => 1, + } + } +}
@@ -0,0 +1,6 @@
+mod key; +mod key_compressed; +mod key_prepared; +pub use key::*; +pub use key_compressed::*; +pub use key_prepared::*;
@@ -1,3 +1,4 @@
+use poulpy_core::layouts::{Base2K, Degree, TorusPrecision}; use poulpy_hal::{ api::{ ScratchOwnedAlloc, ScratchOwnedBorrow, TakeSlice, VecZnxCopy, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes,@@ -13,32 +14,97 @@ Left,
Right, } -pub struct LookUpTable { +pub struct LookUpTableLayout { + pub n: Degree, + pub extension_factor: usize, + pub k: TorusPrecision, + pub base2k: Base2K, +} + +pub trait LookupTableInfos { + fn n(&self) -> Degree; + fn extension_factor(&self) -> usize; + fn k(&self) -> TorusPrecision; + fn base2k(&self) -> Base2K; + fn size(&self) -> usize; +} + +impl LookupTableInfos for LookUpTableLayout { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn extension_factor(&self) -> usize { + self.extension_factor + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn size(&self) -> usize { + self.k().as_usize().div_ceil(self.base2k().as_usize()) + } + + fn n(&self) -> Degree { + self.n + } +} + +pub struct LookupTable { pub(crate) data: Vec<VecZnx<Vec<u8>>>, pub(crate) rot_dir: LookUpTableRotationDirection, - pub(crate) base2k: usize, - pub(crate) k: usize, + pub(crate) base2k: Base2K, + pub(crate) k: TorusPrecision, pub(crate) drift: usize, } -impl LookUpTable { - pub fn alloc<B: Backend>(module: &Module<B>, base2k: usize, k: usize, extension_factor: usize) -> Self { +impl LookupTableInfos for LookupTable { + fn base2k(&self) -> Base2K { + self.base2k + } + + fn extension_factor(&self) -> usize { + self.data.len() + } + + fn k(&self) -> TorusPrecision { + self.k + } + + fn n(&self) -> Degree { + self.data[0].n().into() + } + + fn size(&self) -> usize { + self.data[0].size() + } +} + +pub trait LookupTableFactory { + fn lookup_table_set(&self, res: &mut LookupTable, f: &[i64], k: usize); + fn lookup_table_rotate(&self, k: i64, res: &mut LookupTable); +} + +impl LookupTable { + pub fn alloc<A>(infos: &A) -> Self + where + A: LookupTableInfos, + { #[cfg(debug_assertions)] { assert!( - extension_factor & (extension_factor - 1) == 0, - "extension_factor must be a power of two but is: {extension_factor}" + infos.extension_factor() & (infos.extension_factor() - 1) == 0, + "extension_factor must be a power of two but is: {}", + infos.extension_factor() ); } - let size: usize = k.div_ceil(base2k); - let mut data: Vec<VecZnx<Vec<u8>>> = Vec::with_capacity(extension_factor); - (0..extension_factor).for_each(|_| { - data.push(VecZnx::alloc(module.n(), 1, size)); - }); Self { - data, - base2k, - k, + data: (0..infos.extension_factor()) + .map(|_| VecZnx::alloc(infos.n().into(), 1, infos.size())) + .collect(), + base2k: infos.base2k(), + k: infos.k(), drift: 0, rot_dir: LookUpTableRotationDirection::Left, }@@ -68,34 +134,80 @@ pub fn set_rotation_direction(&mut self, rot_dir: LookUpTableRotationDirection) {
self.rot_dir = rot_dir } - pub fn set<B: Backend>(&mut self, module: &Module<B>, f: &[i64], k: usize) + pub fn set<M>(&mut self, module: &M, f: &[i64], k: usize) where - Module<B>: VecZnxRotateInplace<B> - + VecZnxNormalizeInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxCopy - + VecZnxRotateInplaceTmpBytes, - ScratchOwned<B>: ScratchOwnedAlloc<B> + ScratchOwnedBorrow<B>, - Scratch<B>: TakeSlice, + M: LookupTableFactory, { - assert!(f.len() <= module.n()); + module.lookup_table_set(self, f, k); + } - let base2k: usize = self.base2k; + pub(crate) fn rotate<M>(&mut self, module: &M, k: i64) + where + M: LookupTableFactory, + { + module.lookup_table_rotate(k, self); + } +} - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(module.vec_znx_normalize_tmp_bytes() | (self.domain_size() << 3)); +pub(crate) trait DivRound { + fn div_round(self, rhs: Self) -> Self; +} + +impl DivRound for usize { + #[inline] + fn div_round(self, rhs: Self) -> Self { + (self + rhs / 2) / rhs + } +} + +#[allow(dead_code)] +fn max_bit_size(vec: &[i64]) -> u32 { + vec.iter() + .map(|&v| { + if v == 0 { + 0 + } else { + v.unsigned_abs().ilog2() + 1 + } + }) + .max() + .unwrap_or(0) +} + +impl<BE: Backend> LookupTableFactory for Module<BE> +where + Self: VecZnxRotateInplace<BE> + + VecZnxNormalizeInplace<BE> + + VecZnxNormalizeTmpBytes + + VecZnxSwitchRing + + VecZnxCopy + + VecZnxRotateInplaceTmpBytes + + VecZnxRotateInplace<BE> + + VecZnxRotateInplaceTmpBytes, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: TakeSlice, +{ + fn lookup_table_set(&self, res: &mut LookupTable, f: &[i64], k: usize) { + assert!(f.len() <= self.n()); + + let base2k: usize = res.base2k.into(); + + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc( + self.vec_znx_normalize_tmp_bytes() + .max(res.domain_size() << 3), + ); // Get the number minimum limb to store the message modulus let limbs: usize = k.div_ceil(base2k); #[cfg(debug_assertions)] { - assert!(f.len() <= module.n()); + assert!(f.len() <= self.n()); assert!( (max_bit_size(f) + (k % base2k) as u32) < i64::BITS, "overflow: max(|f|) << (k%base2k) > i64::BITS" ); - assert!(limbs <= self.data[0].size()); + assert!(limbs <= res.data[0].size()); } // Scaling factor@@ -108,9 +220,9 @@ // #elements in lookup table
let f_len: usize = f.len(); // If LUT size > TakeScalarZnx - let domain_size: usize = self.domain_size(); + let domain_size: usize = res.domain_size(); - let size: usize = self.k.div_ceil(self.base2k); + let size: usize = res.k.div_ceil(res.base2k) as usize; // Equivalent to AUTO([f(0), -f(n-1), -f(n-2), ..., -f(1)], -1) let mut lut_full: VecZnx<Vec<u8>> = VecZnx::alloc(domain_size, 1, size);@@ -129,39 +241,34 @@ let drift: usize = step >> 1;
// Rotates half the step to the left - if self.extension_factor() > 1 { + if res.extension_factor() > 1 { let (tmp, _) = scratch.borrow().take_slice(lut_full.n()); - for i in 0..self.extension_factor() { - module.vec_znx_switch_ring(&mut self.data[i], 0, &lut_full, 0); - if i < self.extension_factor() { + for i in 0..res.extension_factor() { + self.vec_znx_switch_ring(&mut res.data[i], 0, &lut_full, 0); + if i < res.extension_factor() { vec_znx_rotate_inplace::<_, ZnxRef>(-1, &mut lut_full, 0, tmp); } } } else { - module.vec_znx_copy(&mut self.data[0], 0, &lut_full, 0); + self.vec_znx_copy(&mut res.data[0], 0, &lut_full, 0); } - for a in self.data.iter_mut() { - module.vec_znx_normalize_inplace(self.base2k, a, 0, scratch.borrow()); + for a in res.data.iter_mut() { + self.vec_znx_normalize_inplace(res.base2k.into(), a, 0, scratch.borrow()); } - self.rotate(module, -(drift as i64)); + res.rotate(self, -(drift as i64)); - self.drift = drift + res.drift = drift } - #[allow(dead_code)] - pub(crate) fn rotate<B: Backend>(&mut self, module: &Module<B>, k: i64) - where - Module<B>: VecZnxRotateInplace<B> + VecZnxRotateInplaceTmpBytes, - ScratchOwned<B>: ScratchOwnedAlloc<B> + ScratchOwnedBorrow<B>, - { - let extension_factor: usize = self.extension_factor(); - let two_n: usize = 2 * self.data[0].n(); + fn lookup_table_rotate(&self, k: i64, res: &mut LookupTable) { + let extension_factor: usize = res.extension_factor(); + let two_n: usize = 2 * res.data[0].n(); let two_n_ext: usize = two_n * extension_factor; - let mut scratch: ScratchOwned<_> = ScratchOwned::alloc(module.vec_znx_rotate_inplace_tmp_bytes()); + let mut scratch: ScratchOwned<_> = ScratchOwned::alloc(self.vec_znx_rotate_inplace_tmp_bytes()); let k_pos: usize = ((k + two_n_ext as i64) % two_n_ext as i64) as usize;@@ -169,38 +276,13 @@ let k_hi: usize = k_pos / extension_factor;
let k_lo: usize = k_pos % extension_factor; (0..extension_factor - k_lo).for_each(|i| { - module.vec_znx_rotate_inplace(k_hi as i64, &mut self.data[i], 0, scratch.borrow()); + self.vec_znx_rotate_inplace(k_hi as i64, &mut res.data[i], 0, scratch.borrow()); }); (extension_factor - k_lo..extension_factor).for_each(|i| { - module.vec_znx_rotate_inplace(k_hi as i64 + 1, &mut self.data[i], 0, scratch.borrow()); + self.vec_znx_rotate_inplace(k_hi as i64 + 1, &mut res.data[i], 0, scratch.borrow()); }); - self.data.rotate_right(k_lo); - } -} - -pub(crate) trait DivRound { - fn div_round(self, rhs: Self) -> Self; -} - -impl DivRound for usize { - #[inline] - fn div_round(self, rhs: Self) -> Self { - (self + rhs / 2) / rhs + res.data.rotate_right(k_lo); } } - -#[allow(dead_code)] -fn max_bit_size(vec: &[i64]) -> u32 { - vec.iter() - .map(|&v| { - if v == 0 { - 0 - } else { - v.unsigned_abs().ilog2() + 1 - } - }) - .max() - .unwrap_or(0) -}
@@ -1,35 +1,11 @@
-mod cggi_algo; -mod cggi_key; -mod key; -mod key_compressed; -mod key_prepared; +mod algorithms; +mod encryption; +mod layouts; mod lut; mod utils; -pub use cggi_algo::*; -pub use key::*; -pub use key_compressed::*; -pub use key_prepared::*; +pub use algorithms::*; +pub use encryption::*; +pub use layouts::*; pub use lut::*; - pub mod tests; - -use poulpy_core::layouts::{GLWECiphertext, LWECiphertext}; -use poulpy_hal::layouts::{Backend, DataMut, DataRef, Module, Scratch}; - -pub trait BlindRotationAlgo {} - -#[derive(Clone)] -pub struct CGGI {} -impl BlindRotationAlgo for CGGI {} - -pub trait BlincRotationExecute<B: Backend> { - fn execute<DR: DataMut, DI: DataRef>( - &self, - module: &Module<B>, - res: &mut GLWECiphertext<DR>, - lwe: &LWECiphertext<DI>, - lut: &LookUpTable, - scratch: &mut Scratch<B>, - ); -}
@@ -1,89 +1,39 @@
use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, - SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, - VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAdd, VecZnxDftAddInplace, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftSubInplace, VecZnxDftZero, VecZnxFillUniform, VecZnxIdftApply, - VecZnxIdftApplyConsume, VecZnxIdftApplyTmpBytes, VecZnxMulXpMinusOneInplace, VecZnxNormalize, VecZnxNormalizeInplace, - VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, VecZnxSub, VecZnxSubInplace, - VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, ZnAddNormal, - ZnFillUniform, ZnNormalizeInplace, - }, - layouts::{Backend, Module, ScratchOwned, ZnxView}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeSliceImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, - TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, VecZnxBigAllocBytesImpl, VecZnxDftAllocBytesImpl, - }, + api::{ScratchOwnedAlloc, ScratchOwnedBorrow}, + layouts::{Backend, Scratch, ScratchOwned, ZnxView}, source::Source, }; use crate::tfhe::blind_rotation::{ - BlincRotationExecute, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, BlindRotationKeyLayout, - BlindRotationKeyPrepared, CGGI, LookUpTable, cggi_blind_rotate_scratch_space, mod_switch_2n, + BlindRotationAlgo, BlindRotationExecute, BlindRotationKey, BlindRotationKeyEncryptSk, BlindRotationKeyFactory, + BlindRotationKeyLayout, BlindRotationKeyPrepared, BlindRotationKeyPreparedFactory, LookUpTableLayout, LookupTable, + LookupTableFactory, mod_switch_2n, }; -use poulpy_core::layouts::{ - GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, LWECiphertext, LWECiphertextLayout, LWECiphertextToRef, - LWEInfos, LWEPlaintext, LWESecret, - prepared::{GLWESecretPrepared, PrepareAlloc}, +use poulpy_core::{ + GLWEDecrypt, LWEEncryptSk, ScratchTakeCore, + layouts::{ + GLWE, GLWELayout, GLWEPlaintext, GLWESecret, GLWESecretPreparedFactory, LWE, LWEInfos, LWELayout, LWEPlaintext, + LWESecret, LWEToRef, prepared::GLWESecretPrepared, + }, }; -pub fn test_blind_rotation<B>(module: &Module<B>, n_lwe: usize, block_size: usize, extension_factor: usize) -where - Module<B>: VecZnxBigAllocBytes - + VecZnxDftAllocBytes - + SvpPPolAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VecZnxIdftApplyTmpBytes - + VecZnxIdftApply<B> - + VecZnxDftAdd<B> - + VecZnxDftAddInplace<B> - + VecZnxDftApply<B> - + VecZnxDftZero<B> - + SvpApplyDftToDft<B> - + VecZnxDftSubInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxRotate - + VecZnxAddInplace - + VecZnxSubInplace - + VecZnxNormalize<B> - + VecZnxNormalizeInplace<B> - + VecZnxCopy - + VecZnxMulXpMinusOneInplace<B> - + SvpPrepare<B> - + SvpPPolAlloc<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxAddNormal - + VecZnxAddScalarInplace - + VecZnxRotateInplace<B> - + VecZnxSwitchRing - + VecZnxSub - + VmpPMatAlloc<B> - + VmpPrepare<B> - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + ZnFillUniform - + ZnAddNormal - + VecZnxRotateInplaceTmpBytes - + ZnNormalizeInplace<B>, - B: Backend - + VecZnxDftAllocBytesImpl<B> - + VecZnxBigAllocBytesImpl<B> - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + TakeVecZnxDftImpl<B> - + TakeVecZnxBigImpl<B> - + TakeVecZnxDftSliceImpl<B> - + ScratchAvailableImpl<B> - + TakeVecZnxImpl<B> - + TakeVecZnxSliceImpl<B> - + TakeSliceImpl<B>, +pub fn test_blind_rotation<BRA: BlindRotationAlgo, M, BE: Backend>( + module: &M, + n_lwe: usize, + block_size: usize, + extension_factor: usize, +) where + M: BlindRotationKeyEncryptSk<BRA, BE> + + BlindRotationKeyPreparedFactory<BRA, BE> + + BlindRotationExecute<BRA, BE> + + LookupTableFactory + + GLWESecretPreparedFactory<BE> + + GLWEDecrypt<BE> + + LWEEncryptSk<BE>, + BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { let n_glwe: usize = module.n(); let base2k: usize = 19;@@ -111,31 +61,30 @@ dnum: rows_brk.into(),
rank: rank.into(), }; - let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout { + let glwe_infos: GLWELayout = GLWELayout { n: n_glwe.into(), base2k: base2k.into(), k: k_res.into(), rank: rank.into(), }; - let lwe_infos: LWECiphertextLayout = LWECiphertextLayout { + let lwe_infos: LWELayout = LWELayout { n: n_lwe.into(), k: k_lwe.into(), base2k: base2k.into(), }; - let mut scratch: ScratchOwned<B> = ScratchOwned::<B>::alloc(BlindRotationKey::generate_from_sk_scratch_space( - module, &brk_infos, - )); + let mut scratch: ScratchOwned<BE> = ScratchOwned::<BE>::alloc(BlindRotationKey::encrypt_sk_tmp_bytes(module, &brk_infos)); - let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos); + let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&glwe_infos); sk_glwe.fill_ternary_prob(0.5, &mut source_xs); - let sk_glwe_dft: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow()); + let mut sk_glwe_dft: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &glwe_infos); + sk_glwe_dft.prepare(module, &sk_glwe); let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe.into()); sk_lwe.fill_binary_block(block_size, &mut source_xs); - let mut scratch_br: ScratchOwned<B> = ScratchOwned::<B>::alloc(cggi_blind_rotate_scratch_space( + let mut scratch_br: ScratchOwned<BE> = ScratchOwned::<BE>::alloc(BlindRotationKeyPrepared::execute_tmp_bytes( module, block_size, extension_factor,@@ -143,7 +92,7 @@ &glwe_infos,
&brk_infos, )); - let mut brk: BlindRotationKey<Vec<u8>, CGGI> = BlindRotationKey::<Vec<u8>, CGGI>::alloc(&brk_infos); + let mut brk: BlindRotationKey<Vec<u8>, BRA> = BlindRotationKey::<Vec<u8>, BRA>::alloc(&brk_infos); brk.encrypt_sk( module,@@ -154,9 +103,9 @@ &mut source_xe,
scratch.borrow(), ); - let mut lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos); + let mut lwe: LWE<Vec<u8>> = LWE::alloc_from_infos(&lwe_infos); - let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(&lwe_infos); + let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_from_infos(&lwe_infos); let x: i64 = 15 % (message_modulus as i64);@@ -172,16 +121,24 @@ .iter_mut()
.enumerate() .for_each(|(i, x)| *x = f(i as i64)); - let mut lut: LookUpTable = LookUpTable::alloc(module, base2k, k_lut, extension_factor); + let lut_infos = LookUpTableLayout { + n: module.n().into(), + extension_factor, + k: k_lut.into(), + base2k: base2k.into(), + }; + + let mut lut: LookupTable = LookupTable::alloc(&lut_infos); lut.set(module, &f_vec, log_message_modulus + 1); - let mut res: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos); + let mut res: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos); - let brk_prepared: BlindRotationKeyPrepared<Vec<u8>, CGGI, B> = brk.prepare_alloc(module, scratch.borrow()); + let mut brk_prepared: BlindRotationKeyPrepared<Vec<u8>, BRA, BE> = BlindRotationKeyPrepared::alloc(module, &brk); + brk_prepared.prepare(module, &brk, scratch_br.borrow()); brk_prepared.execute(module, &mut res, &lwe, &lut, scratch_br.borrow()); - let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos); + let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos); res.decrypt(module, &mut pt_have, &sk_glwe_dft, scratch.borrow());
@@ -1,25 +1,12 @@
use std::vec; -use poulpy_hal::{ - api::{ - VecZnxCopy, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, - VecZnxSwitchRing, - }, - layouts::{Backend, Module}, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeSliceImpl}, -}; +use poulpy_hal::api::ModuleN; -use crate::tfhe::blind_rotation::{DivRound, LookUpTable}; +use crate::tfhe::blind_rotation::{DivRound, LookUpTableLayout, LookupTable, LookupTableFactory}; -pub fn test_lut_standard<B>(module: &Module<B>) +pub fn test_lut_standard<M>(module: &M) where - Module<B>: VecZnxRotateInplace<B> - + VecZnxNormalizeInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxCopy - + VecZnxRotateInplaceTmpBytes, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B> + TakeSliceImpl<B>, + M: LookupTableFactory + ModuleN, { let base2k: usize = 20; let k_lut: usize = 40;@@ -33,7 +20,14 @@ f.iter_mut()
.enumerate() .for_each(|(i, x)| *x = (i as i64) - 8); - let mut lut: LookUpTable = LookUpTable::alloc(module, base2k, k_lut, extension_factor); + let lut_infos: LookUpTableLayout = LookUpTableLayout { + n: module.n().into(), + extension_factor, + k: k_lut.into(), + base2k: base2k.into(), + }; + + let mut lut: LookupTable = LookupTable::alloc(&lut_infos); lut.set(module, &f, log_scale); let half_step: i64 = lut.domain_size().div_round(message_modulus << 1) as i64;@@ -51,15 +45,9 @@ });
}); } -pub fn test_lut_extended<B>(module: &Module<B>) +pub fn test_lut_extended<M>(module: &M) where - Module<B>: VecZnxRotateInplace<B> - + VecZnxNormalizeInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxCopy - + VecZnxRotateInplaceTmpBytes, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B> + TakeSliceImpl<B>, + M: LookupTableFactory + ModuleN, { let base2k: usize = 20; let k_lut: usize = 40;@@ -73,7 +61,14 @@ f.iter_mut()
.enumerate() .for_each(|(i, x)| *x = (i as i64) - 8); - let mut lut: LookUpTable = LookUpTable::alloc(module, base2k, k_lut, extension_factor); + let lut_infos: LookUpTableLayout = LookUpTableLayout { + n: module.n().into(), + extension_factor, + k: k_lut.into(), + base2k: base2k.into(), + }; + + let mut lut: LookupTable = LookupTable::alloc(&lut_infos); lut.set(module, &f, log_scale); let half_step: i64 = lut.domain_size().div_round(message_modulus << 1) as i64;
@@ -1,8 +1,6 @@
use poulpy_hal::test_suite::serialization::test_reader_writer_interface; -use crate::tfhe::blind_rotation::{ - BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyCompressed, BlindRotationKeyLayout, CGGI, -}; +use crate::tfhe::blind_rotation::{BlindRotationKey, BlindRotationKeyCompressed, BlindRotationKeyLayout, CGGI}; #[test] fn test_cggi_blind_rotation_key_serialization() {@@ -14,7 +12,6 @@ k: 54_usize.into(),
dnum: 2_usize.into(), rank: 2_usize.into(), }; - let original: BlindRotationKey<Vec<u8>, CGGI> = BlindRotationKey::alloc(&layout); test_reader_writer_interface(original); }@@ -29,7 +26,6 @@ k: 54_usize.into(),
dnum: 2_usize.into(), rank: 2_usize.into(), }; - let original: BlindRotationKeyCompressed<Vec<u8>, CGGI> = BlindRotationKeyCompressed::alloc(&layout); test_reader_writer_interface(original); }
@@ -1,37 +0,0 @@
-use poulpy_backend::cpu_spqlios::FFT64Spqlios; -use poulpy_hal::{api::ModuleNew, layouts::Module}; - -use crate::tfhe::blind_rotation::tests::{ - generic_blind_rotation::test_blind_rotation, - generic_lut::{test_lut_extended, test_lut_standard}, -}; - -#[test] -fn lut_standard() { - let module: Module<FFT64Spqlios> = Module::<FFT64Spqlios>::new(32); - test_lut_standard(&module); -} - -#[test] -fn lut_extended() { - let module: Module<FFT64Spqlios> = Module::<FFT64Spqlios>::new(32); - test_lut_extended(&module); -} - -#[test] -fn standard() { - let module: Module<FFT64Spqlios> = Module::<FFT64Spqlios>::new(512); - test_blind_rotation(&module, 224, 1, 1); -} - -#[test] -fn block_binary() { - let module: Module<FFT64Spqlios> = Module::<FFT64Spqlios>::new(512); - test_blind_rotation(&module, 224, 7, 1); -} - -#[test] -fn block_binary_extended() { - let module: Module<FFT64Spqlios> = Module::<FFT64Spqlios>::new(512); - test_blind_rotation(&module, 224, 7, 2); -}
@@ -1,1 +0,0 @@
-mod fft64;
@@ -0,0 +1,40 @@
+use poulpy_backend::cpu_fft64_ref::FFT64Ref; +use poulpy_hal::{api::ModuleNew, layouts::Module}; + +use crate::tfhe::blind_rotation::{ + CGGI, + tests::{ + generic_blind_rotation::test_blind_rotation, + generic_lut::{test_lut_extended, test_lut_standard}, + }, +}; + +#[test] +fn lut_standard() { + let module: Module<FFT64Ref> = Module::<FFT64Ref>::new(32); + test_lut_standard(&module); +} + +#[test] +fn lut_extended() { + let module: Module<FFT64Ref> = Module::<FFT64Ref>::new(32); + test_lut_extended(&module); +} + +#[test] +fn standard() { + let module: Module<FFT64Ref> = Module::<FFT64Ref>::new(512); + test_blind_rotation::<CGGI, _, FFT64Ref>(&module, 224, 1, 1); +} + +#[test] +fn block_binary() { + let module: Module<FFT64Ref> = Module::<FFT64Ref>::new(512); + test_blind_rotation::<CGGI, _, FFT64Ref>(&module, 224, 7, 1); +} + +#[test] +fn block_binary_extended() { + let module: Module<FFT64Ref> = Module::<FFT64Ref>::new(512); + test_blind_rotation::<CGGI, _, FFT64Ref>(&module, 224, 7, 2); +}
@@ -1,1 +1,1 @@
-mod cpu_spqlios; +mod fft64;
@@ -1,185 +1,231 @@
use std::collections::HashMap; use poulpy_hal::{ - api::{ - ScratchAvailable, TakeMatZnx, TakeSlice, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, TakeVecZnxDftSlice, TakeVecZnxSlice, - VecZnxAddInplace, VecZnxAutomorphismInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, - VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAddInplace, - VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNegateInplace, - VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, - VecZnxRotateInplaceTmpBytes, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, - VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ToOwnedDeep}, - oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl}, + api::{ModuleLogN, ModuleN, ScratchOwnedAlloc, ScratchOwnedBorrow}, + layouts::{Backend, DataRef, Module, Scratch, ScratchOwned, ToOwnedDeep}, }; use poulpy_core::{ - GLWEOperations, TakeGGLWE, TakeGLWECt, - layouts::{Dsize, GGLWECiphertextLayout, GGSWInfos, GLWEInfos, LWEInfos}, + GGSWFromGGLWE, GLWEDecrypt, GLWEPacking, GLWETrace, ScratchTakeCore, + layouts::{ + Dsize, GGLWELayout, GGSWInfos, GGSWToMut, GLWEInfos, GLWESecretPreparedFactory, GLWEToMut, GLWEToRef, LWEInfos, LWEToRef, + }, }; -use poulpy_core::glwe_packing; -use poulpy_core::layouts::{GGSWCiphertext, GLWECiphertext, LWECiphertext, prepared::GGLWEAutomorphismKeyPrepared}; +use poulpy_core::layouts::{GGSW, GLWE, LWE, prepared::GLWEAutomorphismKeyPrepared}; use crate::tfhe::{ blind_rotation::{ - BlincRotationExecute, BlindRotationAlgo, BlindRotationKeyPrepared, LookUpTable, LookUpTableRotationDirection, + BlindRotationAlgo, BlindRotationExecute, LookUpTableLayout, LookUpTableRotationDirection, LookupTable, LookupTableFactory, }, - circuit_bootstrapping::{CircuitBootstrappingKeyPrepared, CirtuitBootstrappingExecute}, + circuit_bootstrapping::{CircuitBootstrappingKeyInfos, CircuitBootstrappingKeyPrepared}, }; -impl<D: DataRef, BRA: BlindRotationAlgo, B> CirtuitBootstrappingExecute<B> for CircuitBootstrappingKeyPrepared<D, BRA, B> +pub trait CirtuitBootstrappingExecute<BRA: BlindRotationAlgo, BE: Backend> { + fn circuit_bootstrapping_execute_tmp_bytes<R, A>( + &self, + block_size: usize, + extension_factor: usize, + res_infos: &R, + cbt_infos: &A, + ) -> usize + where + R: GGSWInfos, + A: CircuitBootstrappingKeyInfos; + + fn circuit_bootstrapping_execute_to_constant<R, L, D>( + &self, + res: &mut R, + lwe: &L, + key: &CircuitBootstrappingKeyPrepared<D, BRA, BE>, + log_domain: usize, + extension_factor: usize, + scratch: &mut Scratch<BE>, + ) where + R: GGSWToMut + GGSWInfos, + L: LWEToRef + LWEInfos, + D: DataRef; + + #[allow(clippy::too_many_arguments)] + fn circuit_bootstrapping_execute_to_exponent<R, L, D>( + &self, + log_gap_out: usize, + res: &mut R, + lwe: &L, + key: &CircuitBootstrappingKeyPrepared<D, BRA, BE>, + log_domain: usize, + extension_factor: usize, + scratch: &mut Scratch<BE>, + ) where + R: GGSWToMut + GGSWInfos, + L: LWEToRef + LWEInfos, + D: DataRef; +} + +impl<D: DataRef, BRA: BlindRotationAlgo, BE: Backend> CircuitBootstrappingKeyPrepared<D, BRA, BE> { + pub fn execute_to_constant<M, L, R>( + &self, + module: &M, + res: &mut R, + lwe: &L, + log_domain: usize, + extension_factor: usize, + scratch: &mut Scratch<BE>, + ) where + M: CirtuitBootstrappingExecute<BRA, BE>, + R: GGSWToMut + GGSWInfos, + L: LWEToRef + LWEInfos, + { + module.circuit_bootstrapping_execute_to_constant(res, lwe, self, log_domain, extension_factor, scratch); + } + + #[allow(clippy::too_many_arguments)] + pub fn execute_to_exponent<R, L, M>( + &self, + module: &M, + log_gap_out: usize, + res: &mut R, + lwe: &L, + log_domain: usize, + extension_factor: usize, + scratch: &mut Scratch<BE>, + ) where + M: CirtuitBootstrappingExecute<BRA, BE>, + R: GGSWToMut + GGSWInfos, + L: LWEToRef + LWEInfos, + { + module.circuit_bootstrapping_execute_to_exponent( + log_gap_out, + res, + lwe, + self, + log_domain, + extension_factor, + scratch, + ); + } +} + +impl<BRA: BlindRotationAlgo, BE: Backend> CirtuitBootstrappingExecute<BRA, BE> for Module<BE> where - Module<B>: VecZnxRotateInplace<B> - + VecZnxNormalizeInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxSub - + VecZnxAddInplace - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxSubInplace - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxRotateInplaceTmpBytes - + VecZnxBigAllocBytes - + VecZnxDftAddInplace<B> - + VecZnxRotate - + VecZnxNormalize<B>, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, - Scratch<B>: TakeVecZnx - + TakeVecZnxDftSlice<B> - + TakeVecZnxBig<B> - + TakeVecZnxDft<B> - + TakeMatZnx - + ScratchAvailable - + TakeVecZnxSlice - + TakeSlice, - BlindRotationKeyPrepared<D, BRA, B>: BlincRotationExecute<B>, + Self: ModuleN + + LookupTableFactory + + BlindRotationExecute<BRA, BE> + + GLWETrace<BE> + + GLWEPacking<BE> + + GGSWFromGGLWE<BE> + + GLWESecretPreparedFactory<BE> + + GLWEDecrypt<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { - fn execute_to_constant<DM: DataMut, DR: DataRef>( + fn circuit_bootstrapping_execute_tmp_bytes<R, A>( &self, - module: &Module<B>, - res: &mut GGSWCiphertext<DM>, - lwe: &LWECiphertext<DR>, + block_size: usize, + extension_factor: usize, + res_infos: &R, + cbt_infos: &A, + ) -> usize + where + R: GGSWInfos, + A: CircuitBootstrappingKeyInfos, + { + self.blind_rotation_execute_tmp_bytes( + block_size, + extension_factor, + res_infos, + &cbt_infos.brk_infos(), + ) + .max(self.glwe_trace_tmp_bytes(res_infos, res_infos, &cbt_infos.atk_infos())) + .max(self.ggsw_from_gglwe_tmp_bytes(res_infos, &cbt_infos.tsk_infos())) + } + + fn circuit_bootstrapping_execute_to_constant<R, L, D>( + &self, + res: &mut R, + lwe: &L, + key: &CircuitBootstrappingKeyPrepared<D, BRA, BE>, log_domain: usize, extension_factor: usize, - scratch: &mut Scratch<B>, - ) { + scratch: &mut Scratch<BE>, + ) where + R: GGSWToMut + GGSWInfos, + L: LWEToRef + LWEInfos, + D: DataRef, + { circuit_bootstrap_core( false, - module, + self, 0, res, lwe, log_domain, extension_factor, - self, + key, scratch, ); } - fn execute_to_exponent<DM: DataMut, DR: DataRef>( + fn circuit_bootstrapping_execute_to_exponent<R, L, D>( &self, - module: &Module<B>, log_gap_out: usize, - res: &mut GGSWCiphertext<DM>, - lwe: &LWECiphertext<DR>, + res: &mut R, + lwe: &L, + key: &CircuitBootstrappingKeyPrepared<D, BRA, BE>, log_domain: usize, extension_factor: usize, - scratch: &mut Scratch<B>, - ) { + scratch: &mut Scratch<BE>, + ) where + R: GGSWToMut + GGSWInfos, + L: LWEToRef + LWEInfos, + D: DataRef, + { circuit_bootstrap_core( true, - module, + self, log_gap_out, res, lwe, log_domain, extension_factor, - self, + key, scratch, ); } } #[allow(clippy::too_many_arguments)] -pub fn circuit_bootstrap_core<DRes, DLwe, DBrk, BRA: BlindRotationAlgo, B>( +pub fn circuit_bootstrap_core<R, L, D, M, BRA: BlindRotationAlgo, BE: Backend>( to_exponent: bool, - module: &Module<B>, + module: &M, log_gap_out: usize, - res: &mut GGSWCiphertext<DRes>, - lwe: &LWECiphertext<DLwe>, + res: &mut R, + lwe: &L, log_domain: usize, extension_factor: usize, - key: &CircuitBootstrappingKeyPrepared<DBrk, BRA, B>, - scratch: &mut Scratch<B>, + key: &CircuitBootstrappingKeyPrepared<D, BRA, BE>, + scratch: &mut Scratch<BE>, ) where - DRes: DataMut, - DLwe: DataRef, - DBrk: DataRef, - Module<B>: VecZnxRotateInplace<B> - + VecZnxNormalizeInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxSub - + VecZnxAddInplace - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxSubInplace - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxBigAllocBytes - + VecZnxDftAddInplace<B> - + VecZnxRotateInplaceTmpBytes - + VecZnxRotate - + VecZnxNormalize<B>, - B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>, - Scratch<B>: TakeVecZnxDftSlice<B> - + TakeVecZnxBig<B> - + TakeVecZnxDft<B> - + TakeVecZnx - + ScratchAvailable - + TakeVecZnxSlice - + TakeMatZnx - + TakeSlice, - BlindRotationKeyPrepared<DBrk, BRA, B>: BlincRotationExecute<B>, + R: GGSWToMut, + L: LWEToRef, + D: DataRef, + M: ModuleN + + LookupTableFactory + + BlindRotationExecute<BRA, BE> + + GLWETrace<BE> + + GLWEPacking<BE> + + GGSWFromGGLWE<BE> + + GLWESecretPreparedFactory<BE> + + GLWEDecrypt<BE>, + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - use poulpy_core::layouts::LWEInfos; + let res: &mut GGSW<&mut [u8]> = &mut res.to_mut(); + let lwe: &LWE<&[u8]> = &lwe.to_ref(); - assert_eq!(res.n(), key.brk.n()); - assert_eq!(lwe.base2k(), key.brk.base2k()); - assert_eq!(res.base2k(), key.brk.base2k()); - } + assert_eq!(res.n(), key.brk.n()); + assert_eq!(lwe.base2k(), key.brk.base2k()); + assert_eq!(res.base2k(), key.brk.base2k()); let n: usize = res.n().into(); let base2k: usize = res.base2k().into();@@ -203,8 +249,15 @@ });
}); } + let lut_infos: LookUpTableLayout = LookUpTableLayout { + n: module.n().into(), + extension_factor, + k: (base2k * dnum).into(), + base2k: base2k.into(), + }; + // Lut precision, basically must be able to hold the decomposition power basis of the GGSW - let mut lut: LookUpTable = LookUpTable::alloc(module, base2k, base2k * dnum, extension_factor); + let mut lut: LookupTable = LookupTable::alloc(&lut_infos); lut.set(module, &f, base2k * dnum); if to_exponent {@@ -212,9 +265,9 @@ lut.set_rotation_direction(LookUpTableRotationDirection::Right);
} // TODO: separate GGSW k from output of blind rotation k - let (mut res_glwe, scratch_1) = scratch.take_glwe_ct(res); + let (mut res_glwe, scratch_1) = scratch.take_glwe(res); - let gglwe_infos: GGLWECiphertextLayout = GGLWECiphertextLayout { + let gglwe_infos: GGLWELayout = GGLWELayout { n: n.into(), base2k: base2k.into(), k: k.into(),@@ -233,7 +286,7 @@
let log_gap_in: usize = (usize::BITS - (gap * alpha - 1).leading_zeros()) as _; (0..dnum).for_each(|i| { - let mut tmp_glwe: GLWECiphertext<&mut [u8]> = tmp_gglwe.at_mut(i, 0); + let mut tmp_glwe: GLWE<&mut [u8]> = tmp_gglwe.at_mut(i, 0); if to_exponent { // Isolates i-th LUT and moves coefficients according to requested gap.@@ -251,8 +304,14 @@ } else {
tmp_glwe.trace(module, 0, module.log_n(), &res_glwe, &key.atk, scratch_2); } + // let sk_glwe: &poulpy_core::layouts::GLWESecret<&[u8]> = &sk_glwe.to_ref(); + // let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, sk_glwe.rank()); + // let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&res_glwe); + // res_glwe.decrypt(module, &mut pt, &sk_glwe_prepared, scratch_2); + // println!("pt[{i}]: {}", pt); + if i < dnum { - res_glwe.rotate_inplace(module, -(gap as i64), scratch_2); + module.glwe_rotate_inplace(-(gap as i64), &mut res_glwe, scratch_2); } });@@ -261,49 +320,27 @@ res.from_gglwe(module, &tmp_gglwe, &key.tsk, scratch_2);
} #[allow(clippy::too_many_arguments)] -fn post_process<DataRes, DataA, B: Backend>( - module: &Module<B>, - res: &mut GLWECiphertext<DataRes>, - a: &GLWECiphertext<DataA>, +fn post_process<R, A, M, BE: Backend>( + module: &M, + res: &mut R, + a: &A, log_gap_in: usize, log_gap_out: usize, log_domain: usize, - auto_keys: &HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>>, - scratch: &mut Scratch<B>, + auto_keys: &HashMap<i64, GLWEAutomorphismKeyPrepared<Vec<u8>, BE>>, + scratch: &mut Scratch<BE>, ) where - DataRes: DataMut, - DataA: DataRef, - Module<B>: VecZnxRotateInplace<B> - + VecZnxNormalizeInplace<B> - + VecZnxNormalizeTmpBytes - + VecZnxSwitchRing - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxSub - + VecZnxAddInplace - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxSubInplace - + VecZnxDftAllocBytes - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxRotate - + VecZnxNormalize<B>, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx, + R: GLWEToMut, + A: GLWEToRef, + M: ModuleLogN + GLWETrace<BE> + GLWEPacking<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); + let log_n: usize = module.log_n(); - let mut cts: HashMap<usize, &mut GLWECiphertext<Vec<u8>>> = HashMap::new(); + let mut cts: HashMap<usize, &mut GLWE<Vec<u8>>> = HashMap::new(); // First partial trace, vanishes all coefficients which are not multiples of gap_in // [1, 1, 1, 1, 0, 0, 0, ..., 0, 0, -1, -1, -1, -1] -> [1, 0, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0]@@ -322,11 +359,11 @@ if log_gap_in != log_gap_out {
let steps: usize = 1 << log_domain; // TODO: from Scratch - let mut cts_vec: Vec<GLWECiphertext<Vec<u8>>> = Vec::new(); + let mut cts_vec: Vec<GLWE<Vec<u8>>> = Vec::new(); for i in 0..steps { if i != 0 { - res.rotate_inplace(module, -(1 << log_gap_in), scratch); + module.glwe_rotate_inplace(-(1 << log_gap_in), res, scratch); } cts_vec.push(res.to_owned_deep()); }@@ -335,8 +372,9 @@ for (i, ct) in cts_vec.iter_mut().enumerate().take(steps) {
cts.insert(i * (1 << log_gap_out), ct); } - glwe_packing(module, &mut cts, log_gap_out, auto_keys, scratch); - let packed: &mut GLWECiphertext<Vec<u8>> = cts.remove(&0).unwrap(); + module.glwe_pack(&mut cts, log_gap_out, auto_keys, scratch); + + let packed: &mut GLWE<Vec<u8>> = cts.remove(&0).unwrap(); res.trace( module, log_n - log_gap_out,
@@ -1,42 +1,38 @@
-use poulpy_core::layouts::{ - GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWEInfos, GGLWETensorKey, GGLWETensorKeyLayout, GGSWInfos, - GLWECiphertext, GLWEInfos, GLWESecret, LWEInfos, LWESecret, - prepared::{GGLWEAutomorphismKeyPrepared, GGLWETensorKeyPrepared, GLWESecretPrepared, PrepareAlloc}, +use poulpy_core::{ + Distribution, GLWEAutomorphismKeyEncryptSk, GLWETensorKeyEncryptSk, GetDistribution, ScratchTakeCore, + layouts::{ + GGLWEInfos, GGSWInfos, GLWEAutomorphismKey, GLWEAutomorphismKeyLayout, GLWEInfos, GLWESecretPreparedFactory, + GLWESecretToRef, GLWETensorKey, GLWETensorKeyLayout, LWEInfos, LWESecretToRef, prepared::GLWESecretPrepared, + }, + trace_galois_elements, }; use std::collections::HashMap; use poulpy_hal::{ - api::{ - ScratchAvailable, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, - TakeSvpPPol, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, - VecZnxAutomorphism, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, - VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, - VecZnxSwitchRing, VmpPMatAlloc, VmpPrepare, - }, - layouts::{Backend, Data, DataRef, Module, Scratch}, + layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, source::Source, }; use crate::tfhe::blind_rotation::{ - BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, BlindRotationKeyInfos, - BlindRotationKeyLayout, BlindRotationKeyPrepared, + BlindRotationAlgo, BlindRotationKey, BlindRotationKeyEncryptSk, BlindRotationKeyFactory, BlindRotationKeyInfos, + BlindRotationKeyLayout, }; pub trait CircuitBootstrappingKeyInfos { fn brk_infos(&self) -> BlindRotationKeyLayout; - fn atk_infos(&self) -> GGLWEAutomorphismKeyLayout; - fn tsk_infos(&self) -> GGLWETensorKeyLayout; + fn atk_infos(&self) -> GLWEAutomorphismKeyLayout; + fn tsk_infos(&self) -> GLWETensorKeyLayout; } #[derive(Debug, Clone, Copy)] pub struct CircuitBootstrappingKeyLayout { pub layout_brk: BlindRotationKeyLayout, - pub layout_atk: GGLWEAutomorphismKeyLayout, - pub layout_tsk: GGLWETensorKeyLayout, + pub layout_atk: GLWEAutomorphismKeyLayout, + pub layout_tsk: GLWETensorKeyLayout, } impl CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyLayout { - fn atk_infos(&self) -> GGLWEAutomorphismKeyLayout { + fn atk_infos(&self) -> GLWEAutomorphismKeyLayout { self.layout_atk }@@ -44,96 +40,117 @@ fn brk_infos(&self) -> BlindRotationKeyLayout {
self.layout_brk } - fn tsk_infos(&self) -> GGLWETensorKeyLayout { + fn tsk_infos(&self) -> GLWETensorKeyLayout { self.layout_tsk } } -pub trait CircuitBootstrappingKeyEncryptSk<B: Backend> { +pub trait CircuitBootstrappingKeyEncryptSk<BRA: BlindRotationAlgo, BE: Backend> { #[allow(clippy::too_many_arguments)] - fn encrypt_sk<DLwe, DGlwe, INFOS>( - module: &Module<B>, - sk_lwe: &LWESecret<DLwe>, - sk_glwe: &GLWESecret<DGlwe>, - cbt_infos: &INFOS, + fn circuit_bootstrapping_key_encrypt_sk<D, S0, S1>( + &self, + res: &mut CircuitBootstrappingKey<D, BRA>, + sk_lwe: &S0, + sk_glwe: &S1, source_xa: &mut Source, source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) -> Self + scratch: &mut Scratch<BE>, + ) where + D: DataMut, + S0: LWESecretToRef + GetDistribution + LWEInfos, + S1: GLWESecretToRef + GLWEInfos + GetDistribution; +} + +impl<BRA: BlindRotationAlgo> CircuitBootstrappingKey<Vec<u8>, BRA> { + pub fn alloc_from_infos<A>(infos: &A) -> Self where - INFOS: CircuitBootstrappingKeyInfos, - DLwe: DataRef, - DGlwe: DataRef; + A: CircuitBootstrappingKeyInfos, + BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, + { + let atk_infos: &GLWEAutomorphismKeyLayout = &infos.atk_infos(); + let brk_infos: &BlindRotationKeyLayout = &infos.brk_infos(); + let trk_infos: &GLWETensorKeyLayout = &infos.tsk_infos(); + let gal_els: Vec<i64> = trace_galois_elements(atk_infos.log_n(), 2 * atk_infos.n().as_usize() as i64); + + Self { + brk: <BlindRotationKey<Vec<u8>, BRA> as BlindRotationKeyFactory<BRA>>::blind_rotation_key_alloc(brk_infos), + atk: gal_els + .iter() + .map(|&gal_el| { + let key = GLWEAutomorphismKey::alloc_from_infos(atk_infos); + (gal_el, key) + }) + .collect(), + tsk: GLWETensorKey::alloc_from_infos(trk_infos), + } + } } pub struct CircuitBootstrappingKey<D: Data, BRA: BlindRotationAlgo> { pub(crate) brk: BlindRotationKey<D, BRA>, - pub(crate) tsk: GGLWETensorKey<Vec<u8>>, - pub(crate) atk: HashMap<i64, GGLWEAutomorphismKey<Vec<u8>>>, + pub(crate) tsk: GLWETensorKey<Vec<u8>>, + pub(crate) atk: HashMap<i64, GLWEAutomorphismKey<Vec<u8>>>, } -impl<BRA: BlindRotationAlgo, B: Backend> CircuitBootstrappingKeyEncryptSk<B> for CircuitBootstrappingKey<Vec<u8>, BRA> +impl<D: DataMut, BRA: BlindRotationAlgo> CircuitBootstrappingKey<D, BRA> { + pub fn encrypt_sk<M, S0, S1, BE: Backend>( + &mut self, + module: &M, + sk_lwe: &S0, + sk_glwe: &S1, + source_xa: &mut Source, + source_xe: &mut Source, + scratch: &mut Scratch<BE>, + ) where + S0: LWESecretToRef + GetDistribution + LWEInfos, + S1: GLWESecretToRef + GLWEInfos + GetDistribution, + M: CircuitBootstrappingKeyEncryptSk<BRA, BE>, + { + module.circuit_bootstrapping_key_encrypt_sk(self, sk_lwe, sk_glwe, source_xa, source_xe, scratch); + } +} + +impl<BRA: BlindRotationAlgo, BE: Backend> CircuitBootstrappingKeyEncryptSk<BRA, BE> for Module<BE> where - BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>, - Module<B>: SvpApplyDftToDft<B> - + VecZnxIdftApplyTmpA<B> - + VecZnxAddScalarInplace - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxFillUniform - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalizeInplace<B> - + VecZnxAddNormal - + VecZnxNormalize<B> - + VecZnxSub - + SvpPrepare<B> - + VecZnxSwitchRing - + SvpPPolAllocBytes - + SvpPPolAlloc<B> - + VecZnxAutomorphism, - Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeSvpPPol<B> + TakeVecZnxBig<B>, + Self: GLWETensorKeyEncryptSk<BE> + + BlindRotationKeyEncryptSk<BRA, BE> + + GLWEAutomorphismKeyEncryptSk<BE> + + GLWESecretPreparedFactory<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { - fn encrypt_sk<DLwe, DGlwe, INFOS>( - module: &Module<B>, - sk_lwe: &LWESecret<DLwe>, - sk_glwe: &GLWESecret<DGlwe>, - cbt_infos: &INFOS, + fn circuit_bootstrapping_key_encrypt_sk<D, S0, S1>( + &self, + res: &mut CircuitBootstrappingKey<D, BRA>, + sk_lwe: &S0, + sk_glwe: &S1, source_xa: &mut Source, source_xe: &mut Source, - scratch: &mut Scratch<B>, - ) -> Self - where - INFOS: CircuitBootstrappingKeyInfos, - DLwe: DataRef, - DGlwe: DataRef, + scratch: &mut Scratch<BE>, + ) where + D: DataMut, + S0: LWESecretToRef + GetDistribution + LWEInfos, + S1: GLWESecretToRef + GLWEInfos + GetDistribution, { - assert_eq!(sk_lwe.n(), cbt_infos.brk_infos().n_lwe()); - assert_eq!(sk_glwe.n(), cbt_infos.brk_infos().n_glwe()); - assert_eq!(sk_glwe.n(), cbt_infos.atk_infos().n()); - assert_eq!(sk_glwe.n(), cbt_infos.tsk_infos().n()); + let brk_infos: &BlindRotationKeyLayout = &res.brk_infos(); + let atk_infos: &GLWEAutomorphismKeyLayout = &res.atk_infos(); + let tsk_infos: &GLWETensorKeyLayout = &res.tsk_infos(); + + assert_eq!(sk_lwe.n(), brk_infos.n_lwe()); + assert_eq!(sk_glwe.n(), brk_infos.n_glwe()); + assert_eq!(sk_glwe.n(), atk_infos.n()); + assert_eq!(sk_glwe.n(), tsk_infos.n()); - let atk_infos: GGLWEAutomorphismKeyLayout = cbt_infos.atk_infos(); - let brk_infos: BlindRotationKeyLayout = cbt_infos.brk_infos(); - let trk_infos: GGLWETensorKeyLayout = cbt_infos.tsk_infos(); + assert!(sk_glwe.dist() != &Distribution::NONE); - let mut auto_keys: HashMap<i64, GGLWEAutomorphismKey<Vec<u8>>> = HashMap::new(); - let gal_els: Vec<i64> = GLWECiphertext::trace_galois_elements(module); - gal_els.iter().for_each(|gal_el| { - let mut key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&atk_infos); - key.encrypt_sk(module, *gal_el, sk_glwe, source_xa, source_xe, scratch); - auto_keys.insert(*gal_el, key); - }); + for (p, atk) in res.atk.iter_mut() { + atk.encrypt_sk(self, *p, sk_glwe, source_xa, source_xe, scratch); + } - let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch); + let mut sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(self, brk_infos.rank()); + sk_glwe_prepared.prepare(self, sk_glwe); - let mut brk: BlindRotationKey<Vec<u8>, BRA> = BlindRotationKey::<Vec<u8>, BRA>::alloc(&brk_infos); - brk.encrypt_sk( - module, + res.brk.encrypt_sk( + self, &sk_glwe_prepared, sk_lwe, source_xa,@@ -141,27 +158,15 @@ source_xe,
scratch, ); - let mut tsk: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&trk_infos); - tsk.encrypt_sk(module, sk_glwe, source_xa, source_xe, scratch); - - Self { - brk, - atk: auto_keys, - tsk, - } + res.tsk + .encrypt_sk(self, sk_glwe, source_xa, source_xe, scratch); } } -pub struct CircuitBootstrappingKeyPrepared<D: Data, BRA: BlindRotationAlgo, B: Backend> { - pub(crate) brk: BlindRotationKeyPrepared<D, BRA, B>, - pub(crate) tsk: GGLWETensorKeyPrepared<Vec<u8>, B>, - pub(crate) atk: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>>, -} - -impl<D: DataRef, BRA: BlindRotationAlgo, B: Backend> CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyPrepared<D, BRA, B> { - fn atk_infos(&self) -> GGLWEAutomorphismKeyLayout { +impl<D: DataRef, BRA: BlindRotationAlgo> CircuitBootstrappingKeyInfos for CircuitBootstrappingKey<D, BRA> { + fn atk_infos(&self) -> GLWEAutomorphismKeyLayout { let (_, atk) = self.atk.iter().next().expect("atk is empty"); - GGLWEAutomorphismKeyLayout { + GLWEAutomorphismKeyLayout { n: atk.n(), base2k: atk.base2k(), k: atk.k(),@@ -182,8 +187,8 @@ rank: self.brk.rank(),
} } - fn tsk_infos(&self) -> GGLWETensorKeyLayout { - GGLWETensorKeyLayout { + fn tsk_infos(&self) -> GLWETensorKeyLayout { + GLWETensorKeyLayout { n: self.tsk.n(), base2k: self.tsk.base2k(), k: self.tsk.k(),@@ -193,22 +198,3 @@ rank: self.tsk.rank(),
} } } - -impl<D: DataRef, BRA: BlindRotationAlgo, B: Backend> PrepareAlloc<B, CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, B>> - for CircuitBootstrappingKey<D, BRA> -where - Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>, - BlindRotationKey<D, BRA>: PrepareAlloc<B, BlindRotationKeyPrepared<Vec<u8>, BRA, B>>, - GGLWETensorKey<D>: PrepareAlloc<B, GGLWETensorKeyPrepared<Vec<u8>, B>>, - GGLWEAutomorphismKey<D>: PrepareAlloc<B, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>>, -{ - fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, B> { - let brk: BlindRotationKeyPrepared<Vec<u8>, BRA, B> = self.brk.prepare_alloc(module, scratch); - let tsk: GGLWETensorKeyPrepared<Vec<u8>, B> = self.tsk.prepare_alloc(module, scratch); - let mut atk: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new(); - for (key, value) in &self.atk { - atk.insert(*key, value.prepare_alloc(module, scratch)); - } - CircuitBootstrappingKeyPrepared { brk, tsk, atk } - } -}
@@ -0,0 +1,13 @@
+use std::collections::HashMap; + +use poulpy_core::layouts::{GLWEAutomorphismKeyCompressed, GLWETensorKeyCompressed}; +use poulpy_hal::layouts::Data; + +use crate::tfhe::blind_rotation::{BlindRotationAlgo, BlindRotationKeyCompressed}; + +#[allow(dead_code)] +pub struct CircuitBootstrappingKey<D: Data, BRA: BlindRotationAlgo> { + pub(crate) brk: BlindRotationKeyCompressed<D, BRA>, + pub(crate) tsk: GLWETensorKeyCompressed<Vec<u8>>, + pub(crate) atk: HashMap<i64, GLWEAutomorphismKeyCompressed<Vec<u8>>>, +}
@@ -0,0 +1,146 @@
+use poulpy_core::{ + layouts::{ + GGLWEInfos, GGSWInfos, GLWEAutomorphismKeyLayout, GLWEAutomorphismKeyPreparedFactory, GLWEInfos, GLWETensorKeyLayout, + GLWETensorKeyPreparedFactory, LWEInfos, + prepared::{GLWEAutomorphismKeyPrepared, GLWETensorKeyPrepared}, + }, + trace_galois_elements, +}; +use std::collections::HashMap; + +use poulpy_hal::layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}; + +use crate::tfhe::{ + blind_rotation::{ + BlindRotationAlgo, BlindRotationKeyInfos, BlindRotationKeyLayout, BlindRotationKeyPrepared, + BlindRotationKeyPreparedFactory, + }, + circuit_bootstrapping::{CircuitBootstrappingKey, CircuitBootstrappingKeyInfos}, +}; + +impl<BRA: BlindRotationAlgo, BE: Backend> CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, BE> { + pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, BE> + where + A: CircuitBootstrappingKeyInfos, + M: CircuitBootstrappingKeyPreparedFactory<BRA, BE>, + { + module.circuit_bootstrapping_key_prepared_alloc_from_infos(infos) + } +} + +impl<D: DataMut, BRA: BlindRotationAlgo, BE: Backend> CircuitBootstrappingKeyPrepared<D, BRA, BE> { + pub fn prepare<DR, M>(&mut self, module: &M, other: &CircuitBootstrappingKey<DR, BRA>, scratch: &mut Scratch<BE>) + where + DR: DataRef, + M: CircuitBootstrappingKeyPreparedFactory<BRA, BE>, + { + module.circuit_bootstrapping_key_prepare(self, other, scratch); + } +} + +impl<BE: Backend, BRA: BlindRotationAlgo> CircuitBootstrappingKeyPreparedFactory<BRA, BE> for Module<BE> where + Self: Sized + + BlindRotationKeyPreparedFactory<BRA, BE> + + GLWETensorKeyPreparedFactory<BE> + + GLWEAutomorphismKeyPreparedFactory<BE> +{ +} + +pub trait CircuitBootstrappingKeyPreparedFactory<BRA: BlindRotationAlgo, BE: Backend> +where + Self: Sized + + BlindRotationKeyPreparedFactory<BRA, BE> + + GLWETensorKeyPreparedFactory<BE> + + GLWEAutomorphismKeyPreparedFactory<BE>, +{ + fn circuit_bootstrapping_key_prepared_alloc_from_infos<A>( + &self, + infos: &A, + ) -> CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, BE> + where + A: CircuitBootstrappingKeyInfos, + { + let atk_infos: &GLWEAutomorphismKeyLayout = &infos.atk_infos(); + let gal_els: Vec<i64> = trace_galois_elements(atk_infos.log_n(), 2 * atk_infos.n().as_usize() as i64); + + CircuitBootstrappingKeyPrepared { + brk: BlindRotationKeyPrepared::alloc(self, &infos.brk_infos()), + tsk: GLWETensorKeyPrepared::alloc_from_infos(self, &infos.tsk_infos()), + atk: gal_els + .iter() + .map(|&gal_el| { + let key = GLWEAutomorphismKeyPrepared::alloc_from_infos(self, atk_infos); + (gal_el, key) + }) + .collect(), + } + } + + fn circuit_bootstrapping_key_prepare_tmp_bytes<A>(&self, infos: &A) -> usize + where + A: CircuitBootstrappingKeyInfos, + { + self.blind_rotation_key_prepare_tmp_bytes(&infos.brk_infos()) + .max(self.prepare_tensor_key_tmp_bytes(&infos.tsk_infos())) + .max(self.prepare_glwe_automorphism_key_tmp_bytes(&infos.atk_infos())) + } + + fn circuit_bootstrapping_key_prepare<DM, DR>( + &self, + res: &mut CircuitBootstrappingKeyPrepared<DM, BRA, BE>, + other: &CircuitBootstrappingKey<DR, BRA>, + scratch: &mut Scratch<BE>, + ) where + DM: DataMut, + DR: DataRef, + { + res.brk.prepare(self, &other.brk, scratch); + res.tsk.prepare(self, &other.tsk, scratch); + + for (k, a) in res.atk.iter_mut() { + a.prepare(self, other.atk.get(k).unwrap(), scratch); + } + } +} + +pub struct CircuitBootstrappingKeyPrepared<D: Data, BRA: BlindRotationAlgo, B: Backend> { + pub(crate) brk: BlindRotationKeyPrepared<D, BRA, B>, + pub(crate) tsk: GLWETensorKeyPrepared<Vec<u8>, B>, + pub(crate) atk: HashMap<i64, GLWEAutomorphismKeyPrepared<Vec<u8>, B>>, +} + +impl<D: DataRef, BRA: BlindRotationAlgo, B: Backend> CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyPrepared<D, BRA, B> { + fn atk_infos(&self) -> GLWEAutomorphismKeyLayout { + let (_, atk) = self.atk.iter().next().expect("atk is empty"); + GLWEAutomorphismKeyLayout { + n: atk.n(), + base2k: atk.base2k(), + k: atk.k(), + dnum: atk.dnum(), + dsize: atk.dsize(), + rank: atk.rank(), + } + } + + fn brk_infos(&self) -> BlindRotationKeyLayout { + BlindRotationKeyLayout { + n_glwe: self.brk.n_glwe(), + n_lwe: self.brk.n_lwe(), + base2k: self.brk.base2k(), + k: self.brk.k(), + dnum: self.brk.dnum(), + rank: self.brk.rank(), + } + } + + fn tsk_infos(&self) -> GLWETensorKeyLayout { + GLWETensorKeyLayout { + n: self.tsk.n(), + base2k: self.tsk.base2k(), + k: self.tsk.k(), + dnum: self.tsk.dnum(), + dsize: self.tsk.dsize(), + rank: self.tsk.rank(), + } + } +}
@@ -1,34 +1,12 @@
mod circuit; mod key; +mod key_compressed; +mod key_prepared; + +#[cfg(test)] pub mod tests; pub use circuit::*; pub use key::*; - -use poulpy_core::layouts::{GGSWCiphertext, LWECiphertext}; - -use poulpy_hal::layouts::{Backend, DataMut, DataRef, Module, Scratch}; - -pub trait CirtuitBootstrappingExecute<B: Backend> { - fn execute_to_constant<DM: DataMut, DR: DataRef>( - &self, - module: &Module<B>, - res: &mut GGSWCiphertext<DM>, - lwe: &LWECiphertext<DR>, - log_domain: usize, - extension_factor: usize, - scratch: &mut Scratch<B>, - ); - - #[allow(clippy::too_many_arguments)] - fn execute_to_exponent<DM: DataMut, DR: DataRef>( - &self, - module: &Module<B>, - log_gap_out: usize, - res: &mut GGSWCiphertext<DM>, - lwe: &LWECiphertext<DR>, - log_domain: usize, - extension_factor: usize, - scratch: &mut Scratch<B>, - ); -} +// pub use key_compressed::*; +pub use key_prepared::*;
@@ -1,110 +1,49 @@
use std::time::Instant; use poulpy_hal::{ - api::{ - ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, - SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace, - VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, - VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAddInplace, - VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxFillUniform, VecZnxIdftApplyConsume, - VecZnxIdftApplyTmpA, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, - VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, - VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, ZnAddNormal, ZnFillUniform, - ZnNormalizeInplace, - }, - layouts::{Backend, Module, ScalarZnx, ScratchOwned, ZnxView, ZnxViewMut}, - oep::{ - ScratchAvailableImpl, ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeMatZnxImpl, TakeScalarZnxImpl, TakeSliceImpl, - TakeSvpPPolImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl, TakeVecZnxDftSliceImpl, TakeVecZnxImpl, TakeVecZnxSliceImpl, - }, + api::{ModuleN, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxRotateInplace}, + layouts::{Backend, ScalarZnx, Scratch, ScratchOwned, ZnxView, ZnxViewMut}, source::Source, }; use crate::tfhe::{ - blind_rotation::{ - BlincRotationExecute, BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, - BlindRotationKeyLayout, BlindRotationKeyPrepared, - }, + blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyFactory, BlindRotationKeyLayout}, circuit_bootstrapping::{ CircuitBootstrappingKey, CircuitBootstrappingKeyEncryptSk, CircuitBootstrappingKeyLayout, - CircuitBootstrappingKeyPrepared, CirtuitBootstrappingExecute, + CircuitBootstrappingKeyPrepared, CircuitBootstrappingKeyPreparedFactory, CirtuitBootstrappingExecute, }, }; -use poulpy_core::layouts::{ - Dsize, GGLWEAutomorphismKeyLayout, GGLWETensorKeyLayout, GGSWCiphertextLayout, LWECiphertextLayout, prepared::PrepareAlloc, +use poulpy_core::{ + GGSWNoise, GLWEDecrypt, GLWEEncryptSk, GLWEExternalProduct, LWEEncryptSk, ScratchTakeCore, + layouts::{ + Dsize, GGSWLayout, GGSWPreparedFactory, GLWEAutomorphismKeyLayout, GLWESecretPreparedFactory, GLWETensorKeyLayout, + LWELayout, + }, }; use poulpy_core::layouts::{ - GGSWCiphertext, GLWECiphertext, GLWEPlaintext, GLWESecret, LWECiphertext, LWEPlaintext, LWESecret, - prepared::{GGSWCiphertextPrepared, GLWESecretPrepared}, + GGSW, GLWE, GLWEPlaintext, GLWESecret, LWE, LWEPlaintext, LWESecret, + prepared::{GGSWPrepared, GLWESecretPrepared}, }; -pub fn test_circuit_bootstrapping_to_exponent<B, BRA: BlindRotationAlgo>(module: &Module<B>) +pub fn test_circuit_bootstrapping_to_exponent<BE: Backend, M, BRA: BlindRotationAlgo>(module: &M) where - Module<B>: VecZnxFillUniform - + VecZnxAddNormal - + VecZnxNormalizeInplace<B> - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalize<B> - + VecZnxSub - + VecZnxAddScalarInplace - + VecZnxAutomorphism - + VecZnxSwitchRing - + VecZnxBigAllocBytes - + VecZnxIdftApplyTmpA<B> - + SvpApplyDftToDft<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VmpPMatAlloc<B> - + VmpPrepare<B> - + SvpPrepare<B> - + SvpPPolAlloc<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + SvpPPolAllocBytes - + VecZnxRotateInplace<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxRotateInplaceTmpBytes - + VecZnxBigAllocBytes - + VecZnxDftAddInplace<B> - + VecZnxRotate - + ZnFillUniform - + ZnAddNormal - + ZnNormalizeInplace<B>, - B: Backend - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + TakeVecZnxDftImpl<B> - + ScratchAvailableImpl<B> - + TakeVecZnxImpl<B> - + TakeScalarZnxImpl<B> - + TakeSvpPPolImpl<B> - + TakeVecZnxBigImpl<B> - + TakeVecZnxDftSliceImpl<B> - + TakeMatZnxImpl<B> - + TakeVecZnxSliceImpl<B> - + TakeSliceImpl<B>, - BlindRotationKey<Vec<u8>, BRA>: PrepareAlloc<B, BlindRotationKeyPrepared<Vec<u8>, BRA, B>>, - BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlincRotationExecute<B>, - BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>, + M: ModuleN + + GLWESecretPreparedFactory<BE> + + GLWEExternalProduct<BE> + + GLWEDecrypt<BE> + + LWEEncryptSk<BE> + + CircuitBootstrappingKeyEncryptSk<BRA, BE> + + CircuitBootstrappingKeyPreparedFactory<BRA, BE> + + CirtuitBootstrappingExecute<BRA, BE> + + GGSWPreparedFactory<BE> + + GGSWNoise<BE> + + GLWEEncryptSk<BE> + + VecZnxRotateInplace<BE>, + BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, // TODO find a way to remove this bound or move it to CBT KEY + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { let n_glwe: usize = module.n(); let base2k: usize = 17;@@ -128,7 +67,7 @@
let k_ggsw_res: usize = 4 * base2k; let rows_ggsw_res: usize = 2; - let lwe_infos: LWECiphertextLayout = LWECiphertextLayout { + let lwe_infos: LWELayout = LWELayout { n: n_lwe.into(), k: k_lwe_ct.into(), base2k: base2k.into(),@@ -143,7 +82,7 @@ k: k_brk.into(),
dnum: rows_brk.into(), rank: rank.into(), }, - layout_atk: GGLWEAutomorphismKeyLayout { + layout_atk: GLWEAutomorphismKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_atk.into(),@@ -151,7 +90,7 @@ dnum: rows_atk.into(),
rank: rank.into(), dsize: Dsize(1), }, - layout_tsk: GGLWETensorKeyLayout { + layout_tsk: GLWETensorKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_tsk.into(),@@ -161,7 +100,7 @@ rank: rank.into(),
}, }; - let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_infos: GGSWLayout = GGSWLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_ggsw_res.into(),@@ -170,7 +109,7 @@ dsize: Dsize(1),
rank: rank.into(), }; - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(1 << 23); + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 23); let mut source_xs: Source = Source::new([1u8; 32]); let mut source_xa: Source = Source::new([1u8; 32]);@@ -179,38 +118,44 @@
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe.into()); sk_lwe.fill_binary_block(block_size, &mut source_xs); - let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n_glwe.into(), rank.into()); + let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n_glwe.into(), rank.into()); sk_glwe.fill_ternary_prob(0.5, &mut source_xs); - let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow()); + let mut sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_glwe_prepared.prepare(module, &sk_glwe); let data: i64 = 1; - let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_with(base2k.into(), k_lwe_pt.into()); + let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(base2k.into(), k_lwe_pt.into()); pt_lwe.encode_i64(data, (k_lwe_pt + 1).into()); println!("pt_lwe: {pt_lwe}"); - let mut ct_lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos); + let mut ct_lwe: LWE<Vec<u8>> = LWE::alloc_from_infos(&lwe_infos); ct_lwe.encrypt_sk(module, &pt_lwe, &sk_lwe, &mut source_xa, &mut source_xe); let now: Instant = Instant::now(); - let cbt_key: CircuitBootstrappingKey<Vec<u8>, BRA> = CircuitBootstrappingKey::encrypt_sk( + let mut cbt_key: CircuitBootstrappingKey<Vec<u8>, BRA> = CircuitBootstrappingKey::alloc_from_infos(&cbt_infos); + println!("CBT-ALLOC: {} ms", now.elapsed().as_millis()); + + let now: Instant = Instant::now(); + cbt_key.encrypt_sk( module, &sk_lwe, &sk_glwe, - &cbt_infos, &mut source_xa, &mut source_xe, scratch.borrow(), ); - println!("CBT-KGEN: {} ms", now.elapsed().as_millis()); + println!("CBT-ENCRYPT: {} ms", now.elapsed().as_millis()); - let mut res: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos); + let mut res: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_infos); let log_gap_out = 1; - let cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, B> = cbt_key.prepare_alloc(module, scratch.borrow()); + let mut cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, BE> = + CircuitBootstrappingKeyPrepared::alloc_from_infos(module, &cbt_infos); + cbt_prepared.prepare(module, &cbt_key, scratch.borrow()); let now: Instant = Instant::now(); cbt_prepared.execute_to_exponent(@@ -236,8 +181,8 @@ );
res.print_noise(module, &sk_glwe_prepared, &pt_ggsw); - let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&ggsw_infos); - let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ggsw_infos); + let mut ct_glwe: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&ggsw_infos); + let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&ggsw_infos); pt_glwe.data.at_mut(0, 0)[0] = 1 << (base2k - 2); ct_glwe.encrypt_sk(@@ -249,11 +194,12 @@ &mut source_xe,
scratch.borrow(), ); - let res_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = res.prepare_alloc(module, scratch.borrow()); + let mut res_prepared: GGSWPrepared<Vec<u8>, BE> = GGSWPrepared::alloc_from_infos(module, &res); + res_prepared.prepare(module, &res, scratch.borrow()); ct_glwe.external_product_inplace(module, &res_prepared, scratch.borrow()); - let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ggsw_infos); + let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&ggsw_infos); ct_glwe.decrypt(module, &mut pt_res, &sk_glwe_prepared, scratch.borrow()); // Parameters are set such that the first limb should be noiseless.@@ -262,76 +208,28 @@ pt_want[data as usize * (1 << log_gap_out)] = pt_glwe.data.at(0, 0)[0];
assert_eq!(pt_res.data.at(0, 0), pt_want); } -pub fn test_circuit_bootstrapping_to_constant<B, BRA: BlindRotationAlgo>(module: &Module<B>) +pub fn test_circuit_bootstrapping_to_constant<BE: Backend, M, BRA: BlindRotationAlgo>(module: &M) where - Module<B>: VecZnxFillUniform - + VecZnxAddNormal - + VecZnxNormalizeInplace<B> - + VecZnxDftAllocBytes - + VecZnxBigNormalize<B> - + VecZnxDftApply<B> - + SvpApplyDftToDftInplace<B> - + VecZnxIdftApplyConsume<B> - + VecZnxNormalizeTmpBytes - + VecZnxSubInplace - + VecZnxAddInplace - + VecZnxNormalize<B> - + VecZnxSub - + VecZnxAddScalarInplace - + VecZnxAutomorphism - + VecZnxSwitchRing - + VecZnxBigAllocBytes - + VecZnxIdftApplyTmpA<B> - + SvpApplyDftToDft<B> - + VecZnxBigAddInplace<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigAlloc<B> - + VecZnxDftAlloc<B> - + VecZnxBigNormalizeTmpBytes - + VmpPMatAlloc<B> - + VmpPrepare<B> - + SvpPrepare<B> - + SvpPPolAlloc<B> - + VmpApplyDftToDftTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + SvpPPolAllocBytes - + VecZnxRotateInplace<B> - + VecZnxBigAutomorphismInplace<B> - + VecZnxRotateInplaceTmpBytes - + VecZnxRshInplace<B> - + VecZnxDftCopy<B> - + VecZnxNegateInplace - + VecZnxCopy - + VecZnxAutomorphismInplace<B> - + VecZnxBigSubSmallNegateInplace<B> - + VecZnxBigAllocBytes - + VecZnxDftAddInplace<B> - + VecZnxRotate - + ZnFillUniform - + ZnAddNormal - + ZnNormalizeInplace<B>, - B: Backend - + ScratchOwnedAllocImpl<B> - + ScratchOwnedBorrowImpl<B> - + TakeVecZnxDftImpl<B> - + ScratchAvailableImpl<B> - + TakeVecZnxImpl<B> - + TakeScalarZnxImpl<B> - + TakeSvpPPolImpl<B> - + TakeVecZnxBigImpl<B> - + TakeVecZnxDftSliceImpl<B> - + TakeMatZnxImpl<B> - + TakeVecZnxSliceImpl<B> - + TakeSliceImpl<B>, - BlindRotationKey<Vec<u8>, BRA>: PrepareAlloc<B, BlindRotationKeyPrepared<Vec<u8>, BRA, B>>, - BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlincRotationExecute<B>, - BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>, + M: ModuleN + + GLWESecretPreparedFactory<BE> + + GLWEExternalProduct<BE> + + GLWEDecrypt<BE> + + LWEEncryptSk<BE> + + CircuitBootstrappingKeyEncryptSk<BRA, BE> + + CircuitBootstrappingKeyPreparedFactory<BRA, BE> + + CirtuitBootstrappingExecute<BRA, BE> + + GGSWPreparedFactory<BE> + + GGSWNoise<BE> + + GLWEEncryptSk<BE> + + VecZnxRotateInplace<BE>, + BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyFactory<BRA>, // TODO find a way to remove this bound or move it to CBT KEY + ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { let n_glwe: usize = module.n(); let base2k: usize = 14; let extension_factor: usize = 1; - let rank: usize = 2; + let rank: usize = 1; let n_lwe: usize = 77; let k_lwe_pt: usize = 1;@@ -350,7 +248,7 @@
let k_ggsw_res: usize = 4 * base2k; let rows_ggsw_res: usize = 3; - let lwe_infos: LWECiphertextLayout = LWECiphertextLayout { + let lwe_infos: LWELayout = LWELayout { n: n_lwe.into(), k: k_lwe_ct.into(), base2k: base2k.into(),@@ -365,7 +263,7 @@ k: k_brk.into(),
dnum: rows_brk.into(), rank: rank.into(), }, - layout_atk: GGLWEAutomorphismKeyLayout { + layout_atk: GLWEAutomorphismKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_atk.into(),@@ -373,7 +271,7 @@ dnum: rows_atk.into(),
rank: rank.into(), dsize: Dsize(1), }, - layout_tsk: GGLWETensorKeyLayout { + layout_tsk: GLWETensorKeyLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_tsk.into(),@@ -383,7 +281,7 @@ rank: rank.into(),
}, }; - let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout { + let ggsw_infos: GGSWLayout = GGSWLayout { n: n_glwe.into(), base2k: base2k.into(), k: k_ggsw_res.into(),@@ -392,7 +290,7 @@ dsize: Dsize(1),
rank: rank.into(), }; - let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(1 << 23); + let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(1 << 23); let mut source_xs: Source = Source::new([1u8; 32]); let mut source_xa: Source = Source::new([1u8; 32]);@@ -401,36 +299,42 @@
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe.into()); sk_lwe.fill_binary_block(block_size, &mut source_xs); - let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n_glwe.into(), rank.into()); + let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n_glwe.into(), rank.into()); sk_glwe.fill_ternary_prob(0.5, &mut source_xs); - let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow()); + let mut sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, rank.into()); + sk_glwe_prepared.prepare(module, &sk_glwe); let data: i64 = 1; - let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_with(base2k.into(), k_lwe_pt.into()); + let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(base2k.into(), k_lwe_pt.into()); pt_lwe.encode_i64(data, (k_lwe_pt + 1).into()); println!("pt_lwe: {pt_lwe}"); - let mut ct_lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos); + let mut ct_lwe: LWE<Vec<u8>> = LWE::alloc_from_infos(&lwe_infos); ct_lwe.encrypt_sk(module, &pt_lwe, &sk_lwe, &mut source_xa, &mut source_xe); let now: Instant = Instant::now(); - let cbt_key: CircuitBootstrappingKey<Vec<u8>, BRA> = CircuitBootstrappingKey::encrypt_sk( + let mut cbt_key: CircuitBootstrappingKey<Vec<u8>, BRA> = CircuitBootstrappingKey::alloc_from_infos(&cbt_infos); + println!("CBT-ALLOC: {} ms", now.elapsed().as_millis()); + + let now: Instant = Instant::now(); + cbt_key.encrypt_sk( module, &sk_lwe, &sk_glwe, - &cbt_infos, &mut source_xa, &mut source_xe, scratch.borrow(), ); - println!("CBT-KGEN: {} ms", now.elapsed().as_millis()); + println!("CBT-ENCRYPT: {} ms", now.elapsed().as_millis()); - let mut res: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos); + let mut res: GGSW<Vec<u8>> = GGSW::alloc_from_infos(&ggsw_infos); - let cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, B> = cbt_key.prepare_alloc(module, scratch.borrow()); + let mut cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, BE> = + CircuitBootstrappingKeyPrepared::alloc_from_infos(module, &cbt_infos); + cbt_prepared.prepare(module, &cbt_key, scratch.borrow()); let now: Instant = Instant::now(); cbt_prepared.execute_to_constant(@@ -449,8 +353,8 @@ pt_ggsw.at_mut(0, 0)[0] = data;
res.print_noise(module, &sk_glwe_prepared, &pt_ggsw); - let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&ggsw_infos); - let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ggsw_infos); + let mut ct_glwe: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&ggsw_infos); + let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&ggsw_infos); pt_glwe.data.at_mut(0, 0)[0] = 1 << (base2k - k_lwe_pt - 1); ct_glwe.encrypt_sk(@@ -462,11 +366,12 @@ &mut source_xe,
scratch.borrow(), ); - let res_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = res.prepare_alloc(module, scratch.borrow()); + let mut res_prepared: GGSWPrepared<Vec<u8>, BE> = GGSWPrepared::alloc_from_infos(module, &res); + res_prepared.prepare(module, &res, scratch.borrow()); ct_glwe.external_product_inplace(module, &res_prepared, scratch.borrow()); - let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ggsw_infos); + let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&ggsw_infos); ct_glwe.decrypt(module, &mut pt_res, &sk_glwe_prepared, scratch.borrow()); // Parameters are set such that the first limb should be noiseless.
@@ -0,0 +1,21 @@
+use poulpy_backend::cpu_fft64_ref::FFT64Ref; +use poulpy_hal::{api::ModuleNew, layouts::Module}; + +use crate::tfhe::{ + blind_rotation::CGGI, + circuit_bootstrapping::tests::circuit_bootstrapping::{ + test_circuit_bootstrapping_to_constant, test_circuit_bootstrapping_to_exponent, + }, +}; + +#[test] +fn test_to_constant_cggi() { + let module: Module<FFT64Ref> = Module::<FFT64Ref>::new(256); + test_circuit_bootstrapping_to_constant::<FFT64Ref, _, CGGI>(&module); +} + +#[test] +fn test_to_exponent_cggi() { + let module: Module<FFT64Ref> = Module::<FFT64Ref>::new(256); + test_circuit_bootstrapping_to_exponent::<FFT64Ref, _, CGGI>(&module); +}
@@ -1,21 +0,0 @@
-use poulpy_backend::cpu_spqlios::FFT64Spqlios; -use poulpy_hal::{api::ModuleNew, layouts::Module}; - -use crate::tfhe::{ - blind_rotation::CGGI, - circuit_bootstrapping::tests::circuit_bootstrapping::{ - test_circuit_bootstrapping_to_constant, test_circuit_bootstrapping_to_exponent, - }, -}; - -#[test] -fn test_to_constant() { - let module: Module<FFT64Spqlios> = Module::<FFT64Spqlios>::new(256); - test_circuit_bootstrapping_to_constant::<FFT64Spqlios, CGGI>(&module); -} - -#[test] -fn test_to_exponent() { - let module: Module<FFT64Spqlios> = Module::<FFT64Spqlios>::new(256); - test_circuit_bootstrapping_to_exponent::<FFT64Spqlios, CGGI>(&module); -}
@@ -1,1 +0,0 @@
-mod fft64;
@@ -1,1 +0,0 @@
-mod cpu_spqlios;
@@ -1,4 +1,3 @@
pub mod circuit_bootstrapping; -#[cfg(test)] -mod implementation; +mod fft64;