arnaucube
arnaucube/poulpyPublic Self-hosted repository
Code organisation for glwe
Jean-Philippe Bossuat jeanphilippe.bossuat@gmail.com
Thu, 12 Jun 2025 15:46:05 +0200
commit

989ea077a9967a9875baf8f97aa759fd6e71dab3

parent

ec4253bb1cb056e674f8e35d9916a352a9e34a6c

M core/src/automorphism.rs → core/src/automorphism.rs

@@ -2,7 +2,7 @@ use backend::{Backend, FFT64, MatZnxDft, MatZnxDftOps, Module, ScalarZnxOps, Scratch, VecZnx, VecZnxDftOps, VecZnxOps, ZnxZero};

use sampling::source::Source; use crate::{ - GGLWECiphertext, GGSWCiphertext, GLWECiphertext, GLWECiphertextFourier, GLWESecret, GLWESwitchingKey, GetRow, Infos, + FourierGLWECiphertext, GGLWECiphertext, GGSWCiphertext, GLWECiphertext, GLWESecret, GLWESwitchingKey, GetRow, Infos, ScratchCore, SetRow, };

@@ -68,7 +68,7 @@ &self,

module: &Module<FFT64>, row_i: usize, col_j: usize, - res: &mut GLWECiphertextFourier<R, FFT64>, + res: &mut FourierGLWECiphertext<R, FFT64>, ) { module.mat_znx_dft_get_row(&mut res.data, &self.key.0.data, row_i, col_j); }

@@ -80,7 +80,7 @@ &mut self,

module: &Module<FFT64>, row_i: usize, col_j: usize, - a: &GLWECiphertextFourier<R, FFT64>, + a: &FourierGLWECiphertext<R, FFT64>, ) { module.mat_znx_dft_set_row(&mut self.key.0.data, row_i, col_j, &a.data); }

@@ -127,8 +127,8 @@ k_ksk: usize,

digits: usize, rank: usize, ) -> usize { - let tmp_dft: usize = GLWECiphertextFourier::bytes_of(module, basek, k_in, rank); - let tmp_idft: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank); + let tmp_dft: usize = FourierGLWECiphertext::bytes_of(module, basek, k_in, rank); + let tmp_idft: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank); let idft: usize = module.vec_znx_idft_tmp_bytes(); let keyswitch: usize = GLWECiphertext::keyswitch_inplace_scratch_space(module, basek, k_out, k_ksk, digits, rank); tmp_dft + tmp_idft + idft + keyswitch
M core/src/blind_rotation/key.rs → core/src/blind_rotation/key.rs

@@ -23,6 +23,10 @@ dist: SecretDistribution::NONE,

} } + pub fn generate_from_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize { + GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k, rank) + } + pub fn generate_from_sk<DataSkGLWE, DataSkLWE>( &mut self, module: &Module<FFT64>,
M core/src/elem.rs → core/src/elem.rs

@@ -1,6 +1,6 @@

use backend::{Backend, Module, ZnxInfos}; -use crate::GLWECiphertextFourier; +use crate::{FourierGLWECiphertext, div_ceil}; pub trait Infos { type Inner: ZnxInfos;

@@ -56,13 +56,13 @@ fn set_k(&mut self, k: usize);

} pub trait GetRow<B: Backend> { - fn get_row<R>(&self, module: &Module<B>, row_i: usize, col_j: usize, res: &mut GLWECiphertextFourier<R, B>) + fn get_row<R>(&self, module: &Module<B>, row_i: usize, col_j: usize, res: &mut FourierGLWECiphertext<R, B>) where R: AsMut<[u8]> + AsRef<[u8]>; } pub trait SetRow<B: Backend> { - fn set_row<R>(&mut self, module: &Module<B>, row_i: usize, col_j: usize, a: &GLWECiphertextFourier<R, B>) + fn set_row<R>(&mut self, module: &Module<B>, row_i: usize, col_j: usize, a: &FourierGLWECiphertext<R, B>) where R: AsRef<[u8]>; }
M core/src/gglwe_ciphertext.rs → core/src/gglwe.rs

@@ -4,7 +4,7 @@ ZnxInfos, ZnxZero,

}; use sampling::source::Source; -use crate::{GLWECiphertext, GLWECiphertextFourier, GLWESecret, GetRow, Infos, ScratchCore, SetRow}; +use crate::{FourierGLWECiphertext, GLWECiphertext, GLWESecret, GetRow, Infos, ScratchCore, SetRow, div_ceil}; pub struct GGLWECiphertext<C, B: Backend> { pub(crate) data: MatZnxDft<C, B>,

@@ -217,7 +217,7 @@ &self,

module: &Module<FFT64>, row_i: usize, col_j: usize, - res: &mut GLWECiphertextFourier<R, FFT64>, + res: &mut FourierGLWECiphertext<R, FFT64>, ) { module.mat_znx_dft_get_row(&mut res.data, &self.data, row_i, col_j); }

@@ -229,7 +229,7 @@ &mut self,

module: &Module<FFT64>, row_i: usize, col_j: usize, - a: &GLWECiphertextFourier<R, FFT64>, + a: &FourierGLWECiphertext<R, FFT64>, ) { module.mat_znx_dft_set_row(&mut self.data, row_i, col_j, &a.data); }
M core/src/ggsw_ciphertext.rs → core/src/ggsw.rs

@@ -6,8 +6,8 @@ };

use sampling::source::Source; use crate::{ - AutomorphismKey, GLWECiphertext, GLWECiphertextFourier, GLWESecret, GLWESwitchingKey, GetRow, Infos, ScratchCore, SetRow, - TensorKey, + AutomorphismKey, FourierGLWECiphertext, GLWECiphertext, GLWESecret, GLWESwitchingKey, GetRow, Infos, ScratchCore, SetRow, + TensorKey, div_ceil, }; pub struct GGSWCiphertext<C, B: Backend> {

@@ -220,9 +220,9 @@ k_ggsw: usize,

digits: usize, rank: usize, ) -> usize { - let tmp_in: usize = GLWECiphertextFourier::bytes_of(module, basek, k_in, rank); - let tmp_out: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank); - let ggsw: usize = GLWECiphertextFourier::external_product_scratch_space(module, basek, k_out, k_in, k_ggsw, digits, rank); + let tmp_in: usize = FourierGLWECiphertext::bytes_of(module, basek, k_in, rank); + let tmp_out: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank); + let ggsw: usize = FourierGLWECiphertext::external_product_scratch_space(module, basek, k_out, k_in, k_ggsw, digits, rank); tmp_in + tmp_out + ggsw }

@@ -234,9 +234,9 @@ k_ggsw: usize,

digits: usize, rank: usize, ) -> usize { - let tmp: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank); + let tmp: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank); let ggsw: usize = - GLWECiphertextFourier::external_product_inplace_scratch_space(module, basek, k_out, k_ggsw, digits, rank); + FourierGLWECiphertext::external_product_inplace_scratch_space(module, basek, k_out, k_ggsw, digits, rank); tmp + ggsw } }

@@ -686,7 +686,7 @@ &self,

module: &Module<FFT64>, row_i: usize, col_j: usize, - res: &mut GLWECiphertextFourier<R, FFT64>, + res: &mut FourierGLWECiphertext<R, FFT64>, ) { module.mat_znx_dft_get_row(&mut res.data, &self.data, row_i, col_j); }

@@ -698,7 +698,7 @@ &mut self,

module: &Module<FFT64>, row_i: usize, col_j: usize, - a: &GLWECiphertextFourier<R, FFT64>, + a: &FourierGLWECiphertext<R, FFT64>, ) { module.mat_znx_dft_set_row(&mut self.data, row_i, col_j, &a.data); }
A core/src/glwe/automorphism.rs

@@ -0,0 +1,121 @@

+use backend::{FFT64, Module, Scratch, VecZnxOps}; + +use crate::{AutomorphismKey, GLWECiphertext}; + +impl GLWECiphertext<Vec<u8>> { + pub fn automorphism_scratch_space( + module: &Module<FFT64>, + basek: usize, + k_out: usize, + k_in: usize, + k_ksk: usize, + digits: usize, + rank: usize, + ) -> usize { + Self::keyswitch_scratch_space(module, basek, k_out, k_in, k_ksk, digits, rank, rank) + } + + pub fn automorphism_inplace_scratch_space( + module: &Module<FFT64>, + basek: usize, + k_out: usize, + k_ksk: usize, + digits: usize, + rank: usize, + ) -> usize { + Self::keyswitch_inplace_scratch_space(module, basek, k_out, k_ksk, digits, rank) + } +} + +impl<DataSelf: AsRef<[u8]> + AsMut<[u8]>> GLWECiphertext<DataSelf> { + pub fn automorphism<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + lhs: &GLWECiphertext<DataLhs>, + rhs: &AutomorphismKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + self.keyswitch(module, lhs, &rhs.key, scratch); + (0..self.rank() + 1).for_each(|i| { + module.vec_znx_automorphism_inplace(rhs.p(), &mut self.data, i); + }) + } + + pub fn automorphism_inplace<DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + rhs: &AutomorphismKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + self.keyswitch_inplace(module, &rhs.key, scratch); + (0..self.rank() + 1).for_each(|i| { + module.vec_znx_automorphism_inplace(rhs.p(), &mut self.data, i); + }) + } + + pub fn automorphism_add<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + lhs: &GLWECiphertext<DataLhs>, + rhs: &AutomorphismKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + Self::keyswitch_private::<_, _, 1>(self, rhs.p(), module, lhs, &rhs.key, scratch); + } + + pub fn automorphism_add_inplace<DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + rhs: &AutomorphismKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + unsafe { + let self_ptr: *mut GLWECiphertext<DataSelf> = self as *mut GLWECiphertext<DataSelf>; + Self::keyswitch_private::<_, _, 1>(self, rhs.p(), module, &*self_ptr, &rhs.key, scratch); + } + } + + pub fn automorphism_sub_ab<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + lhs: &GLWECiphertext<DataLhs>, + rhs: &AutomorphismKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + Self::keyswitch_private::<_, _, 2>(self, rhs.p(), module, lhs, &rhs.key, scratch); + } + + pub fn automorphism_sub_ab_inplace<DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + rhs: &AutomorphismKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + unsafe { + let self_ptr: *mut GLWECiphertext<DataSelf> = self as *mut GLWECiphertext<DataSelf>; + Self::keyswitch_private::<_, _, 2>(self, rhs.p(), module, &*self_ptr, &rhs.key, scratch); + } + } + + pub fn automorphism_sub_ba<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + lhs: &GLWECiphertext<DataLhs>, + rhs: &AutomorphismKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + Self::keyswitch_private::<_, _, 3>(self, rhs.p(), module, lhs, &rhs.key, scratch); + } + + pub fn automorphism_sub_ba_inplace<DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + rhs: &AutomorphismKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + unsafe { + let self_ptr: *mut GLWECiphertext<DataSelf> = self as *mut GLWECiphertext<DataSelf>; + Self::keyswitch_private::<_, _, 3>(self, rhs.p(), module, &*self_ptr, &rhs.key, scratch); + } + } +}
A core/src/glwe/ciphertext.rs

@@ -0,0 +1,115 @@

+use backend::{ + Backend, FFT64, Module, VecZnx, VecZnxAlloc, VecZnxBigAlloc, VecZnxBigScratch, VecZnxDftAlloc, VecZnxDftOps, VecZnxToMut, + VecZnxToRef, +}; + +use crate::{FourierGLWECiphertext, GLWEOps, Infos, SetMetaData, div_ceil}; + +pub struct GLWECiphertext<C> { + pub data: VecZnx<C>, + pub basek: usize, + pub k: usize, +} + +impl GLWECiphertext<Vec<u8>> { + pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self { + Self { + data: module.new_vec_znx(rank + 1, div_ceil(k, basek)), + basek, + k, + } + } + + pub fn bytes_of(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize { + module.bytes_of_vec_znx(rank + 1, div_ceil(k, basek)) + } +} + +impl<T> Infos for GLWECiphertext<T> { + type Inner = VecZnx<T>; + + fn inner(&self) -> &Self::Inner { + &self.data + } + + fn basek(&self) -> usize { + self.basek + } + + fn k(&self) -> usize { + self.k + } +} + +impl<T> GLWECiphertext<T> { + pub fn rank(&self) -> usize { + self.cols() - 1 + } +} + +impl<C: AsRef<[u8]>> GLWECiphertext<C> { + #[allow(dead_code)] + pub(crate) fn dft<R: AsMut<[u8]> + AsRef<[u8]>>(&self, module: &Module<FFT64>, res: &mut FourierGLWECiphertext<R, FFT64>) { + #[cfg(debug_assertions)] + { + assert_eq!(self.rank(), res.rank()); + assert_eq!(self.basek(), res.basek()) + } + + (0..self.rank() + 1).for_each(|i| { + module.vec_znx_dft(1, 0, &mut res.data, i, &self.data, i); + }) + } +} + +impl GLWECiphertext<Vec<u8>> { + pub fn decrypt_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize { + let size: usize = div_ceil(k, basek); + (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size) + } +} + +impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> SetMetaData for GLWECiphertext<DataSelf> { + fn set_k(&mut self, k: usize) { + self.k = k + } + + fn set_basek(&mut self, basek: usize) { + self.basek = basek + } +} + +pub trait GLWECiphertextToRef { + fn to_ref(&self) -> GLWECiphertext<&[u8]>; +} + +impl<D: AsRef<[u8]>> GLWECiphertextToRef for GLWECiphertext<D> { + fn to_ref(&self) -> GLWECiphertext<&[u8]> { + GLWECiphertext { + data: self.data.to_ref(), + basek: self.basek, + k: self.k, + } + } +} + +pub trait GLWECiphertextToMut { + fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]>; +} + +impl<D: AsMut<[u8]> + AsRef<[u8]>> GLWECiphertextToMut for GLWECiphertext<D> { + fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]> { + GLWECiphertext { + data: self.data.to_mut(), + basek: self.basek, + k: self.k, + } + } +} + +impl<D> GLWEOps for GLWECiphertext<D> +where + D: AsRef<[u8]> + AsMut<[u8]>, + GLWECiphertext<D>: GLWECiphertextToMut + Infos + SetMetaData, +{ +}
A core/src/glwe/decryption.rs

@@ -0,0 +1,56 @@

+use backend::{FFT64, Module, ScalarZnxDftOps, Scratch, VecZnxBigOps, VecZnxDftOps, ZnxZero}; + +use crate::{GLWECiphertext, GLWEPlaintext, GLWESecret, Infos}; + +impl<DataSelf: AsRef<[u8]>> GLWECiphertext<DataSelf> { + pub fn clone(&self) -> GLWECiphertext<Vec<u8>> { + GLWECiphertext { + data: self.data.clone(), + basek: self.basek(), + k: self.k(), + } + } + + pub fn decrypt<DataPt: AsMut<[u8]> + AsRef<[u8]>, DataSk: AsRef<[u8]>>( + &self, + module: &Module<FFT64>, + pt: &mut GLWEPlaintext<DataPt>, + sk: &GLWESecret<DataSk, FFT64>, + scratch: &mut Scratch, + ) { + #[cfg(debug_assertions)] + { + assert_eq!(self.rank(), sk.rank()); + assert_eq!(self.n(), module.n()); + assert_eq!(pt.n(), module.n()); + assert_eq!(sk.n(), module.n()); + } + + let cols: usize = self.rank() + 1; + + let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, self.size()); // TODO optimize size when pt << ct + c0_big.zero(); + + { + (1..cols).for_each(|i| { + // ci_dft = DFT(a[i]) * DFT(s[i]) + let (mut ci_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, self.size()); // TODO optimize size when pt << ct + module.vec_znx_dft(1, 0, &mut ci_dft, 0, &self.data, i); + module.svp_apply_inplace(&mut ci_dft, 0, &sk.data_fourier, i - 1); + let ci_big = module.vec_znx_idft_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.basek(), &mut pt.data, 0, &mut c0_big, 0, scratch_1); + + pt.basek = self.basek(); + pt.k = pt.k().min(self.k()); + } +}
A core/src/glwe/encryption.rs

@@ -0,0 +1,254 @@

+use backend::{ + AddNormal, FFT64, FillUniform, Module, ScalarZnxAlloc, ScalarZnxDftAlloc, ScalarZnxDftOps, Scratch, VecZnxAlloc, VecZnxBig, + VecZnxBigAlloc, VecZnxBigOps, VecZnxBigScratch, VecZnxDftAlloc, VecZnxDftOps, VecZnxOps, ZnxZero, +}; +use sampling::source::Source; + +use crate::{GLWECiphertext, GLWEPlaintext, GLWEPublicKey, GLWESecret, Infos, SIX_SIGMA, div_ceil, keys::SecretDistribution}; + +impl GLWECiphertext<Vec<u8>> { + pub fn encrypt_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize { + let size: usize = div_ceil(k, basek); + module.vec_znx_big_normalize_tmp_bytes() + module.bytes_of_vec_znx_dft(1, size) + module.bytes_of_vec_znx(1, size) + } + pub fn encrypt_pk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize { + let size: usize = div_ceil(k, basek); + ((module.bytes_of_vec_znx_dft(1, size) + module.bytes_of_vec_znx_big(1, size)) | module.bytes_of_scalar_znx(1)) + + module.bytes_of_scalar_znx_dft(1) + + module.vec_znx_big_normalize_tmp_bytes() + } +} + +impl<DataSelf: AsRef<[u8]> + AsMut<[u8]>> GLWECiphertext<DataSelf> { + pub fn encrypt_sk<DataPt: AsRef<[u8]>, DataSk: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + pt: &GLWEPlaintext<DataPt>, + sk: &GLWESecret<DataSk, FFT64>, + source_xa: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch, + ) { + self.encrypt_sk_private( + module, + Some((pt, 0)), + sk, + source_xa, + source_xe, + sigma, + scratch, + ); + } + + pub fn encrypt_zero_sk<DataSk: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + sk: &GLWESecret<DataSk, FFT64>, + source_xa: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch, + ) { + self.encrypt_sk_private( + module, + None::<(&GLWEPlaintext<Vec<u8>>, usize)>, + sk, + source_xa, + source_xe, + sigma, + scratch, + ); + } + + pub fn encrypt_pk<DataPt: AsRef<[u8]>, DataPk: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + pt: &GLWEPlaintext<DataPt>, + pk: &GLWEPublicKey<DataPk, FFT64>, + source_xu: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch, + ) { + self.encrypt_pk_private( + module, + Some((pt, 0)), + pk, + source_xu, + source_xe, + sigma, + scratch, + ); + } + + pub fn encrypt_zero_pk<DataPk: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + pk: &GLWEPublicKey<DataPk, FFT64>, + source_xu: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch, + ) { + self.encrypt_pk_private( + module, + None::<(&GLWEPlaintext<Vec<u8>>, usize)>, + pk, + source_xu, + source_xe, + sigma, + scratch, + ); + } + + pub(crate) fn encrypt_sk_private<DataPt: AsRef<[u8]>, DataSk: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + pt: Option<(&GLWEPlaintext<DataPt>, usize)>, + sk: &GLWESecret<DataSk, FFT64>, + source_xa: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch, + ) { + #[cfg(debug_assertions)] + { + assert_eq!(self.rank(), sk.rank()); + assert_eq!(sk.n(), module.n()); + assert_eq!(self.n(), module.n()); + if let Some((pt, col)) = pt { + assert_eq!(pt.n(), module.n()); + assert!(col < self.rank() + 1); + } + assert!( + scratch.available() >= GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k()), + "scratch.available(): {} < GLWECiphertext::encrypt_sk_scratch_space: {}", + scratch.available(), + GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k()) + ) + } + + let basek: usize = self.basek(); + let k: usize = self.k(); + let size: usize = self.size(); + let cols: usize = self.rank() + 1; + + let (mut c0_big, scratch_1) = scratch.tmp_vec_znx(module, 1, size); + c0_big.zero(); + + { + // c[i] = uniform + // c[0] -= c[i] * s[i], + (1..cols).for_each(|i| { + let (mut ci_dft, scratch_2) = scratch_1.tmp_vec_znx_dft(module, 1, size); + + // c[i] = uniform + self.data.fill_uniform(basek, i, size, source_xa); + + // c[i] = norm(IDFT(DFT(c[i]) * DFT(s[i]))) + module.vec_znx_dft(1, 0, &mut ci_dft, 0, &self.data, i); + module.svp_apply_inplace(&mut ci_dft, 0, &sk.data_fourier, i - 1); + let ci_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(ci_dft); + + // use c[0] as buffer, which is overwritten later by the normalization step + module.vec_znx_big_normalize(basek, &mut self.data, 0, &ci_big, 0, scratch_2); + + // c0_tmp = -c[i] * s[i] (use c[0] as buffer) + module.vec_znx_sub_ab_inplace(&mut c0_big, 0, &self.data, 0); + + // c[i] += m if col = i + if let Some((pt, col)) = pt { + if i == col { + module.vec_znx_add_inplace(&mut self.data, i, &pt.data, 0); + module.vec_znx_normalize_inplace(basek, &mut self.data, i, scratch_2); + } + } + }); + } + + // c[0] += e + c0_big.add_normal(basek, 0, k, source_xe, sigma, sigma * SIX_SIGMA); + + // c[0] += m if col = 0 + if let Some((pt, col)) = pt { + if col == 0 { + module.vec_znx_add_inplace(&mut c0_big, 0, &pt.data, 0); + } + } + + // c[0] = norm(c[0]) + module.vec_znx_normalize(basek, &mut self.data, 0, &c0_big, 0, scratch_1); + } + + pub(crate) fn encrypt_pk_private<DataPt: AsRef<[u8]>, DataPk: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + pt: Option<(&GLWEPlaintext<DataPt>, usize)>, + pk: &GLWEPublicKey<DataPk, FFT64>, + source_xu: &mut Source, + source_xe: &mut Source, + sigma: f64, + scratch: &mut Scratch, + ) { + #[cfg(debug_assertions)] + { + assert_eq!(self.basek(), pk.basek()); + assert_eq!(self.n(), module.n()); + assert_eq!(pk.n(), module.n()); + assert_eq!(self.rank(), pk.rank()); + if let Some((pt, _)) = pt { + assert_eq!(pt.basek(), pk.basek()); + assert_eq!(pt.n(), module.n()); + } + } + + let basek: usize = pk.basek(); + let size_pk: usize = pk.size(); + let cols: usize = self.rank() + 1; + + // Generates u according to the underlying secret distribution. + let (mut u_dft, scratch_1) = scratch.tmp_scalar_znx_dft(module, 1); + + { + let (mut u, _) = scratch_1.tmp_scalar_znx(module, 1); + match pk.dist { + SecretDistribution::NONE => panic!( + "invalid public key: SecretDistribution::NONE, ensure it has been correctly intialized through \ + Self::generate" + ), + SecretDistribution::TernaryFixed(hw) => u.fill_ternary_hw(0, hw, source_xu), + SecretDistribution::TernaryProb(prob) => u.fill_ternary_prob(0, prob, source_xu), + SecretDistribution::BinaryFixed(hw) => u.fill_binary_hw(0, hw, source_xu), + SecretDistribution::BinaryProb(prob) => u.fill_binary_prob(0, prob, source_xu), + SecretDistribution::BinaryBlock(block_size) => u.fill_binary_block(0, block_size, source_xu), + SecretDistribution::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.tmp_vec_znx_dft(module, 1, size_pk); + // ci_dft = DFT(u) * DFT(pk[i]) + module.svp_apply(&mut ci_dft, 0, &u_dft, 0, &pk.data.data, i); + + // ci_big = u * p[i] + let mut ci_big = module.vec_znx_idft_consume(ci_dft); + + // ci_big = u * pk[i] + e + ci_big.add_normal(basek, 0, pk.k(), source_xe, sigma, sigma * SIX_SIGMA); + + // ci_big = u * pk[i] + e + m (if col = i) + if let Some((pt, col)) = pt { + if 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(basek, &mut self.data, i, &ci_big, 0, scratch_2); + }); + } +}
A core/src/glwe/external_product.rs

@@ -0,0 +1,129 @@

+use backend::{ + FFT64, MatZnxDftOps, MatZnxDftScratch, Module, Scratch, VecZnxBig, VecZnxBigOps, VecZnxDftAlloc, VecZnxDftOps, VecZnxScratch, +}; + +use crate::{FourierGLWECiphertext, GGSWCiphertext, GLWECiphertext, Infos, div_ceil}; + +impl GLWECiphertext<Vec<u8>> { + pub fn external_product_scratch_space( + module: &Module<FFT64>, + basek: usize, + k_out: usize, + k_in: usize, + ggsw_k: usize, + digits: usize, + rank: usize, + ) -> usize { + let res_dft: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank); + let in_size: usize = div_ceil(div_ceil(k_in, basek), digits); + let out_size: usize = div_ceil(k_out, basek); + let ggsw_size: usize = div_ceil(ggsw_k, basek); + let vmp: usize = module.bytes_of_vec_znx_dft(rank + 1, in_size) + + module.vmp_apply_tmp_bytes( + out_size, + in_size, + in_size, // rows + rank + 1, // cols in + rank + 1, // cols out + ggsw_size, + ); + let normalize: usize = module.vec_znx_normalize_tmp_bytes(); + res_dft + (vmp | normalize) + } + + pub fn external_product_inplace_scratch_space( + module: &Module<FFT64>, + basek: usize, + k_out: usize, + ggsw_k: usize, + digits: usize, + rank: usize, + ) -> usize { + Self::external_product_scratch_space(module, basek, k_out, k_out, ggsw_k, digits, rank) + } +} + +impl<DataSelf: AsRef<[u8]> + AsMut<[u8]>> GLWECiphertext<DataSelf> { + pub fn external_product<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + lhs: &GLWECiphertext<DataLhs>, + rhs: &GGSWCiphertext<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + let basek: usize = self.basek(); + + #[cfg(debug_assertions)] + { + assert_eq!(rhs.rank(), lhs.rank()); + assert_eq!(rhs.rank(), self.rank()); + assert_eq!(self.basek(), basek); + assert_eq!(lhs.basek(), basek); + assert_eq!(rhs.n(), module.n()); + assert_eq!(self.n(), module.n()); + assert_eq!(lhs.n(), module.n()); + assert!( + scratch.available() + >= GLWECiphertext::external_product_scratch_space( + module, + self.basek(), + self.k(), + lhs.k(), + rhs.k(), + rhs.digits(), + rhs.rank(), + ) + ); + } + + let cols: usize = rhs.rank() + 1; + let digits: usize = rhs.digits(); + + let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, cols, rhs.size()); // Todo optimise + let (mut a_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, cols, (lhs.size() + digits - 1) / digits); + + { + (0..digits).for_each(|di| { + // (lhs.size() + di) / digits = (a - (digit - di - 1) + digit - 1) / digits + a_dft.set_size((lhs.size() + di) / digits); + + // Small optimization for digits > 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^{(digits-1) * B}. + // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last digits-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(rhs.size() - ((digits - di) as isize - 2).max(0) as usize); + + (0..cols).for_each(|col_i| { + module.vec_znx_dft(digits, digits - 1 - di, &mut a_dft, col_i, &lhs.data, col_i); + }); + + if di == 0 { + module.vmp_apply(&mut res_dft, &a_dft, &rhs.data, scratch2); + } else { + module.vmp_apply_add(&mut res_dft, &a_dft, &rhs.data, di, scratch2); + } + }); + } + + let res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(res_dft); + + (0..cols).for_each(|i| { + module.vec_znx_big_normalize(basek, &mut self.data, i, &res_big, i, scratch1); + }); + } + + pub fn external_product_inplace<DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + rhs: &GGSWCiphertext<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + unsafe { + let self_ptr: *mut GLWECiphertext<DataSelf> = self as *mut GLWECiphertext<DataSelf>; + self.external_product(&module, &*self_ptr, rhs, scratch); + } + } +}
A core/src/glwe/keyswitch.rs

@@ -0,0 +1,244 @@

+use backend::{ + FFT64, MatZnxDftOps, MatZnxDftScratch, Module, Scratch, VecZnxBig, VecZnxBigOps, VecZnxBigScratch, VecZnxDftAlloc, + VecZnxDftOps, ZnxZero, +}; + +use crate::{FourierGLWECiphertext, GLWECiphertext, GLWESwitchingKey, Infos, div_ceil}; + +impl GLWECiphertext<Vec<u8>> { + pub fn keyswitch_scratch_space( + module: &Module<FFT64>, + basek: usize, + k_out: usize, + k_in: usize, + k_ksk: usize, + digits: usize, + rank_in: usize, + rank_out: usize, + ) -> usize { + let res_dft: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank_out + 1); + let in_size: usize = div_ceil(div_ceil(k_in, basek), digits); + let out_size: usize = div_ceil(k_out, basek); + let ksk_size: usize = div_ceil(k_ksk, basek); + let ai_dft: usize = module.bytes_of_vec_znx_dft(rank_in, in_size); + let vmp: usize = module.vmp_apply_tmp_bytes(out_size, in_size, in_size, rank_in, rank_out + 1, ksk_size) + + module.bytes_of_vec_znx_dft(rank_in, in_size); + let normalize: usize = module.vec_znx_big_normalize_tmp_bytes(); + return res_dft + ((ai_dft + vmp) | normalize); + } + + pub fn keyswitch_from_fourier_scratch_space( + module: &Module<FFT64>, + basek: usize, + k_out: usize, + k_in: usize, + k_ksk: usize, + digits: usize, + rank_in: usize, + rank_out: usize, + ) -> usize { + Self::keyswitch_scratch_space(module, basek, k_out, k_in, k_ksk, digits, rank_in, rank_out) + } + + pub fn keyswitch_inplace_scratch_space( + module: &Module<FFT64>, + basek: usize, + k_out: usize, + k_ksk: usize, + digits: usize, + rank: usize, + ) -> usize { + Self::keyswitch_scratch_space(module, basek, k_out, k_out, k_ksk, digits, rank, rank) + } +} + +impl<DataSelf: AsRef<[u8]> + AsMut<[u8]>> GLWECiphertext<DataSelf> { + pub fn keyswitch<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + lhs: &GLWECiphertext<DataLhs>, + rhs: &GLWESwitchingKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + Self::keyswitch_private::<_, _, 0>(self, 0, module, lhs, rhs, scratch); + } + + pub fn keyswitch_inplace<DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + rhs: &GLWESwitchingKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + unsafe { + let self_ptr: *mut GLWECiphertext<DataSelf> = self as *mut GLWECiphertext<DataSelf>; + self.keyswitch(&module, &*self_ptr, rhs, scratch); + } + } + + pub(crate) fn keyswitch_private<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>, const OP: u8>( + &mut self, + apply_auto: i64, + module: &Module<FFT64>, + lhs: &GLWECiphertext<DataLhs>, + rhs: &GLWESwitchingKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + let basek: usize = self.basek(); + + #[cfg(debug_assertions)] + { + assert_eq!(lhs.rank(), rhs.rank_in()); + assert_eq!(self.rank(), rhs.rank_out()); + assert_eq!(self.basek(), basek); + assert_eq!(lhs.basek(), basek); + assert_eq!(rhs.n(), module.n()); + assert_eq!(self.n(), module.n()); + assert_eq!(lhs.n(), module.n()); + assert!( + scratch.available() + >= GLWECiphertext::keyswitch_scratch_space( + module, + self.basek(), + self.k(), + lhs.k(), + rhs.k(), + rhs.digits(), + rhs.rank_in(), + rhs.rank_out(), + ) + ); + } + + let cols_in: usize = rhs.rank_in(); + let cols_out: usize = rhs.rank_out() + 1; + let digits: usize = rhs.digits(); + + let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, cols_out, rhs.size()); // Todo optimise + let (mut ai_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, cols_in, (lhs.size() + digits - 1) / digits); + ai_dft.zero(); + { + (0..digits).for_each(|di| { + ai_dft.set_size((lhs.size() + di) / digits); + + // Small optimization for digits > 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^{(digits-1) * B}. + // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. + // It is possible to further ignore the last digits-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(rhs.size() - ((digits - di) as isize - 2).max(0) as usize); + + (0..cols_in).for_each(|col_i| { + module.vec_znx_dft( + digits, + digits - di - 1, + &mut ai_dft, + col_i, + &lhs.data, + col_i + 1, + ); + }); + + if di == 0 { + module.vmp_apply(&mut res_dft, &ai_dft, &rhs.0.data, scratch2); + } else { + module.vmp_apply_add(&mut res_dft, &ai_dft, &rhs.0.data, di, scratch2); + } + }); + } + + let mut res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(res_dft); + + module.vec_znx_big_add_small_inplace(&mut res_big, 0, &lhs.data, 0); + + (0..cols_out).for_each(|i| { + if apply_auto != 0 { + module.vec_znx_big_automorphism_inplace(apply_auto, &mut res_big, i); + } + + match OP { + 1 => module.vec_znx_big_add_small_inplace(&mut res_big, i, &lhs.data, i), + 2 => module.vec_znx_big_sub_small_a_inplace(&mut res_big, i, &lhs.data, i), + 3 => module.vec_znx_big_sub_small_b_inplace(&mut res_big, i, &lhs.data, i), + _ => {} + } + module.vec_znx_big_normalize(basek, &mut self.data, i, &res_big, i, scratch1); + }); + } + + pub(crate) fn keyswitch_from_fourier<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + lhs: &FourierGLWECiphertext<DataLhs, FFT64>, + rhs: &GLWESwitchingKey<DataRhs, FFT64>, + scratch: &mut Scratch, + ) { + let basek: usize = self.basek(); + + #[cfg(debug_assertions)] + { + assert_eq!(lhs.rank(), rhs.rank_in()); + assert_eq!(self.rank(), rhs.rank_out()); + assert_eq!(self.basek(), basek); + assert_eq!(lhs.basek(), basek); + assert_eq!(rhs.n(), module.n()); + assert_eq!(self.n(), module.n()); + assert_eq!(lhs.n(), module.n()); + assert!( + scratch.available() + >= GLWECiphertext::keyswitch_from_fourier_scratch_space( + module, + self.basek(), + self.k(), + lhs.k(), + rhs.k(), + rhs.digits(), + rhs.rank_in(), + rhs.rank_out(), + ) + ); + } + + let cols_in: usize = rhs.rank_in(); + let cols_out: usize = rhs.rank_out() + 1; + + // Buffer of the result of VMP in DFT + let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, cols_out, rhs.size()); // Todo optimise + + { + let digits = rhs.digits(); + + (0..digits).for_each(|di| { + // (lhs.size() + di) / digits = (a - (digit - di - 1) + digit - 1) / digits + let (mut ai_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, cols_in, (lhs.size() + di) / digits); + + (0..cols_in).for_each(|col_i| { + module.vec_znx_dft_copy( + digits, + digits - 1 - di, + &mut ai_dft, + col_i, + &lhs.data, + col_i + 1, + ); + }); + + if di == 0 { + module.vmp_apply(&mut res_dft, &ai_dft, &rhs.0.data, scratch2); + } else { + module.vmp_apply_add(&mut res_dft, &ai_dft, &rhs.0.data, di, scratch2); + } + }); + } + + module.vec_znx_dft_add_inplace(&mut res_dft, 0, &lhs.data, 0); + + // Switches result of VMP outside of DFT + let res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume::<&mut [u8]>(res_dft); + + (0..cols_out).for_each(|i| { + module.vec_znx_big_normalize(basek, &mut self.data, i, &res_big, i, scratch1); + }); + } +}
A core/src/glwe/mod.rs

@@ -0,0 +1,31 @@

+pub mod automorphism; +pub mod ciphertext; +pub mod decryption; +pub mod encryption; +pub mod external_product; +pub mod keyswitch; +pub mod ops; +pub mod packing; +pub mod plaintext; +pub mod public_key; +pub mod secret; +pub mod trace; + +#[allow(unused_imports)] +pub use automorphism::*; +pub use ciphertext::*; +#[allow(unused_imports)] +pub use decryption::*; +#[allow(unused_imports)] +pub use encryption::*; +#[allow(unused_imports)] +pub use external_product::*; +#[allow(unused_imports)] +pub use keyswitch::*; +pub use ops::*; +pub use packing::*; +pub use plaintext::*; +pub use public_key::*; +pub use secret::*; +#[allow(unused_imports)] +pub use trace::*;
A core/src/glwe/public_key.rs

@@ -0,0 +1,75 @@

+use backend::{Backend, FFT64, Module, ScratchOwned, VecZnxDft}; +use sampling::source::Source; + +use crate::{FourierGLWECiphertext, GLWESecret, Infos, keys::SecretDistribution}; + +pub struct GLWEPublicKey<D, B: Backend> { + pub(crate) data: FourierGLWECiphertext<D, B>, + pub(crate) dist: SecretDistribution, +} + +impl<B: Backend> GLWEPublicKey<Vec<u8>, B> { + pub fn alloc(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self { + Self { + data: FourierGLWECiphertext::alloc(module, basek, k, rank), + dist: SecretDistribution::NONE, + } + } + + pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize { + FourierGLWECiphertext::<Vec<u8>, B>::bytes_of(module, basek, k, rank) + } +} + +impl<T, B: Backend> Infos for GLWEPublicKey<T, B> { + type Inner = VecZnxDft<T, B>; + + fn inner(&self) -> &Self::Inner { + &self.data.data + } + + fn basek(&self) -> usize { + self.data.basek + } + + fn k(&self) -> usize { + self.data.k + } +} + +impl<T, B: Backend> GLWEPublicKey<T, B> { + pub fn rank(&self) -> usize { + self.cols() - 1 + } +} + +impl<C: AsRef<[u8]> + AsMut<[u8]>> GLWEPublicKey<C, FFT64> { + pub fn generate_from_sk<S: AsRef<[u8]>>( + &mut self, + module: &Module<FFT64>, + sk: &GLWESecret<S, FFT64>, + source_xa: &mut Source, + source_xe: &mut Source, + sigma: f64, + ) { + #[cfg(debug_assertions)] + { + match sk.dist { + SecretDistribution::NONE => panic!("invalid sk: SecretDistribution::NONE"), + _ => {} + } + } + + // Its ok to allocate scratch space here since pk is usually generated only once. + let mut scratch: ScratchOwned = ScratchOwned::new(FourierGLWECiphertext::encrypt_sk_scratch_space( + module, + self.basek(), + self.k(), + self.rank(), + )); + + self.data + .encrypt_zero_sk(module, sk, source_xa, source_xe, sigma, scratch.borrow()); + self.dist = sk.dist; + } +}
A core/src/glwe/secret.rs

@@ -0,0 +1,93 @@

+use backend::{ + Backend, FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxDft, ScalarZnxDftAlloc, ScalarZnxDftOps, ZnxInfos, ZnxZero, +}; +use sampling::source::Source; + +use crate::keys::SecretDistribution; + +pub struct GLWESecret<T, B: Backend> { + pub(crate) data: ScalarZnx<T>, + pub(crate) data_fourier: ScalarZnxDft<T, B>, + pub(crate) dist: SecretDistribution, +} + +impl<B: Backend> GLWESecret<Vec<u8>, B> { + pub fn alloc(module: &Module<B>, rank: usize) -> Self { + Self { + data: module.new_scalar_znx(rank), + data_fourier: module.new_scalar_znx_dft(rank), + dist: SecretDistribution::NONE, + } + } + + pub fn bytes_of(module: &Module<B>, rank: usize) -> usize { + module.bytes_of_scalar_znx(rank) + module.bytes_of_scalar_znx_dft(rank) + } +} + +impl<DataSelf, B: Backend> GLWESecret<DataSelf, B> { + pub fn n(&self) -> usize { + self.data.n() + } + + pub fn log_n(&self) -> usize { + self.data.log_n() + } + + pub fn rank(&self) -> usize { + self.data.cols() + } +} + +impl<S: AsMut<[u8]> + AsRef<[u8]>> GLWESecret<S, FFT64> { + pub fn fill_ternary_prob(&mut self, module: &Module<FFT64>, prob: f64, source: &mut Source) { + (0..self.rank()).for_each(|i| { + self.data.fill_ternary_prob(i, prob, source); + }); + self.prep_fourier(module); + self.dist = SecretDistribution::TernaryProb(prob); + } + + pub fn fill_ternary_hw(&mut self, module: &Module<FFT64>, hw: usize, source: &mut Source) { + (0..self.rank()).for_each(|i| { + self.data.fill_ternary_hw(i, hw, source); + }); + self.prep_fourier(module); + self.dist = SecretDistribution::TernaryFixed(hw); + } + + pub fn fill_binary_prob(&mut self, module: &Module<FFT64>, prob: f64, source: &mut Source) { + (0..self.rank()).for_each(|i| { + self.data.fill_binary_prob(i, prob, source); + }); + self.prep_fourier(module); + self.dist = SecretDistribution::BinaryProb(prob); + } + + pub fn fill_binary_hw(&mut self, module: &Module<FFT64>, hw: usize, source: &mut Source) { + (0..self.rank()).for_each(|i| { + self.data.fill_binary_hw(i, hw, source); + }); + self.prep_fourier(module); + self.dist = SecretDistribution::BinaryFixed(hw); + } + + pub fn fill_binary_block(&mut self, module: &Module<FFT64>, block_size: usize, source: &mut Source) { + (0..self.rank()).for_each(|i| { + self.data.fill_binary_block(i, block_size, source); + }); + self.prep_fourier(module); + self.dist = SecretDistribution::BinaryBlock(block_size); + } + + pub fn fill_zero(&mut self) { + self.data.zero(); + self.dist = SecretDistribution::ZERO; + } + + pub(crate) fn prep_fourier(&mut self, module: &Module<FFT64>) { + (0..self.rank()).for_each(|i| { + module.svp_prepare(&mut self.data_fourier, i, &self.data, i); + }); + } +}
D core/src/glwe_ciphertext.rs

@@ -1,886 +0,0 @@

-use backend::{ - AddNormal, Backend, FFT64, FillUniform, MatZnxDftOps, MatZnxDftScratch, Module, ScalarZnxAlloc, ScalarZnxDftAlloc, - ScalarZnxDftOps, Scratch, VecZnx, VecZnxAlloc, VecZnxBig, VecZnxBigAlloc, VecZnxBigOps, VecZnxBigScratch, VecZnxDftAlloc, - VecZnxDftOps, VecZnxOps, VecZnxToMut, VecZnxToRef, ZnxZero, -}; -use sampling::source::Source; - -use crate::{ - AutomorphismKey, GGSWCiphertext, GLWECiphertextFourier, GLWEOps, GLWEPlaintext, GLWEPublicKey, GLWESecret, GLWESwitchingKey, - Infos, SIX_SIGMA, SecretDistribution, SetMetaData, -}; - -pub struct GLWECiphertext<C> { - pub data: VecZnx<C>, - pub basek: usize, - pub k: usize, -} - -impl GLWECiphertext<Vec<u8>> { - pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self { - Self { - data: module.new_vec_znx(rank + 1, k.div_ceil(basek)), - basek, - k, - } - } - - pub fn bytes_of(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize { - module.bytes_of_vec_znx(rank + 1, k.div_ceil(basek)) - } -} - -impl<T> Infos for GLWECiphertext<T> { - type Inner = VecZnx<T>; - - fn inner(&self) -> &Self::Inner { - &self.data - } - - fn basek(&self) -> usize { - self.basek - } - - fn k(&self) -> usize { - self.k - } -} - -impl<T> GLWECiphertext<T> { - pub fn rank(&self) -> usize { - self.cols() - 1 - } -} - -impl<C: AsRef<[u8]>> GLWECiphertext<C> { - #[allow(dead_code)] - pub(crate) fn dft<R: AsMut<[u8]> + AsRef<[u8]>>(&self, module: &Module<FFT64>, res: &mut GLWECiphertextFourier<R, FFT64>) { - #[cfg(debug_assertions)] - { - assert_eq!(self.rank(), res.rank()); - assert_eq!(self.basek(), res.basek()) - } - - (0..self.rank() + 1).for_each(|i| { - module.vec_znx_dft(1, 0, &mut res.data, i, &self.data, i); - }) - } -} - -impl GLWECiphertext<Vec<u8>> { - pub fn encrypt_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize { - let size: usize = k.div_ceil(basek); - module.vec_znx_big_normalize_tmp_bytes() + module.bytes_of_vec_znx_dft(1, size) + module.bytes_of_vec_znx(1, size) - } - pub fn encrypt_pk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize { - let size: usize = k.div_ceil(basek); - ((module.bytes_of_vec_znx_dft(1, size) + module.bytes_of_vec_znx_big(1, size)) | module.bytes_of_scalar_znx(1)) - + module.bytes_of_scalar_znx_dft(1) - + module.vec_znx_big_normalize_tmp_bytes() - } - - pub fn decrypt_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize { - let size: usize = k.div_ceil(basek); - (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size) - } - - pub fn keyswitch_scratch_space( - module: &Module<FFT64>, - basek: usize, - k_out: usize, - k_in: usize, - k_ksk: usize, - digits: usize, - rank_in: usize, - rank_out: usize, - ) -> usize { - let res_dft: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank_out + 1); - let in_size: usize = k_in.div_ceil(basek).div_ceil(digits); - let out_size: usize = k_out.div_ceil(basek); - let ksk_size: usize = k_ksk.div_ceil(basek); - let ai_dft: usize = module.bytes_of_vec_znx_dft(rank_in, in_size); - let vmp: usize = module.vmp_apply_tmp_bytes(out_size, in_size, in_size, rank_in, rank_out + 1, ksk_size) - + module.bytes_of_vec_znx_dft(rank_in, in_size); - let normalize: usize = module.vec_znx_big_normalize_tmp_bytes(); - return res_dft + ((ai_dft + vmp) | normalize); - } - - pub fn keyswitch_from_fourier_scratch_space( - module: &Module<FFT64>, - basek: usize, - k_out: usize, - k_in: usize, - k_ksk: usize, - digits: usize, - rank_in: usize, - rank_out: usize, - ) -> usize { - Self::keyswitch_scratch_space(module, basek, k_out, k_in, k_ksk, digits, rank_in, rank_out) - } - - pub fn keyswitch_inplace_scratch_space( - module: &Module<FFT64>, - basek: usize, - k_out: usize, - k_ksk: usize, - digits: usize, - rank: usize, - ) -> usize { - Self::keyswitch_scratch_space(module, basek, k_out, k_out, k_ksk, digits, rank, rank) - } - - pub fn automorphism_scratch_space( - module: &Module<FFT64>, - basek: usize, - k_out: usize, - k_in: usize, - k_ksk: usize, - digits: usize, - rank: usize, - ) -> usize { - Self::keyswitch_scratch_space(module, basek, k_out, k_in, k_ksk, digits, rank, rank) - } - - pub fn automorphism_inplace_scratch_space( - module: &Module<FFT64>, - basek: usize, - k_out: usize, - k_ksk: usize, - digits: usize, - rank: usize, - ) -> usize { - Self::keyswitch_inplace_scratch_space(module, basek, k_out, k_ksk, digits, rank) - } - - pub fn external_product_scratch_space( - module: &Module<FFT64>, - basek: usize, - k_out: usize, - k_in: usize, - ggsw_k: usize, - digits: usize, - rank: usize, - ) -> usize { - let res_dft: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank); - let in_size: usize = k_in.div_ceil(basek).div_ceil(digits); - let out_size: usize = k_out.div_ceil(basek); - let ggsw_size: usize = ggsw_k.div_ceil(basek); - let vmp: usize = module.bytes_of_vec_znx_dft(rank + 1, in_size) - + module.vmp_apply_tmp_bytes( - out_size, - in_size, - in_size, // rows - rank + 1, // cols in - rank + 1, // cols out - ggsw_size, - ); - let normalize: usize = module.vec_znx_big_normalize_tmp_bytes(); - res_dft + (vmp | normalize) - } - - pub fn external_product_inplace_scratch_space( - module: &Module<FFT64>, - basek: usize, - k_out: usize, - ggsw_k: usize, - digits: usize, - rank: usize, - ) -> usize { - Self::external_product_scratch_space(module, basek, k_out, k_out, ggsw_k, digits, rank) - } -} - -impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> SetMetaData for GLWECiphertext<DataSelf> { - fn set_k(&mut self, k: usize) { - self.k = k - } - - fn set_basek(&mut self, basek: usize) { - self.basek = basek - } -} - -impl<DataSelf: AsRef<[u8]> + AsMut<[u8]>> GLWECiphertext<DataSelf> { - pub fn encrypt_sk<DataPt: AsRef<[u8]>, DataSk: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - pt: &GLWEPlaintext<DataPt>, - sk: &GLWESecret<DataSk, FFT64>, - source_xa: &mut Source, - source_xe: &mut Source, - sigma: f64, - scratch: &mut Scratch, - ) { - self.encrypt_sk_private( - module, - Some((pt, 0)), - sk, - source_xa, - source_xe, - sigma, - scratch, - ); - } - - pub fn encrypt_zero_sk<DataSk: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - sk: &GLWESecret<DataSk, FFT64>, - source_xa: &mut Source, - source_xe: &mut Source, - sigma: f64, - scratch: &mut Scratch, - ) { - self.encrypt_sk_private( - module, - None::<(&GLWEPlaintext<Vec<u8>>, usize)>, - sk, - source_xa, - source_xe, - sigma, - scratch, - ); - } - - pub fn encrypt_pk<DataPt: AsRef<[u8]>, DataPk: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - pt: &GLWEPlaintext<DataPt>, - pk: &GLWEPublicKey<DataPk, FFT64>, - source_xu: &mut Source, - source_xe: &mut Source, - sigma: f64, - scratch: &mut Scratch, - ) { - self.encrypt_pk_private( - module, - Some((pt, 0)), - pk, - source_xu, - source_xe, - sigma, - scratch, - ); - } - - pub fn encrypt_zero_pk<DataPk: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - pk: &GLWEPublicKey<DataPk, FFT64>, - source_xu: &mut Source, - source_xe: &mut Source, - sigma: f64, - scratch: &mut Scratch, - ) { - self.encrypt_pk_private( - module, - None::<(&GLWEPlaintext<Vec<u8>>, usize)>, - pk, - source_xu, - source_xe, - sigma, - scratch, - ); - } - - pub fn automorphism<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &AutomorphismKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - self.keyswitch(module, lhs, &rhs.key, scratch); - (0..self.rank() + 1).for_each(|i| { - module.vec_znx_automorphism_inplace(rhs.p(), &mut self.data, i); - }) - } - - pub fn automorphism_inplace<DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - rhs: &AutomorphismKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - self.keyswitch_inplace(module, &rhs.key, scratch); - (0..self.rank() + 1).for_each(|i| { - module.vec_znx_automorphism_inplace(rhs.p(), &mut self.data, i); - }) - } - - pub fn automorphism_add<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &AutomorphismKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - Self::keyswitch_private::<_, _, 1>(self, rhs.p(), module, lhs, &rhs.key, scratch); - } - - pub fn automorphism_add_inplace<DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - rhs: &AutomorphismKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - unsafe { - let self_ptr: *mut GLWECiphertext<DataSelf> = self as *mut GLWECiphertext<DataSelf>; - Self::keyswitch_private::<_, _, 1>(self, rhs.p(), module, &*self_ptr, &rhs.key, scratch); - } - } - - pub fn automorphism_sub_ab<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &AutomorphismKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - Self::keyswitch_private::<_, _, 2>(self, rhs.p(), module, lhs, &rhs.key, scratch); - } - - pub fn automorphism_sub_ab_inplace<DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - rhs: &AutomorphismKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - unsafe { - let self_ptr: *mut GLWECiphertext<DataSelf> = self as *mut GLWECiphertext<DataSelf>; - Self::keyswitch_private::<_, _, 2>(self, rhs.p(), module, &*self_ptr, &rhs.key, scratch); - } - } - - pub fn automorphism_sub_ba<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &AutomorphismKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - Self::keyswitch_private::<_, _, 3>(self, rhs.p(), module, lhs, &rhs.key, scratch); - } - - pub fn automorphism_sub_ba_inplace<DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - rhs: &AutomorphismKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - unsafe { - let self_ptr: *mut GLWECiphertext<DataSelf> = self as *mut GLWECiphertext<DataSelf>; - Self::keyswitch_private::<_, _, 3>(self, rhs.p(), module, &*self_ptr, &rhs.key, scratch); - } - } - - pub(crate) fn keyswitch_from_fourier<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - lhs: &GLWECiphertextFourier<DataLhs, FFT64>, - rhs: &GLWESwitchingKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - let basek: usize = self.basek(); - - #[cfg(debug_assertions)] - { - assert_eq!(lhs.rank(), rhs.rank_in()); - assert_eq!(self.rank(), rhs.rank_out()); - assert_eq!(self.basek(), basek); - assert_eq!(lhs.basek(), basek); - assert_eq!(rhs.n(), module.n()); - assert_eq!(self.n(), module.n()); - assert_eq!(lhs.n(), module.n()); - assert!( - scratch.available() - >= GLWECiphertext::keyswitch_from_fourier_scratch_space( - module, - self.basek(), - self.k(), - lhs.k(), - rhs.k(), - rhs.digits(), - rhs.rank_in(), - rhs.rank_out(), - ) - ); - } - - let cols_in: usize = rhs.rank_in(); - let cols_out: usize = rhs.rank_out() + 1; - - // Buffer of the result of VMP in DFT - let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, cols_out, rhs.size()); // Todo optimise - - { - let digits = rhs.digits(); - - (0..digits).for_each(|di| { - // (lhs.size() + di) / digits = (a - (digit - di - 1) + digit - 1) / digits - let (mut ai_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, cols_in, (lhs.size() + di) / digits); - - (0..cols_in).for_each(|col_i| { - module.vec_znx_dft_copy( - digits, - digits - 1 - di, - &mut ai_dft, - col_i, - &lhs.data, - col_i + 1, - ); - }); - - if di == 0 { - module.vmp_apply(&mut res_dft, &ai_dft, &rhs.0.data, scratch2); - } else { - module.vmp_apply_add(&mut res_dft, &ai_dft, &rhs.0.data, di, scratch2); - } - }); - } - - module.vec_znx_dft_add_inplace(&mut res_dft, 0, &lhs.data, 0); - - // Switches result of VMP outside of DFT - let res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume::<&mut [u8]>(res_dft); - - (0..cols_out).for_each(|i| { - module.vec_znx_big_normalize(basek, &mut self.data, i, &res_big, i, scratch1); - }); - } - - pub fn keyswitch<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &GLWESwitchingKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - Self::keyswitch_private::<_, _, 0>(self, 0, module, lhs, rhs, scratch); - } - - pub(crate) fn keyswitch_private<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>, const OP: u8>( - &mut self, - apply_auto: i64, - module: &Module<FFT64>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &GLWESwitchingKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - let basek: usize = self.basek(); - - #[cfg(debug_assertions)] - { - assert_eq!(lhs.rank(), rhs.rank_in()); - assert_eq!(self.rank(), rhs.rank_out()); - assert_eq!(self.basek(), basek); - assert_eq!(lhs.basek(), basek); - assert_eq!(rhs.n(), module.n()); - assert_eq!(self.n(), module.n()); - assert_eq!(lhs.n(), module.n()); - assert!( - scratch.available() - >= GLWECiphertext::keyswitch_scratch_space( - module, - self.basek(), - self.k(), - lhs.k(), - rhs.k(), - rhs.digits(), - rhs.rank_in(), - rhs.rank_out(), - ) - ); - } - - let cols_in: usize = rhs.rank_in(); - let cols_out: usize = rhs.rank_out() + 1; - let digits: usize = rhs.digits(); - - let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, cols_out, rhs.size()); // Todo optimise - let (mut ai_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, cols_in, (lhs.size() + digits - 1) / digits); - ai_dft.zero(); - { - (0..digits).for_each(|di| { - ai_dft.set_size((lhs.size() + di) / digits); - - // Small optimization for digits > 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^{(digits-1) * B}. - // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last digits-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(rhs.size() - ((digits - di) as isize - 2).max(0) as usize); - - (0..cols_in).for_each(|col_i| { - module.vec_znx_dft( - digits, - digits - di - 1, - &mut ai_dft, - col_i, - &lhs.data, - col_i + 1, - ); - }); - - if di == 0 { - module.vmp_apply(&mut res_dft, &ai_dft, &rhs.0.data, scratch2); - } else { - module.vmp_apply_add(&mut res_dft, &ai_dft, &rhs.0.data, di, scratch2); - } - }); - } - - let mut res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(res_dft); - - module.vec_znx_big_add_small_inplace(&mut res_big, 0, &lhs.data, 0); - - (0..cols_out).for_each(|i| { - if apply_auto != 0 { - module.vec_znx_big_automorphism_inplace(apply_auto, &mut res_big, i); - } - - match OP { - 1 => module.vec_znx_big_add_small_inplace(&mut res_big, i, &lhs.data, i), - 2 => module.vec_znx_big_sub_small_a_inplace(&mut res_big, i, &lhs.data, i), - 3 => module.vec_znx_big_sub_small_b_inplace(&mut res_big, i, &lhs.data, i), - _ => {} - } - module.vec_znx_big_normalize(basek, &mut self.data, i, &res_big, i, scratch1); - }); - } - - pub fn keyswitch_inplace<DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - rhs: &GLWESwitchingKey<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - unsafe { - let self_ptr: *mut GLWECiphertext<DataSelf> = self as *mut GLWECiphertext<DataSelf>; - self.keyswitch(&module, &*self_ptr, rhs, scratch); - } - } - - pub fn external_product<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - lhs: &GLWECiphertext<DataLhs>, - rhs: &GGSWCiphertext<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - let basek: usize = self.basek(); - - #[cfg(debug_assertions)] - { - assert_eq!(rhs.rank(), lhs.rank()); - assert_eq!(rhs.rank(), self.rank()); - assert_eq!(self.basek(), basek); - assert_eq!(lhs.basek(), basek); - assert_eq!(rhs.n(), module.n()); - assert_eq!(self.n(), module.n()); - assert_eq!(lhs.n(), module.n()); - assert!( - scratch.available() - >= GLWECiphertext::external_product_scratch_space( - module, - self.basek(), - self.k(), - lhs.k(), - rhs.k(), - rhs.digits(), - rhs.rank(), - ) - ); - } - - let cols: usize = rhs.rank() + 1; - let digits: usize = rhs.digits(); - - let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, cols, rhs.size()); // Todo optimise - let (mut a_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, cols, (lhs.size() + digits - 1) / digits); - - { - (0..digits).for_each(|di| { - // (lhs.size() + di) / digits = (a - (digit - di - 1) + digit - 1) / digits - a_dft.set_size((lhs.size() + di) / digits); - - // Small optimization for digits > 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^{(digits-1) * B}. - // As such we can ignore the last digits-2 limbs safely of the sum of vmp products. - // It is possible to further ignore the last digits-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(rhs.size() - ((digits - di) as isize - 2).max(0) as usize); - - (0..cols).for_each(|col_i| { - module.vec_znx_dft(digits, digits - 1 - di, &mut a_dft, col_i, &lhs.data, col_i); - }); - - if di == 0 { - module.vmp_apply(&mut res_dft, &a_dft, &rhs.data, scratch2); - } else { - module.vmp_apply_add(&mut res_dft, &a_dft, &rhs.data, di, scratch2); - } - }); - } - - let res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(res_dft); - - (0..cols).for_each(|i| { - module.vec_znx_big_normalize(basek, &mut self.data, i, &res_big, i, scratch1); - }); - } - - pub fn external_product_inplace<DataRhs: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - rhs: &GGSWCiphertext<DataRhs, FFT64>, - scratch: &mut Scratch, - ) { - unsafe { - let self_ptr: *mut GLWECiphertext<DataSelf> = self as *mut GLWECiphertext<DataSelf>; - self.external_product(&module, &*self_ptr, rhs, scratch); - } - } - - pub(crate) fn encrypt_sk_private<DataPt: AsRef<[u8]>, DataSk: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - pt: Option<(&GLWEPlaintext<DataPt>, usize)>, - sk: &GLWESecret<DataSk, FFT64>, - source_xa: &mut Source, - source_xe: &mut Source, - sigma: f64, - scratch: &mut Scratch, - ) { - #[cfg(debug_assertions)] - { - assert_eq!(self.rank(), sk.rank()); - assert_eq!(sk.n(), module.n()); - assert_eq!(self.n(), module.n()); - if let Some((pt, col)) = pt { - assert_eq!(pt.n(), module.n()); - assert!(col < self.rank() + 1); - } - assert!( - scratch.available() >= GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k()), - "scratch.available(): {} < GLWECiphertext::encrypt_sk_scratch_space: {}", - scratch.available(), - GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k()) - ) - } - - let basek: usize = self.basek(); - let k: usize = self.k(); - let size: usize = self.size(); - let cols: usize = self.rank() + 1; - - let (mut c0_big, scratch_1) = scratch.tmp_vec_znx(module, 1, size); - c0_big.zero(); - - { - // c[i] = uniform - // c[0] -= c[i] * s[i], - (1..cols).for_each(|i| { - let (mut ci_dft, scratch_2) = scratch_1.tmp_vec_znx_dft(module, 1, size); - - // c[i] = uniform - self.data.fill_uniform(basek, i, size, source_xa); - - // c[i] = norm(IDFT(DFT(c[i]) * DFT(s[i]))) - module.vec_znx_dft(1, 0, &mut ci_dft, 0, &self.data, i); - module.svp_apply_inplace(&mut ci_dft, 0, &sk.data_fourier, i - 1); - let ci_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(ci_dft); - - // use c[0] as buffer, which is overwritten later by the normalization step - module.vec_znx_big_normalize(basek, &mut self.data, 0, &ci_big, 0, scratch_2); - - // c0_tmp = -c[i] * s[i] (use c[0] as buffer) - module.vec_znx_sub_ab_inplace(&mut c0_big, 0, &self.data, 0); - - // c[i] += m if col = i - if let Some((pt, col)) = pt { - if i == col { - module.vec_znx_add_inplace(&mut self.data, i, &pt.data, 0); - module.vec_znx_normalize_inplace(basek, &mut self.data, i, scratch_2); - } - } - }); - } - - // c[0] += e - c0_big.add_normal(basek, 0, k, source_xe, sigma, sigma * SIX_SIGMA); - - // c[0] += m if col = 0 - if let Some((pt, col)) = pt { - if col == 0 { - module.vec_znx_add_inplace(&mut c0_big, 0, &pt.data, 0); - } - } - - // c[0] = norm(c[0]) - module.vec_znx_normalize(basek, &mut self.data, 0, &c0_big, 0, scratch_1); - } - - pub(crate) fn encrypt_pk_private<DataPt: AsRef<[u8]>, DataPk: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - pt: Option<(&GLWEPlaintext<DataPt>, usize)>, - pk: &GLWEPublicKey<DataPk, FFT64>, - source_xu: &mut Source, - source_xe: &mut Source, - sigma: f64, - scratch: &mut Scratch, - ) { - #[cfg(debug_assertions)] - { - assert_eq!(self.basek(), pk.basek()); - assert_eq!(self.n(), module.n()); - assert_eq!(pk.n(), module.n()); - assert_eq!(self.rank(), pk.rank()); - if let Some((pt, _)) = pt { - assert_eq!(pt.basek(), pk.basek()); - assert_eq!(pt.n(), module.n()); - } - } - - let basek: usize = pk.basek(); - let size_pk: usize = pk.size(); - let cols: usize = self.rank() + 1; - - // Generates u according to the underlying secret distribution. - let (mut u_dft, scratch_1) = scratch.tmp_scalar_znx_dft(module, 1); - - { - let (mut u, _) = scratch_1.tmp_scalar_znx(module, 1); - match pk.dist { - SecretDistribution::NONE => panic!( - "invalid public key: SecretDistribution::NONE, ensure it has been correctly intialized through \ - Self::generate" - ), - SecretDistribution::TernaryFixed(hw) => u.fill_ternary_hw(0, hw, source_xu), - SecretDistribution::TernaryProb(prob) => u.fill_ternary_prob(0, prob, source_xu), - SecretDistribution::BinaryFixed(hw) => u.fill_binary_hw(0, hw, source_xu), - SecretDistribution::BinaryProb(prob) => u.fill_binary_prob(0, prob, source_xu), - SecretDistribution::BinaryBlock(block_size) => u.fill_binary_block(0, block_size, source_xu), - SecretDistribution::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.tmp_vec_znx_dft(module, 1, size_pk); - // ci_dft = DFT(u) * DFT(pk[i]) - module.svp_apply(&mut ci_dft, 0, &u_dft, 0, &pk.data.data, i); - - // ci_big = u * p[i] - let mut ci_big = module.vec_znx_idft_consume(ci_dft); - - // ci_big = u * pk[i] + e - ci_big.add_normal(basek, 0, pk.k(), source_xe, sigma, sigma * SIX_SIGMA); - - // ci_big = u * pk[i] + e + m (if col = i) - if let Some((pt, col)) = pt { - if 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(basek, &mut self.data, i, &ci_big, 0, scratch_2); - }); - } -} - -impl<DataSelf: AsRef<[u8]>> GLWECiphertext<DataSelf> { - pub fn clone(&self) -> GLWECiphertext<Vec<u8>> { - GLWECiphertext { - data: self.data.clone(), - basek: self.basek(), - k: self.k(), - } - } - - pub fn decrypt<DataPt: AsMut<[u8]> + AsRef<[u8]>, DataSk: AsRef<[u8]>>( - &self, - module: &Module<FFT64>, - pt: &mut GLWEPlaintext<DataPt>, - sk: &GLWESecret<DataSk, FFT64>, - scratch: &mut Scratch, - ) { - #[cfg(debug_assertions)] - { - assert_eq!(self.rank(), sk.rank()); - assert_eq!(self.n(), module.n()); - assert_eq!(pt.n(), module.n()); - assert_eq!(sk.n(), module.n()); - } - - let cols: usize = self.rank() + 1; - - let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, self.size()); // TODO optimize size when pt << ct - c0_big.zero(); - - { - (1..cols).for_each(|i| { - // ci_dft = DFT(a[i]) * DFT(s[i]) - let (mut ci_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, self.size()); // TODO optimize size when pt << ct - module.vec_znx_dft(1, 0, &mut ci_dft, 0, &self.data, i); - module.svp_apply_inplace(&mut ci_dft, 0, &sk.data_fourier, i - 1); - let ci_big = module.vec_znx_idft_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.basek(), &mut pt.data, 0, &mut c0_big, 0, scratch_1); - - pt.basek = self.basek(); - pt.k = pt.k().min(self.k()); - } -} - -pub trait GLWECiphertextToRef { - fn to_ref(&self) -> GLWECiphertext<&[u8]>; -} - -impl<D: AsRef<[u8]>> GLWECiphertextToRef for GLWECiphertext<D> { - fn to_ref(&self) -> GLWECiphertext<&[u8]> { - GLWECiphertext { - data: self.data.to_ref(), - basek: self.basek, - k: self.k, - } - } -} - -pub trait GLWECiphertextToMut { - fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]>; -} - -impl<D: AsMut<[u8]> + AsRef<[u8]>> GLWECiphertextToMut for GLWECiphertext<D> { - fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]> { - GLWECiphertext { - data: self.data.to_mut(), - basek: self.basek, - k: self.k, - } - } -} - -impl<D> GLWEOps for GLWECiphertext<D> -where - D: AsRef<[u8]> + AsMut<[u8]>, - GLWECiphertext<D>: GLWECiphertextToMut + Infos + SetMetaData, -{ -}
M core/src/glwe_ciphertext_fourier.rs → core/src/fourier_glwe.rs

@@ -6,13 +6,13 @@ use sampling::source::Source;

use crate::{GGSWCiphertext, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos, ScratchCore}; -pub struct GLWECiphertextFourier<C, B: Backend> { +pub struct FourierGLWECiphertext<C, B: Backend> { pub data: VecZnxDft<C, B>, pub basek: usize, pub k: usize, } -impl<B: Backend> GLWECiphertextFourier<Vec<u8>, B> { +impl<B: Backend> FourierGLWECiphertext<Vec<u8>, B> { pub fn alloc(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self { Self { data: module.new_vec_znx_dft(rank + 1, k.div_ceil(basek)),

@@ -26,7 +26,7 @@ module.bytes_of_vec_znx_dft(rank + 1, k.div_ceil(basek))

} } -impl<T, B: Backend> Infos for GLWECiphertextFourier<T, B> { +impl<T, B: Backend> Infos for FourierGLWECiphertext<T, B> { type Inner = VecZnxDft<T, B>; fn inner(&self) -> &Self::Inner {

@@ -42,13 +42,13 @@ self.k

} } -impl<T, B: Backend> GLWECiphertextFourier<T, B> { +impl<T, B: Backend> FourierGLWECiphertext<T, B> { pub fn rank(&self) -> usize { self.cols() - 1 } } -impl GLWECiphertextFourier<Vec<u8>, FFT64> { +impl FourierGLWECiphertext<Vec<u8>, FFT64> { #[allow(dead_code)] pub(crate) fn idft_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize { module.bytes_of_vec_znx(1, k.div_ceil(basek))

@@ -125,7 +125,7 @@ Self::external_product_scratch_space(module, basek, k_out, k_out, k_ggsw, digits, rank)

} } -impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWECiphertextFourier<DataSelf, FFT64> { +impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> FourierGLWECiphertext<DataSelf, FFT64> { pub fn encrypt_zero_sk<DataSk: AsRef<[u8]>>( &mut self, module: &Module<FFT64>,

@@ -143,7 +143,7 @@

pub fn keyswitch<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( &mut self, module: &Module<FFT64>, - lhs: &GLWECiphertextFourier<DataLhs, FFT64>, + lhs: &FourierGLWECiphertext<DataLhs, FFT64>, rhs: &GLWESwitchingKey<DataRhs, FFT64>, scratch: &mut Scratch, ) {

@@ -159,7 +159,7 @@ rhs: &GLWESwitchingKey<DataRhs, FFT64>,

scratch: &mut Scratch, ) { unsafe { - let self_ptr: *mut GLWECiphertextFourier<DataSelf, FFT64> = self as *mut GLWECiphertextFourier<DataSelf, FFT64>; + let self_ptr: *mut FourierGLWECiphertext<DataSelf, FFT64> = self as *mut FourierGLWECiphertext<DataSelf, FFT64>; self.keyswitch(&module, &*self_ptr, rhs, scratch); } }

@@ -167,7 +167,7 @@

pub fn external_product<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>( &mut self, module: &Module<FFT64>, - lhs: &GLWECiphertextFourier<DataLhs, FFT64>, + lhs: &FourierGLWECiphertext<DataLhs, FFT64>, rhs: &GGSWCiphertext<DataRhs, FFT64>, scratch: &mut Scratch, ) {

@@ -184,7 +184,7 @@ assert_eq!(self.n(), module.n());

assert_eq!(lhs.n(), module.n()); assert!( scratch.available() - >= GLWECiphertextFourier::external_product_scratch_space( + >= FourierGLWECiphertext::external_product_scratch_space( module, self.basek(), self.k(),

@@ -246,13 +246,13 @@ rhs: &GGSWCiphertext<DataRhs, FFT64>,

scratch: &mut Scratch, ) { unsafe { - let self_ptr: *mut GLWECiphertextFourier<DataSelf, FFT64> = self as *mut GLWECiphertextFourier<DataSelf, FFT64>; + let self_ptr: *mut FourierGLWECiphertext<DataSelf, FFT64> = self as *mut FourierGLWECiphertext<DataSelf, FFT64>; self.external_product(&module, &*self_ptr, rhs, scratch); } } } -impl<DataSelf: AsRef<[u8]>> GLWECiphertextFourier<DataSelf, FFT64> { +impl<DataSelf: AsRef<[u8]>> FourierGLWECiphertext<DataSelf, FFT64> { pub fn decrypt<DataPt: AsRef<[u8]> + AsMut<[u8]>, DataSk: AsRef<[u8]>>( &self, module: &Module<FFT64>,
M core/src/glwe_plaintext.rs → core/src/glwe/plaintext.rs

@@ -1,6 +1,10 @@

use backend::{Backend, FFT64, Module, VecZnx, VecZnxAlloc, VecZnxToMut, VecZnxToRef}; -use crate::{GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, GLWEOps, Infos, SetMetaData}; +use crate::{ + GLWEOps, Infos, SetMetaData, + ciphertext::{GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef}, + div_ceil, +}; pub struct GLWEPlaintext<C> { pub data: VecZnx<C>,
M core/src/keys.rs → core/src/keys.rs

@@ -1,11 +1,3 @@

-use backend::{ - Backend, FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxDft, ScalarZnxDftAlloc, ScalarZnxDftOps, ScratchOwned, VecZnxDft, - ZnxInfos, ZnxZero, -}; -use sampling::source::Source; - -use crate::{GLWECiphertextFourier, Infos}; - #[derive(Clone, Copy, Debug)] pub(crate) enum SecretDistribution { TernaryFixed(usize), // Ternary with fixed Hamming weight

@@ -16,221 +8,3 @@ BinaryBlock(usize), // Binary split in block of size 2^k

ZERO, // Debug mod NONE, // Unitialized } - -pub struct LWESecret<T> { - pub(crate) data: ScalarZnx<T>, - pub(crate) dist: SecretDistribution, -} - -impl LWESecret<Vec<u8>> { - pub fn alloc(n: usize) -> Self { - Self { - data: ScalarZnx::new(n, 1), - dist: SecretDistribution::NONE, - } - } -} - -impl<DataSelf> LWESecret<DataSelf> { - pub fn n(&self) -> usize { - self.data.n() - } - - pub fn log_n(&self) -> usize { - self.data.log_n() - } - - pub fn rank(&self) -> usize { - self.data.cols() - } -} - -impl<D: AsRef<[u8]> + AsMut<[u8]>> LWESecret<D> { - pub fn fill_ternary_prob(&mut self, prob: f64, source: &mut Source) { - self.data.fill_ternary_prob(0, prob, source); - self.dist = SecretDistribution::TernaryProb(prob); - } - - pub fn fill_ternary_hw(&mut self, hw: usize, source: &mut Source) { - self.data.fill_ternary_hw(0, hw, source); - self.dist = SecretDistribution::TernaryFixed(hw); - } - - pub fn fill_binary_prob(&mut self, prob: f64, source: &mut Source) { - self.data.fill_binary_prob(0, prob, source); - self.dist = SecretDistribution::BinaryProb(prob); - } - - pub fn fill_binary_hw(&mut self, hw: usize, source: &mut Source) { - self.data.fill_binary_hw(0, hw, source); - self.dist = SecretDistribution::BinaryFixed(hw); - } - - pub fn fill_binary_block(&mut self, block_size: usize, source: &mut Source) { - self.data.fill_binary_block(0, block_size, source); - self.dist = SecretDistribution::BinaryBlock(block_size); - } - - pub fn fill_zero(&mut self) { - self.data.zero(); - self.dist = SecretDistribution::ZERO; - } -} - -pub struct GLWESecret<T, B: Backend> { - pub(crate) data: ScalarZnx<T>, - pub(crate) data_fourier: ScalarZnxDft<T, B>, - pub(crate) dist: SecretDistribution, -} - -impl<B: Backend> GLWESecret<Vec<u8>, B> { - pub fn alloc(module: &Module<B>, rank: usize) -> Self { - Self { - data: module.new_scalar_znx(rank), - data_fourier: module.new_scalar_znx_dft(rank), - dist: SecretDistribution::NONE, - } - } - - pub fn bytes_of(module: &Module<B>, rank: usize) -> usize { - module.bytes_of_scalar_znx(rank) + module.bytes_of_scalar_znx_dft(rank) - } -} - -impl<DataSelf, B: Backend> GLWESecret<DataSelf, B> { - pub fn n(&self) -> usize { - self.data.n() - } - - pub fn log_n(&self) -> usize { - self.data.log_n() - } - - pub fn rank(&self) -> usize { - self.data.cols() - } -} - -impl<S: AsMut<[u8]> + AsRef<[u8]>> GLWESecret<S, FFT64> { - pub fn fill_ternary_prob(&mut self, module: &Module<FFT64>, prob: f64, source: &mut Source) { - (0..self.rank()).for_each(|i| { - self.data.fill_ternary_prob(i, prob, source); - }); - self.prep_fourier(module); - self.dist = SecretDistribution::TernaryProb(prob); - } - - pub fn fill_ternary_hw(&mut self, module: &Module<FFT64>, hw: usize, source: &mut Source) { - (0..self.rank()).for_each(|i| { - self.data.fill_ternary_hw(i, hw, source); - }); - self.prep_fourier(module); - self.dist = SecretDistribution::TernaryFixed(hw); - } - - pub fn fill_binary_prob(&mut self, module: &Module<FFT64>, prob: f64, source: &mut Source) { - (0..self.rank()).for_each(|i| { - self.data.fill_binary_prob(i, prob, source); - }); - self.prep_fourier(module); - self.dist = SecretDistribution::BinaryProb(prob); - } - - pub fn fill_binary_hw(&mut self, module: &Module<FFT64>, hw: usize, source: &mut Source) { - (0..self.rank()).for_each(|i| { - self.data.fill_binary_hw(i, hw, source); - }); - self.prep_fourier(module); - self.dist = SecretDistribution::BinaryFixed(hw); - } - - pub fn fill_binary_block(&mut self, module: &Module<FFT64>, block_size: usize, source: &mut Source) { - (0..self.rank()).for_each(|i| { - self.data.fill_binary_block(i, block_size, source); - }); - self.prep_fourier(module); - self.dist = SecretDistribution::BinaryBlock(block_size); - } - - pub fn fill_zero(&mut self) { - self.data.zero(); - self.dist = SecretDistribution::ZERO; - } - - pub(crate) fn prep_fourier(&mut self, module: &Module<FFT64>) { - (0..self.rank()).for_each(|i| { - module.svp_prepare(&mut self.data_fourier, i, &self.data, i); - }); - } -} - -pub struct GLWEPublicKey<D, B: Backend> { - pub(crate) data: GLWECiphertextFourier<D, B>, - pub(crate) dist: SecretDistribution, -} - -impl<B: Backend> GLWEPublicKey<Vec<u8>, B> { - pub fn alloc(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self { - Self { - data: GLWECiphertextFourier::alloc(module, basek, k, rank), - dist: SecretDistribution::NONE, - } - } - - pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize { - GLWECiphertextFourier::<Vec<u8>, B>::bytes_of(module, basek, k, rank) - } -} - -impl<T, B: Backend> Infos for GLWEPublicKey<T, B> { - type Inner = VecZnxDft<T, B>; - - fn inner(&self) -> &Self::Inner { - &self.data.data - } - - fn basek(&self) -> usize { - self.data.basek - } - - fn k(&self) -> usize { - self.data.k - } -} - -impl<T, B: Backend> GLWEPublicKey<T, B> { - pub fn rank(&self) -> usize { - self.cols() - 1 - } -} - -impl<C: AsRef<[u8]> + AsMut<[u8]>> GLWEPublicKey<C, FFT64> { - pub fn generate_from_sk<S: AsRef<[u8]>>( - &mut self, - module: &Module<FFT64>, - sk: &GLWESecret<S, FFT64>, - source_xa: &mut Source, - source_xe: &mut Source, - sigma: f64, - ) { - #[cfg(debug_assertions)] - { - match sk.dist { - SecretDistribution::NONE => panic!("invalid sk: SecretDistribution::NONE"), - _ => {} - } - } - - // Its ok to allocate scratch space here since pk is usually generated only once. - let mut scratch: ScratchOwned = ScratchOwned::new(GLWECiphertextFourier::encrypt_sk_scratch_space( - module, - self.basek(), - self.k(), - self.rank(), - )); - - self.data - .encrypt_zero_sk(module, sk, source_xa, source_xe, sigma, scratch.borrow()); - self.dist = sk.dist; - } -}
M core/src/keyswitch_key.rs → core/src/keyswitch_key.rs

@@ -1,7 +1,7 @@

use backend::{Backend, FFT64, MatZnxDft, MatZnxDftOps, Module, Scratch, ZnxZero}; use sampling::source::Source; -use crate::{GGLWECiphertext, GGSWCiphertext, GLWECiphertextFourier, GLWESecret, GetRow, Infos, ScratchCore, SetRow}; +use crate::{FourierGLWECiphertext, GGLWECiphertext, GGSWCiphertext, GLWESecret, GetRow, Infos, ScratchCore, SetRow}; pub struct GLWESwitchingKey<Data, B: Backend>(pub(crate) GGLWECiphertext<Data, B>);

@@ -73,7 +73,7 @@ &self,

module: &Module<FFT64>, row_i: usize, col_j: usize, - res: &mut GLWECiphertextFourier<R, FFT64>, + res: &mut FourierGLWECiphertext<R, FFT64>, ) { module.mat_znx_dft_get_row(&mut res.data, &self.0.data, row_i, col_j); }

@@ -85,7 +85,7 @@ &mut self,

module: &Module<FFT64>, row_i: usize, col_j: usize, - a: &GLWECiphertextFourier<R, FFT64>, + a: &FourierGLWECiphertext<R, FFT64>, ) { module.mat_znx_dft_set_row(&mut self.0.data, row_i, col_j, &a.data); }

@@ -110,10 +110,10 @@ digits: usize,

rank_in: usize, rank_out: usize, ) -> usize { - let tmp_in: usize = GLWECiphertextFourier::bytes_of(module, basek, k_in, rank_in); - let tmp_out: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank_out); + let tmp_in: usize = FourierGLWECiphertext::bytes_of(module, basek, k_in, rank_in); + let tmp_out: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank_out); let ksk: usize = - GLWECiphertextFourier::keyswitch_scratch_space(module, basek, k_out, k_in, k_ksk, digits, rank_in, rank_out); + FourierGLWECiphertext::keyswitch_scratch_space(module, basek, k_out, k_in, k_ksk, digits, rank_in, rank_out); tmp_in + tmp_out + ksk }

@@ -125,8 +125,8 @@ k_ksk: usize,

digits: usize, rank: usize, ) -> usize { - let tmp: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank); - let ksk: usize = GLWECiphertextFourier::keyswitch_inplace_scratch_space(module, basek, k_out, k_ksk, digits, rank); + let tmp: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank); + let ksk: usize = FourierGLWECiphertext::keyswitch_inplace_scratch_space(module, basek, k_out, k_ksk, digits, rank); tmp + ksk }

@@ -139,9 +139,9 @@ k_ggsw: usize,

digits: usize, rank: usize, ) -> usize { - let tmp_in: usize = GLWECiphertextFourier::bytes_of(module, basek, k_in, rank); - let tmp_out: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank); - let ggsw: usize = GLWECiphertextFourier::external_product_scratch_space(module, basek, k_out, k_in, k_ggsw, digits, rank); + let tmp_in: usize = FourierGLWECiphertext::bytes_of(module, basek, k_in, rank); + let tmp_out: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank); + let ggsw: usize = FourierGLWECiphertext::external_product_scratch_space(module, basek, k_out, k_in, k_ggsw, digits, rank); tmp_in + tmp_out + ggsw }

@@ -153,9 +153,9 @@ k_ggsw: usize,

digits: usize, rank: usize, ) -> usize { - let tmp: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank); + let tmp: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank); let ggsw: usize = - GLWECiphertextFourier::external_product_inplace_scratch_space(module, basek, k_out, k_ggsw, digits, rank); + FourierGLWECiphertext::external_product_inplace_scratch_space(module, basek, k_out, k_ggsw, digits, rank); tmp + ggsw } }
M core/src/lib.rs → core/src/lib.rs

@@ -1,38 +1,35 @@

pub mod automorphism; pub mod blind_rotation; pub mod elem; -pub mod gglwe_ciphertext; -pub mod ggsw_ciphertext; -pub mod glwe_ciphertext; -pub mod glwe_ciphertext_fourier; -pub mod glwe_ops; -pub mod glwe_packing; -pub mod glwe_plaintext; +pub mod fourier_glwe; +pub mod gglwe; +pub mod ggsw; +pub mod glwe; pub mod keys; pub mod keyswitch_key; +pub mod lwe; pub mod tensor_key; #[cfg(test)] mod test_fft64; -pub mod trace; +mod utils; pub use automorphism::*; use backend::Backend; use backend::FFT64; use backend::Module; pub use elem::*; -pub use gglwe_ciphertext::*; -pub use ggsw_ciphertext::*; -pub use glwe_ciphertext::*; -pub use glwe_ciphertext_fourier::*; -pub use glwe_ops::*; -pub use glwe_packing::*; -pub use glwe_plaintext::*; -pub use keys::*; +pub use fourier_glwe::*; +pub use gglwe::*; +pub use ggsw::*; +pub use glwe::*; pub use keyswitch_key::*; +pub use lwe::*; pub use tensor_key::*; pub use backend::Scratch; pub use backend::ScratchOwned; + +use crate::keys::SecretDistribution; pub(crate) const SIX_SIGMA: f64 = 6.0;

@@ -64,7 +61,7 @@ module: &Module<B>,

basek: usize, k: usize, rank: usize, - ) -> (GLWECiphertextFourier<&mut [u8], B>, &mut Self); + ) -> (FourierGLWECiphertext<&mut [u8], B>, &mut Self); fn tmp_sk(&mut self, module: &Module<B>, rank: usize) -> (GLWESecret<&mut [u8], B>, &mut Self); fn tmp_glwe_pk( &mut self,

@@ -181,9 +178,9 @@ module: &Module<FFT64>,

basek: usize, k: usize, rank: usize, - ) -> (GLWECiphertextFourier<&mut [u8], FFT64>, &mut Self) { - let (data, scratch) = self.tmp_vec_znx_dft(module, rank + 1, k.div_ceil(basek)); - (GLWECiphertextFourier { data, basek, k }, scratch) + ) -> (FourierGLWECiphertext<&mut [u8], FFT64>, &mut Self) { + let (data, scratch) = self.tmp_vec_znx_dft(module, rank + 1, div_ceil(k, basek)); + (FourierGLWECiphertext { data, basek, k }, scratch) } fn tmp_glwe_pk(
A core/src/lwe.rs

@@ -0,0 +1,64 @@

+use backend::{ScalarZnx, ZnxInfos, ZnxZero}; +use sampling::source::Source; + +use crate::SecretDistribution; + +pub struct LWESecret<T> { + pub(crate) data: ScalarZnx<T>, + pub(crate) dist: SecretDistribution, +} + +impl LWESecret<Vec<u8>> { + pub fn alloc(n: usize) -> Self { + Self { + data: ScalarZnx::new(n, 1), + dist: SecretDistribution::NONE, + } + } +} + +impl<DataSelf> LWESecret<DataSelf> { + pub fn n(&self) -> usize { + self.data.n() + } + + pub fn log_n(&self) -> usize { + self.data.log_n() + } + + pub fn rank(&self) -> usize { + self.data.cols() + } +} + +impl<D: AsRef<[u8]> + AsMut<[u8]>> LWESecret<D> { + pub fn fill_ternary_prob(&mut self, prob: f64, source: &mut Source) { + self.data.fill_ternary_prob(0, prob, source); + self.dist = SecretDistribution::TernaryProb(prob); + } + + pub fn fill_ternary_hw(&mut self, hw: usize, source: &mut Source) { + self.data.fill_ternary_hw(0, hw, source); + self.dist = SecretDistribution::TernaryFixed(hw); + } + + pub fn fill_binary_prob(&mut self, prob: f64, source: &mut Source) { + self.data.fill_binary_prob(0, prob, source); + self.dist = SecretDistribution::BinaryProb(prob); + } + + pub fn fill_binary_hw(&mut self, hw: usize, source: &mut Source) { + self.data.fill_binary_hw(0, hw, source); + self.dist = SecretDistribution::BinaryFixed(hw); + } + + pub fn fill_binary_block(&mut self, block_size: usize, source: &mut Source) { + self.data.fill_binary_block(0, block_size, source); + self.dist = SecretDistribution::BinaryBlock(block_size); + } + + pub fn fill_zero(&mut self) { + self.data.zero(); + self.dist = SecretDistribution::ZERO; + } +}
M core/src/test_fft64/automorphism_key.rs → core/src/test_fft64/automorphism_key.rs

@@ -2,7 +2,8 @@ use backend::{FFT64, Module, ScalarZnxOps, ScratchOwned, Stats, VecZnxOps};

use sampling::source::Source; use crate::{ - AutomorphismKey, GLWECiphertextFourier, GLWEPlaintext, GLWESecret, GetRow, Infos, test_fft64::log2_std_noise_gglwe_product, + AutomorphismKey, FourierGLWECiphertext, GLWEPlaintext, GLWESecret, GetRow, Infos, div_ceil, + test_fft64::log2_std_noise_gglwe_product, }; #[test]

@@ -69,7 +70,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_apply, rank) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_out) + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_out) | AutomorphismKey::automorphism_scratch_space(&module, basek, k_out, k_in, k_apply, digits, rank), );

@@ -101,7 +102,7 @@

// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0) auto_key_out.automorphism(&module, &auto_key_in, &auto_key_apply, scratch.borrow()); - let mut ct_glwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_out, rank); + let mut ct_glwe_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_out, rank); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out); let mut sk_auto: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);

@@ -183,7 +184,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_apply, rank) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_in) + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_in) | AutomorphismKey::automorphism_inplace_scratch_space(&module, basek, k_in, k_apply, digits, rank), );

@@ -215,7 +216,7 @@

// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0) auto_key.automorphism_inplace(&module, &auto_key_apply, scratch.borrow()); - let mut ct_glwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_in, rank); + let mut ct_glwe_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_in, rank); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_in); let mut sk_auto: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
M core/src/test_fft64/gglwe.rs → core/src/test_fft64/gglwe.rs

@@ -2,7 +2,7 @@ use backend::{FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxToMut, ScratchOwned, Stats, VecZnxOps, ZnxViewMut};

use sampling::source::Source; use crate::{ - GGSWCiphertext, GLWECiphertextFourier, GLWEPlaintext, GLWESecret, GLWESwitchingKey, GetRow, Infos, + FourierGLWECiphertext, GGSWCiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, GetRow, Infos, div_ceil, test_fft64::{log2_std_noise_gglwe_product, noise_ggsw_product}, };

@@ -145,7 +145,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank_out) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_ksk), + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_ksk), ); let mut sk_in: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank_in);

@@ -164,8 +164,8 @@ sigma,

scratch.borrow(), ); - let mut ct_glwe_fourier: GLWECiphertextFourier<Vec<u8>, FFT64> = - GLWECiphertextFourier::alloc(&module, basek, k_ksk, rank_out); + let mut ct_glwe_fourier: FourierGLWECiphertext<Vec<u8>, FFT64> = + FourierGLWECiphertext::alloc(&module, basek, k_ksk, rank_out); (0..ksk.rank_in()).for_each(|col_i| { (0..ksk.rows()).for_each(|row_i| {

@@ -234,7 +234,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank_in_s0s1 | rank_out_s0s1) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_out) + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_out) | GLWESwitchingKey::keyswitch_scratch_space( &module, basek,

@@ -281,8 +281,8 @@

// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0) ct_gglwe_s0s2.keyswitch(&module, &ct_gglwe_s0s1, &ct_gglwe_s1s2, scratch.borrow()); - let mut ct_glwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = - GLWECiphertextFourier::alloc(&module, basek, k_out, rank_out_s1s2); + let mut ct_glwe_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = + FourierGLWECiphertext::alloc(&module, basek, k_out, rank_out_s1s2); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out); (0..ct_gglwe_s0s2.rank_in()).for_each(|col_i| {

@@ -346,7 +346,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank_out) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_ksk) + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_ksk) | GLWESwitchingKey::keyswitch_inplace_scratch_space(&module, basek, k_ct, k_ksk, digits, rank_out), );

@@ -386,7 +386,7 @@ ct_gglwe_s0s1.keyswitch_inplace(&module, &ct_gglwe_s1s2, scratch.borrow());

let ct_gglwe_s0s2: GLWESwitchingKey<Vec<u8>, FFT64> = ct_gglwe_s0s1; - let mut ct_glwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_ct, rank_out); + let mut ct_glwe_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_ct, rank_out); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct); (0..ct_gglwe_s0s2.rank_in()).for_each(|col_i| {

@@ -455,7 +455,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_in, rank_out) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_out) + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_out) | GLWESwitchingKey::external_product_scratch_space(&module, basek, k_out, k_in, k_ggsw, digits, rank_out) | GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_ggsw, rank_out), );

@@ -494,7 +494,7 @@

// gglwe_(m) (x) RGSW_(X^k) = gglwe_(m * X^k) ct_gglwe_out.external_product(&module, &ct_gglwe_in, &ct_rgsw, scratch.borrow()); - let mut ct_glwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_out, rank_out); + let mut ct_glwe_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_out, rank_out); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out); (0..rank_in).for_each(|i| {

@@ -575,7 +575,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ct, rank_out) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_ct) + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_ct) | GLWESwitchingKey::external_product_inplace_scratch_space(&module, basek, k_ct, k_ggsw, digits, rank_out) | GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_ggsw, rank_out), );

@@ -614,7 +614,7 @@

// gglwe_(m) (x) RGSW_(X^k) = gglwe_(m * X^k) ct_gglwe.external_product_inplace(&module, &ct_rgsw, scratch.borrow()); - let mut ct_glwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_ct, rank_out); + let mut ct_glwe_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_ct, rank_out); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct); (0..rank_in).for_each(|i| {
M core/src/test_fft64/ggsw.rs → core/src/test_fft64/ggsw.rs

@@ -5,7 +5,7 @@ };

use sampling::source::Source; use crate::{ - GGSWCiphertext, GLWECiphertextFourier, GLWEPlaintext, GLWESecret, GLWESwitchingKey, GetRow, Infos, TensorKey, + FourierGLWECiphertext, GGSWCiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, GetRow, Infos, TensorKey, automorphism::AutomorphismKey, test_fft64::{noise_ggsw_keyswitch, noise_ggsw_product}, };

@@ -139,7 +139,7 @@ pt_scalar.fill_ternary_hw(0, module.n(), &mut source_xs);

let mut scratch: ScratchOwned = ScratchOwned::new( GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k, rank) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k), + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k), ); let mut sk: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);

@@ -155,7 +155,7 @@ sigma,

scratch.borrow(), ); - let mut ct_glwe_fourier: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k, rank); + let mut ct_glwe_fourier: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k, rank); let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct.size()); let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct.size());

@@ -221,7 +221,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_in, rank) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_out) + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_out) | GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank) | TensorKey::generate_from_sk_scratch_space(&module, basek, k_tsk, rank) | GGSWCiphertext::keyswitch_scratch_space(

@@ -269,7 +269,7 @@ );

ct_out.keyswitch(&module, &ct_in, &ksk, &tsk, scratch.borrow()); - let mut ct_glwe_fourier: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_out, rank); + let mut ct_glwe_fourier: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_out, rank); let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_out.size()); let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_out.size());

@@ -348,7 +348,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_ct, rank) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_ct) + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_ct) | GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank) | TensorKey::generate_from_sk_scratch_space(&module, basek, k_tsk, rank) | GGSWCiphertext::keyswitch_inplace_scratch_space(&module, basek, k_ct, k_ksk, digits, k_tsk, digits, rank),

@@ -394,7 +394,7 @@ );

ct.keyswitch_inplace(&module, &ksk, &tsk, scratch.borrow()); - let mut ct_glwe_fourier: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_ct, rank); + let mut ct_glwe_fourier: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_ct, rank); let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct.size()); let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct.size());

@@ -483,7 +483,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_in, rank) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_out) + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_out) | AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_ksk, rank) | TensorKey::generate_from_sk_scratch_space(&module, basek, k_tsk, rank) | GGSWCiphertext::automorphism_scratch_space(

@@ -530,7 +530,7 @@ ct_out.automorphism(&module, &ct_in, &auto_key, &tensor_key, scratch.borrow());

module.scalar_znx_automorphism_inplace(p, &mut pt_scalar, 0); - let mut ct_glwe_fourier: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_out, rank); + let mut ct_glwe_fourier: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_out, rank); let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_out.size()); let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_out.size());

@@ -608,7 +608,7 @@ let mut source_xa: Source = Source::new([0u8; 32]);

let mut scratch: ScratchOwned = ScratchOwned::new( GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_ct, rank) - | GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_ct) + | FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_ct) | AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_ksk, rank) | TensorKey::generate_from_sk_scratch_space(&module, basek, k_tsk, rank) | GGSWCiphertext::automorphism_inplace_scratch_space(&module, basek, k_ct, k_ksk, digits, k_tsk, digits, rank),

@@ -653,7 +653,7 @@ ct.automorphism_inplace(&module, &auto_key, &tensor_key, scratch.borrow());

module.scalar_znx_automorphism_inplace(p, &mut pt_scalar, 0); - let mut ct_glwe_fourier: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_ct, rank); + let mut ct_glwe_fourier: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_ct, rank); let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct.size()); let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct.size());

@@ -737,7 +737,7 @@

pt_ggsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k} let mut scratch: ScratchOwned = ScratchOwned::new( - GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_out) + FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_out) | GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_ggsw, rank) | GGSWCiphertext::external_product_scratch_space(&module, basek, k_out, k_in, k_ggsw, digits, rank), );

@@ -767,7 +767,7 @@ );

ct_ggsw_lhs_out.external_product(&module, &ct_ggsw_lhs_in, &ct_ggsw_rhs, scratch.borrow()); - let mut ct_glwe_fourier: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_out, rank); + let mut ct_glwe_fourier: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_out, rank); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out); let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_ggsw_lhs_out.size()); let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_ggsw_lhs_out.size());

@@ -857,7 +857,7 @@

pt_ggsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k} let mut scratch: ScratchOwned = ScratchOwned::new( - GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_ct) + FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_ct) | GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_ggsw, rank) | GGSWCiphertext::external_product_inplace_scratch_space(&module, basek, k_ct, k_ggsw, digits, rank), );

@@ -887,7 +887,7 @@ );

ct_ggsw_lhs.external_product_inplace(&module, &ct_ggsw_rhs, scratch.borrow()); - let mut ct_glwe_fourier: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_ct, rank); + let mut ct_glwe_fourier: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_ct, rank); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct); let mut pt_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(1, ct_ggsw_lhs.size()); let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_ggsw_lhs.size());
M core/src/test_fft64/glwe.rs → core/src/test_fft64/glwe.rs

@@ -6,7 +6,7 @@ use itertools::izip;

use sampling::source::Source; use crate::{ - GGSWCiphertext, GLWECiphertext, GLWECiphertextFourier, GLWEPlaintext, GLWEPublicKey, GLWESecret, Infos, + FourierGLWECiphertext, GGSWCiphertext, GLWECiphertext, GLWEPlaintext, GLWEPublicKey, GLWESecret, Infos, automorphism::AutomorphismKey, keyswitch_key::GLWESwitchingKey, test_fft64::{log2_std_noise_gglwe_product, noise_ggsw_product},

@@ -207,11 +207,11 @@

let mut sk: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank); sk.fill_ternary_prob(&module, 0.5, &mut source_xs); - let mut ct_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_ct, rank); + let mut ct_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_ct, rank); let mut scratch: ScratchOwned = ScratchOwned::new( - GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_ct) - | GLWECiphertextFourier::encrypt_sk_scratch_space(&module, basek, k_ct, rank), + FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_ct) + | FourierGLWECiphertext::encrypt_sk_scratch_space(&module, basek, k_ct, rank), ); ct_dft.encrypt_zero_sk(
M core/src/test_fft64/glwe_fourier.rs → core/src/test_fft64/glwe_fourier.rs

@@ -1,5 +1,5 @@

use crate::{ - GGSWCiphertext, GLWECiphertext, GLWECiphertextFourier, GLWEOps, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos, + FourierGLWECiphertext, GGSWCiphertext, GLWECiphertext, GLWEOps, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos, div_ceil, test_fft64::{log2_std_noise_gglwe_product, noise_ggsw_product}, }; use backend::{FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, ZnxViewMut};

@@ -90,10 +90,10 @@

let mut ksk: GLWESwitchingKey<Vec<u8>, FFT64> = GLWESwitchingKey::alloc(&module, basek, k_ksk, rows, digits, rank_in, rank_out); let mut ct_glwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_in, rank_in); - let mut ct_glwe_dft_in: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_in, rank_in); + let mut ct_glwe_dft_in: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_in, rank_in); let mut ct_glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_out, rank_out); - let mut ct_glwe_dft_out: GLWECiphertextFourier<Vec<u8>, FFT64> = - GLWECiphertextFourier::alloc(&module, basek, k_out, rank_out); + let mut ct_glwe_dft_out: FourierGLWECiphertext<Vec<u8>, FFT64> = + FourierGLWECiphertext::alloc(&module, basek, k_out, rank_out); let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_in); let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out);

@@ -110,7 +110,7 @@ let mut scratch: ScratchOwned = ScratchOwned::new(

GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank_out) | GLWECiphertext::decrypt_scratch_space(&module, basek, k_out) | GLWECiphertext::encrypt_sk_scratch_space(&module, basek, k_in) - | GLWECiphertextFourier::keyswitch_scratch_space( + | FourierGLWECiphertext::keyswitch_scratch_space( &module, basek, ct_glwe_out.k(),

@@ -185,7 +185,7 @@ let rows: usize = k_ct.div_ceil(basek * digits);

let mut ksk: GLWESwitchingKey<Vec<u8>, FFT64> = GLWESwitchingKey::alloc(&module, basek, k_ksk, rows, digits, rank, rank); let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_ct, rank); - let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_ct, rank); + let mut ct_rlwe_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_ct, rank); let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct); let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct);

@@ -202,7 +202,7 @@ let mut scratch: ScratchOwned = ScratchOwned::new(

GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, ksk.k(), rank) | GLWECiphertext::decrypt_scratch_space(&module, basek, ct_glwe.k()) | GLWECiphertext::encrypt_sk_scratch_space(&module, basek, ct_glwe.k()) - | GLWECiphertextFourier::keyswitch_inplace_scratch_space(&module, basek, ct_rlwe_dft.k(), ksk.k(), digits, rank), + | FourierGLWECiphertext::keyswitch_inplace_scratch_space(&module, basek, ct_rlwe_dft.k(), ksk.k(), digits, rank), ); let mut sk_in: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);

@@ -278,8 +278,8 @@

let mut ct_ggsw: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::alloc(&module, basek, k_ggsw, rows, digits, rank); let mut ct_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_in, rank); let mut ct_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_out, rank); - let mut ct_in_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_in, rank); - let mut ct_out_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_out, rank); + let mut ct_in_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_in, rank); + let mut ct_out_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_out, rank); let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_in); let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out);

@@ -304,7 +304,7 @@ let mut scratch: ScratchOwned = ScratchOwned::new(

GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, ct_ggsw.k(), rank) | GLWECiphertext::decrypt_scratch_space(&module, basek, ct_out.k()) | GLWECiphertext::encrypt_sk_scratch_space(&module, basek, ct_in.k()) - | GLWECiphertextFourier::external_product_scratch_space( + | FourierGLWECiphertext::external_product_scratch_space( &module, basek, ct_out.k(),

@@ -384,7 +384,7 @@ let rows: usize = k_ct.div_ceil(basek * digits);

let mut ct_ggsw: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::alloc(&module, basek, k_ggsw, rows, digits, rank); let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_ct, rank); - let mut ct_rlwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k_ct, rank); + let mut ct_rlwe_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k_ct, rank); let mut pt_rgsw: ScalarZnx<Vec<u8>> = module.new_scalar_znx(1); let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct); let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct);

@@ -409,7 +409,7 @@ let mut scratch: ScratchOwned = ScratchOwned::new(

GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, ct_ggsw.k(), rank) | GLWECiphertext::decrypt_scratch_space(&module, basek, ct.k()) | GLWECiphertext::encrypt_sk_scratch_space(&module, basek, ct.k()) - | GLWECiphertextFourier::external_product_inplace_scratch_space(&module, basek, ct.k(), ct_ggsw.k(), digits, rank), + | FourierGLWECiphertext::external_product_inplace_scratch_space(&module, basek, ct.k(), ct_ggsw.k(), digits, rank), ); let mut sk: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
M core/src/test_fft64/tensor_key.rs → core/src/test_fft64/tensor_key.rs

@@ -1,7 +1,7 @@

use backend::{FFT64, Module, ScalarZnxDftOps, ScratchOwned, Stats, VecZnxOps}; use sampling::source::Source; -use crate::{GLWECiphertextFourier, GLWEPlaintext, GLWESecret, GetRow, Infos, TensorKey}; +use crate::{FourierGLWECiphertext, GLWEPlaintext, GLWESecret, GetRow, Infos, TensorKey}; #[test] fn encrypt_sk() {

@@ -42,7 +42,7 @@ sigma,

scratch.borrow(), ); - let mut ct_glwe_fourier: GLWECiphertextFourier<Vec<u8>, FFT64> = GLWECiphertextFourier::alloc(&module, basek, k, rank); + let mut ct_glwe_fourier: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::alloc(&module, basek, k, rank); let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k); let mut sk_ij = GLWESecret::alloc(&module, 1);