mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 13:16:44 +01:00
Code organisation for glwe
This commit is contained in:
@@ -2,7 +2,7 @@ use backend::{Backend, FFT64, MatZnxDft, MatZnxDftOps, Module, ScalarZnxOps, Scr
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
GGLWECiphertext, GGSWCiphertext, GLWECiphertext, GLWECiphertextFourier, GLWESecret, GLWESwitchingKey, GetRow, Infos,
|
FourierGLWECiphertext, GGLWECiphertext, GGSWCiphertext, GLWECiphertext, GLWESecret, GLWESwitchingKey, GetRow, Infos,
|
||||||
ScratchCore, SetRow,
|
ScratchCore, SetRow,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ impl<C: AsRef<[u8]>> GetRow<FFT64> for AutomorphismKey<C, FFT64> {
|
|||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
row_i: usize,
|
row_i: usize,
|
||||||
col_j: 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);
|
module.mat_znx_dft_get_row(&mut res.data, &self.key.0.data, row_i, col_j);
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ impl<C: AsMut<[u8]> + AsRef<[u8]>> SetRow<FFT64> for AutomorphismKey<C, FFT64> {
|
|||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
row_i: usize,
|
row_i: usize,
|
||||||
col_j: 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);
|
module.mat_znx_dft_set_row(&mut self.key.0.data, row_i, col_j, &a.data);
|
||||||
}
|
}
|
||||||
@@ -127,8 +127,8 @@ impl AutomorphismKey<Vec<u8>, FFT64> {
|
|||||||
digits: usize,
|
digits: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let tmp_dft: usize = GLWECiphertextFourier::bytes_of(module, basek, k_in, rank);
|
let tmp_dft: usize = FourierGLWECiphertext::bytes_of(module, basek, k_in, rank);
|
||||||
let tmp_idft: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank);
|
let tmp_idft: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank);
|
||||||
let idft: usize = module.vec_znx_idft_tmp_bytes();
|
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);
|
let keyswitch: usize = GLWECiphertext::keyswitch_inplace_scratch_space(module, basek, k_out, k_ksk, digits, rank);
|
||||||
tmp_dft + tmp_idft + idft + keyswitch
|
tmp_dft + tmp_idft + idft + keyswitch
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ impl BlindRotationKeyCGGI<FFT64> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>(
|
pub fn generate_from_sk<DataSkGLWE, DataSkLWE>(
|
||||||
&mut self,
|
&mut self,
|
||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use backend::{Backend, Module, ZnxInfos};
|
use backend::{Backend, Module, ZnxInfos};
|
||||||
|
|
||||||
use crate::GLWECiphertextFourier;
|
use crate::{FourierGLWECiphertext, div_ceil};
|
||||||
|
|
||||||
pub trait Infos {
|
pub trait Infos {
|
||||||
type Inner: ZnxInfos;
|
type Inner: ZnxInfos;
|
||||||
@@ -56,13 +56,13 @@ pub trait SetMetaData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait GetRow<B: Backend> {
|
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
|
where
|
||||||
R: AsMut<[u8]> + AsRef<[u8]>;
|
R: AsMut<[u8]> + AsRef<[u8]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SetRow<B: Backend> {
|
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
|
where
|
||||||
R: AsRef<[u8]>;
|
R: AsRef<[u8]>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ use sampling::source::Source;
|
|||||||
|
|
||||||
use crate::{GGSWCiphertext, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos, ScratchCore};
|
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 data: VecZnxDft<C, B>,
|
||||||
pub basek: usize,
|
pub basek: usize,
|
||||||
pub k: 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 {
|
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: module.new_vec_znx_dft(rank + 1, k.div_ceil(basek)),
|
data: module.new_vec_znx_dft(rank + 1, k.div_ceil(basek)),
|
||||||
@@ -26,7 +26,7 @@ impl<B: Backend> GLWECiphertextFourier<Vec<u8>, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, B: Backend> Infos for GLWECiphertextFourier<T, B> {
|
impl<T, B: Backend> Infos for FourierGLWECiphertext<T, B> {
|
||||||
type Inner = VecZnxDft<T, B>;
|
type Inner = VecZnxDft<T, B>;
|
||||||
|
|
||||||
fn inner(&self) -> &Self::Inner {
|
fn inner(&self) -> &Self::Inner {
|
||||||
@@ -42,13 +42,13 @@ impl<T, B: Backend> Infos for GLWECiphertextFourier<T, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, B: Backend> GLWECiphertextFourier<T, B> {
|
impl<T, B: Backend> FourierGLWECiphertext<T, B> {
|
||||||
pub fn rank(&self) -> usize {
|
pub fn rank(&self) -> usize {
|
||||||
self.cols() - 1
|
self.cols() - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GLWECiphertextFourier<Vec<u8>, FFT64> {
|
impl FourierGLWECiphertext<Vec<u8>, FFT64> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn idft_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize {
|
pub(crate) fn idft_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize {
|
||||||
module.bytes_of_vec_znx(1, k.div_ceil(basek))
|
module.bytes_of_vec_znx(1, k.div_ceil(basek))
|
||||||
@@ -125,7 +125,7 @@ impl GLWECiphertextFourier<Vec<u8>, FFT64> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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]>>(
|
pub fn encrypt_zero_sk<DataSk: AsRef<[u8]>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
@@ -143,7 +143,7 @@ impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWECiphertextFourier<DataSelf, FFT64>
|
|||||||
pub fn keyswitch<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>(
|
pub fn keyswitch<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
lhs: &GLWECiphertextFourier<DataLhs, FFT64>,
|
lhs: &FourierGLWECiphertext<DataLhs, FFT64>,
|
||||||
rhs: &GLWESwitchingKey<DataRhs, FFT64>,
|
rhs: &GLWESwitchingKey<DataRhs, FFT64>,
|
||||||
scratch: &mut Scratch,
|
scratch: &mut Scratch,
|
||||||
) {
|
) {
|
||||||
@@ -159,7 +159,7 @@ impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWECiphertextFourier<DataSelf, FFT64>
|
|||||||
scratch: &mut Scratch,
|
scratch: &mut Scratch,
|
||||||
) {
|
) {
|
||||||
unsafe {
|
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);
|
self.keyswitch(&module, &*self_ptr, rhs, scratch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,7 +167,7 @@ impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWECiphertextFourier<DataSelf, FFT64>
|
|||||||
pub fn external_product<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>(
|
pub fn external_product<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
lhs: &GLWECiphertextFourier<DataLhs, FFT64>,
|
lhs: &FourierGLWECiphertext<DataLhs, FFT64>,
|
||||||
rhs: &GGSWCiphertext<DataRhs, FFT64>,
|
rhs: &GGSWCiphertext<DataRhs, FFT64>,
|
||||||
scratch: &mut Scratch,
|
scratch: &mut Scratch,
|
||||||
) {
|
) {
|
||||||
@@ -184,7 +184,7 @@ impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWECiphertextFourier<DataSelf, FFT64>
|
|||||||
assert_eq!(lhs.n(), module.n());
|
assert_eq!(lhs.n(), module.n());
|
||||||
assert!(
|
assert!(
|
||||||
scratch.available()
|
scratch.available()
|
||||||
>= GLWECiphertextFourier::external_product_scratch_space(
|
>= FourierGLWECiphertext::external_product_scratch_space(
|
||||||
module,
|
module,
|
||||||
self.basek(),
|
self.basek(),
|
||||||
self.k(),
|
self.k(),
|
||||||
@@ -246,13 +246,13 @@ impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWECiphertextFourier<DataSelf, FFT64>
|
|||||||
scratch: &mut Scratch,
|
scratch: &mut Scratch,
|
||||||
) {
|
) {
|
||||||
unsafe {
|
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);
|
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]>>(
|
pub fn decrypt<DataPt: AsRef<[u8]> + AsMut<[u8]>, DataSk: AsRef<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
@@ -4,7 +4,7 @@ use backend::{
|
|||||||
};
|
};
|
||||||
use sampling::source::Source;
|
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 struct GGLWECiphertext<C, B: Backend> {
|
||||||
pub(crate) data: MatZnxDft<C, B>,
|
pub(crate) data: MatZnxDft<C, B>,
|
||||||
@@ -217,7 +217,7 @@ impl<C: AsRef<[u8]>> GetRow<FFT64> for GGLWECiphertext<C, FFT64> {
|
|||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
row_i: usize,
|
row_i: usize,
|
||||||
col_j: 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);
|
module.mat_znx_dft_get_row(&mut res.data, &self.data, row_i, col_j);
|
||||||
}
|
}
|
||||||
@@ -229,7 +229,7 @@ impl<C: AsMut<[u8]> + AsRef<[u8]>> SetRow<FFT64> for GGLWECiphertext<C, FFT64> {
|
|||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
row_i: usize,
|
row_i: usize,
|
||||||
col_j: 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);
|
module.mat_znx_dft_set_row(&mut self.data, row_i, col_j, &a.data);
|
||||||
}
|
}
|
||||||
@@ -6,8 +6,8 @@ use backend::{
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AutomorphismKey, GLWECiphertext, GLWECiphertextFourier, GLWESecret, GLWESwitchingKey, GetRow, Infos, ScratchCore, SetRow,
|
AutomorphismKey, FourierGLWECiphertext, GLWECiphertext, GLWESecret, GLWESwitchingKey, GetRow, Infos, ScratchCore, SetRow,
|
||||||
TensorKey,
|
TensorKey, div_ceil,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct GGSWCiphertext<C, B: Backend> {
|
pub struct GGSWCiphertext<C, B: Backend> {
|
||||||
@@ -220,9 +220,9 @@ impl GGSWCiphertext<Vec<u8>, FFT64> {
|
|||||||
digits: usize,
|
digits: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let tmp_in: usize = GLWECiphertextFourier::bytes_of(module, basek, k_in, rank);
|
let tmp_in: usize = FourierGLWECiphertext::bytes_of(module, basek, k_in, rank);
|
||||||
let tmp_out: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank);
|
let tmp_out: usize = FourierGLWECiphertext::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 ggsw: usize = FourierGLWECiphertext::external_product_scratch_space(module, basek, k_out, k_in, k_ggsw, digits, rank);
|
||||||
tmp_in + tmp_out + ggsw
|
tmp_in + tmp_out + ggsw
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,9 +234,9 @@ impl GGSWCiphertext<Vec<u8>, FFT64> {
|
|||||||
digits: usize,
|
digits: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> 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 =
|
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
|
tmp + ggsw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -686,7 +686,7 @@ impl<DataSelf: AsRef<[u8]>> GetRow<FFT64> for GGSWCiphertext<DataSelf, FFT64> {
|
|||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
row_i: usize,
|
row_i: usize,
|
||||||
col_j: 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);
|
module.mat_znx_dft_get_row(&mut res.data, &self.data, row_i, col_j);
|
||||||
}
|
}
|
||||||
@@ -698,7 +698,7 @@ impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> SetRow<FFT64> for GGSWCiphertext<DataS
|
|||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
row_i: usize,
|
row_i: usize,
|
||||||
col_j: 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);
|
module.mat_znx_dft_set_row(&mut self.data, row_i, col_j, &a.data);
|
||||||
}
|
}
|
||||||
121
core/src/glwe/automorphism.rs
Normal file
121
core/src/glwe/automorphism.rs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
115
core/src/glwe/ciphertext.rs
Normal file
115
core/src/glwe/ciphertext.rs
Normal file
@@ -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,
|
||||||
|
{
|
||||||
|
}
|
||||||
56
core/src/glwe/decryption.rs
Normal file
56
core/src/glwe/decryption.rs
Normal file
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
254
core/src/glwe/encryption.rs
Normal file
254
core/src/glwe/encryption.rs
Normal file
@@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
129
core/src/glwe/external_product.rs
Normal file
129
core/src/glwe/external_product.rs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
244
core/src/glwe/keyswitch.rs
Normal file
244
core/src/glwe/keyswitch.rs
Normal file
@@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
31
core/src/glwe/mod.rs
Normal file
31
core/src/glwe/mod.rs
Normal file
@@ -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::*;
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
use backend::{Backend, FFT64, Module, VecZnx, VecZnxAlloc, VecZnxToMut, VecZnxToRef};
|
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 struct GLWEPlaintext<C> {
|
||||||
pub data: VecZnx<C>,
|
pub data: VecZnx<C>,
|
||||||
75
core/src/glwe/public_key.rs
Normal file
75
core/src/glwe/public_key.rs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
93
core/src/glwe/secret.rs
Normal file
93
core/src/glwe/secret.rs
Normal file
@@ -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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
226
core/src/keys.rs
226
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)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub(crate) enum SecretDistribution {
|
pub(crate) enum SecretDistribution {
|
||||||
TernaryFixed(usize), // Ternary with fixed Hamming weight
|
TernaryFixed(usize), // Ternary with fixed Hamming weight
|
||||||
@@ -16,221 +8,3 @@ pub(crate) enum SecretDistribution {
|
|||||||
ZERO, // Debug mod
|
ZERO, // Debug mod
|
||||||
NONE, // Unitialized
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use backend::{Backend, FFT64, MatZnxDft, MatZnxDftOps, Module, Scratch, ZnxZero};
|
use backend::{Backend, FFT64, MatZnxDft, MatZnxDftOps, Module, Scratch, ZnxZero};
|
||||||
use sampling::source::Source;
|
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>);
|
pub struct GLWESwitchingKey<Data, B: Backend>(pub(crate) GGLWECiphertext<Data, B>);
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ impl<C: AsRef<[u8]>> GetRow<FFT64> for GLWESwitchingKey<C, FFT64> {
|
|||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
row_i: usize,
|
row_i: usize,
|
||||||
col_j: 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);
|
module.mat_znx_dft_get_row(&mut res.data, &self.0.data, row_i, col_j);
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ impl<C: AsMut<[u8]> + AsRef<[u8]>> SetRow<FFT64> for GLWESwitchingKey<C, FFT64>
|
|||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
row_i: usize,
|
row_i: usize,
|
||||||
col_j: 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);
|
module.mat_znx_dft_set_row(&mut self.0.data, row_i, col_j, &a.data);
|
||||||
}
|
}
|
||||||
@@ -110,10 +110,10 @@ impl GLWESwitchingKey<Vec<u8>, FFT64> {
|
|||||||
rank_in: usize,
|
rank_in: usize,
|
||||||
rank_out: usize,
|
rank_out: usize,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let tmp_in: usize = GLWECiphertextFourier::bytes_of(module, basek, k_in, rank_in);
|
let tmp_in: usize = FourierGLWECiphertext::bytes_of(module, basek, k_in, rank_in);
|
||||||
let tmp_out: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank_out);
|
let tmp_out: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank_out);
|
||||||
let ksk: usize =
|
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
|
tmp_in + tmp_out + ksk
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,8 +125,8 @@ impl GLWESwitchingKey<Vec<u8>, FFT64> {
|
|||||||
digits: usize,
|
digits: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> 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 ksk: usize = GLWECiphertextFourier::keyswitch_inplace_scratch_space(module, basek, k_out, k_ksk, digits, rank);
|
let ksk: usize = FourierGLWECiphertext::keyswitch_inplace_scratch_space(module, basek, k_out, k_ksk, digits, rank);
|
||||||
tmp + ksk
|
tmp + ksk
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,9 +139,9 @@ impl GLWESwitchingKey<Vec<u8>, FFT64> {
|
|||||||
digits: usize,
|
digits: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let tmp_in: usize = GLWECiphertextFourier::bytes_of(module, basek, k_in, rank);
|
let tmp_in: usize = FourierGLWECiphertext::bytes_of(module, basek, k_in, rank);
|
||||||
let tmp_out: usize = GLWECiphertextFourier::bytes_of(module, basek, k_out, rank);
|
let tmp_out: usize = FourierGLWECiphertext::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 ggsw: usize = FourierGLWECiphertext::external_product_scratch_space(module, basek, k_out, k_in, k_ggsw, digits, rank);
|
||||||
tmp_in + tmp_out + ggsw
|
tmp_in + tmp_out + ggsw
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,9 +153,9 @@ impl GLWESwitchingKey<Vec<u8>, FFT64> {
|
|||||||
digits: usize,
|
digits: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> 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 =
|
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
|
tmp + ggsw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,36 @@
|
|||||||
pub mod automorphism;
|
pub mod automorphism;
|
||||||
pub mod blind_rotation;
|
pub mod blind_rotation;
|
||||||
pub mod elem;
|
pub mod elem;
|
||||||
pub mod gglwe_ciphertext;
|
pub mod fourier_glwe;
|
||||||
pub mod ggsw_ciphertext;
|
pub mod gglwe;
|
||||||
pub mod glwe_ciphertext;
|
pub mod ggsw;
|
||||||
pub mod glwe_ciphertext_fourier;
|
pub mod glwe;
|
||||||
pub mod glwe_ops;
|
|
||||||
pub mod glwe_packing;
|
|
||||||
pub mod glwe_plaintext;
|
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
pub mod keyswitch_key;
|
pub mod keyswitch_key;
|
||||||
|
pub mod lwe;
|
||||||
pub mod tensor_key;
|
pub mod tensor_key;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_fft64;
|
mod test_fft64;
|
||||||
pub mod trace;
|
mod utils;
|
||||||
|
|
||||||
pub use automorphism::*;
|
pub use automorphism::*;
|
||||||
use backend::Backend;
|
use backend::Backend;
|
||||||
use backend::FFT64;
|
use backend::FFT64;
|
||||||
use backend::Module;
|
use backend::Module;
|
||||||
pub use elem::*;
|
pub use elem::*;
|
||||||
pub use gglwe_ciphertext::*;
|
pub use fourier_glwe::*;
|
||||||
pub use ggsw_ciphertext::*;
|
pub use gglwe::*;
|
||||||
pub use glwe_ciphertext::*;
|
pub use ggsw::*;
|
||||||
pub use glwe_ciphertext_fourier::*;
|
pub use glwe::*;
|
||||||
pub use glwe_ops::*;
|
|
||||||
pub use glwe_packing::*;
|
|
||||||
pub use glwe_plaintext::*;
|
|
||||||
pub use keys::*;
|
|
||||||
pub use keyswitch_key::*;
|
pub use keyswitch_key::*;
|
||||||
|
pub use lwe::*;
|
||||||
pub use tensor_key::*;
|
pub use tensor_key::*;
|
||||||
|
|
||||||
pub use backend::Scratch;
|
pub use backend::Scratch;
|
||||||
pub use backend::ScratchOwned;
|
pub use backend::ScratchOwned;
|
||||||
|
|
||||||
|
use crate::keys::SecretDistribution;
|
||||||
|
|
||||||
pub(crate) const SIX_SIGMA: f64 = 6.0;
|
pub(crate) const SIX_SIGMA: f64 = 6.0;
|
||||||
|
|
||||||
pub trait ScratchCore<B: Backend> {
|
pub trait ScratchCore<B: Backend> {
|
||||||
@@ -64,7 +61,7 @@ pub trait ScratchCore<B: Backend> {
|
|||||||
basek: usize,
|
basek: usize,
|
||||||
k: usize,
|
k: usize,
|
||||||
rank: 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_sk(&mut self, module: &Module<B>, rank: usize) -> (GLWESecret<&mut [u8], B>, &mut Self);
|
||||||
fn tmp_glwe_pk(
|
fn tmp_glwe_pk(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -181,9 +178,9 @@ impl ScratchCore<FFT64> for Scratch {
|
|||||||
basek: usize,
|
basek: usize,
|
||||||
k: usize,
|
k: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> (GLWECiphertextFourier<&mut [u8], FFT64>, &mut Self) {
|
) -> (FourierGLWECiphertext<&mut [u8], FFT64>, &mut Self) {
|
||||||
let (data, scratch) = self.tmp_vec_znx_dft(module, rank + 1, k.div_ceil(basek));
|
let (data, scratch) = self.tmp_vec_znx_dft(module, rank + 1, div_ceil(k, basek));
|
||||||
(GLWECiphertextFourier { data, basek, k }, scratch)
|
(FourierGLWECiphertext { data, basek, k }, scratch)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tmp_glwe_pk(
|
fn tmp_glwe_pk(
|
||||||
|
|||||||
64
core/src/lwe.rs
Normal file
64
core/src/lwe.rs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,8 @@ use backend::{FFT64, Module, ScalarZnxOps, ScratchOwned, Stats, VecZnxOps};
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
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]
|
#[test]
|
||||||
@@ -69,7 +70,7 @@ fn test_automorphism(
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_apply, rank)
|
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),
|
| AutomorphismKey::automorphism_scratch_space(&module, basek, k_out, k_in, k_apply, digits, rank),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -101,7 +102,7 @@ fn test_automorphism(
|
|||||||
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
|
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
|
||||||
auto_key_out.automorphism(&module, &auto_key_in, &auto_key_apply, scratch.borrow());
|
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 pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out);
|
||||||
|
|
||||||
let mut sk_auto: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
|
let mut sk_auto: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
|
||||||
@@ -183,7 +184,7 @@ fn test_automorphism_inplace(
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_apply, rank)
|
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),
|
| AutomorphismKey::automorphism_inplace_scratch_space(&module, basek, k_in, k_apply, digits, rank),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -215,7 +216,7 @@ fn test_automorphism_inplace(
|
|||||||
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
|
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
|
||||||
auto_key.automorphism_inplace(&module, &auto_key_apply, scratch.borrow());
|
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 pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_in);
|
||||||
|
|
||||||
let mut sk_auto: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
|
let mut sk_auto: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use backend::{FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxToMut, ScratchO
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
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},
|
test_fft64::{log2_std_noise_gglwe_product, noise_ggsw_product},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ fn test_encrypt_sk(log_n: usize, basek: usize, k_ksk: usize, digits: usize, rank
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank_out)
|
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);
|
let mut sk_in: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank_in);
|
||||||
@@ -164,8 +164,8 @@ fn test_encrypt_sk(log_n: usize, basek: usize, k_ksk: usize, digits: usize, rank
|
|||||||
scratch.borrow(),
|
scratch.borrow(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut ct_glwe_fourier: GLWECiphertextFourier<Vec<u8>, FFT64> =
|
let mut ct_glwe_fourier: FourierGLWECiphertext<Vec<u8>, FFT64> =
|
||||||
GLWECiphertextFourier::alloc(&module, basek, k_ksk, rank_out);
|
FourierGLWECiphertext::alloc(&module, basek, k_ksk, rank_out);
|
||||||
|
|
||||||
(0..ksk.rank_in()).for_each(|col_i| {
|
(0..ksk.rank_in()).for_each(|col_i| {
|
||||||
(0..ksk.rows()).for_each(|row_i| {
|
(0..ksk.rows()).for_each(|row_i| {
|
||||||
@@ -234,7 +234,7 @@ fn test_key_switch(
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank_in_s0s1 | rank_out_s0s1)
|
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(
|
| GLWESwitchingKey::keyswitch_scratch_space(
|
||||||
&module,
|
&module,
|
||||||
basek,
|
basek,
|
||||||
@@ -281,8 +281,8 @@ fn test_key_switch(
|
|||||||
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
|
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
|
||||||
ct_gglwe_s0s2.keyswitch(&module, &ct_gglwe_s0s1, &ct_gglwe_s1s2, scratch.borrow());
|
ct_gglwe_s0s2.keyswitch(&module, &ct_gglwe_s0s1, &ct_gglwe_s1s2, scratch.borrow());
|
||||||
|
|
||||||
let mut ct_glwe_dft: GLWECiphertextFourier<Vec<u8>, FFT64> =
|
let mut ct_glwe_dft: FourierGLWECiphertext<Vec<u8>, FFT64> =
|
||||||
GLWECiphertextFourier::alloc(&module, basek, k_out, rank_out_s1s2);
|
FourierGLWECiphertext::alloc(&module, basek, k_out, rank_out_s1s2);
|
||||||
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out);
|
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out);
|
||||||
|
|
||||||
(0..ct_gglwe_s0s2.rank_in()).for_each(|col_i| {
|
(0..ct_gglwe_s0s2.rank_in()).for_each(|col_i| {
|
||||||
@@ -346,7 +346,7 @@ fn test_key_switch_inplace(
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank_out)
|
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),
|
| GLWESwitchingKey::keyswitch_inplace_scratch_space(&module, basek, k_ct, k_ksk, digits, rank_out),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -386,7 +386,7 @@ fn test_key_switch_inplace(
|
|||||||
|
|
||||||
let ct_gglwe_s0s2: GLWESwitchingKey<Vec<u8>, FFT64> = ct_gglwe_s0s1;
|
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);
|
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct);
|
||||||
|
|
||||||
(0..ct_gglwe_s0s2.rank_in()).for_each(|col_i| {
|
(0..ct_gglwe_s0s2.rank_in()).for_each(|col_i| {
|
||||||
@@ -455,7 +455,7 @@ fn test_external_product(
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_in, rank_out)
|
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)
|
| 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),
|
| GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_ggsw, rank_out),
|
||||||
);
|
);
|
||||||
@@ -494,7 +494,7 @@ fn test_external_product(
|
|||||||
// gglwe_(m) (x) RGSW_(X^k) = gglwe_(m * X^k)
|
// gglwe_(m) (x) RGSW_(X^k) = gglwe_(m * X^k)
|
||||||
ct_gglwe_out.external_product(&module, &ct_gglwe_in, &ct_rgsw, scratch.borrow());
|
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);
|
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out);
|
||||||
|
|
||||||
(0..rank_in).for_each(|i| {
|
(0..rank_in).for_each(|i| {
|
||||||
@@ -575,7 +575,7 @@ fn test_external_product_inplace(
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ct, rank_out)
|
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)
|
| 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),
|
| GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_ggsw, rank_out),
|
||||||
);
|
);
|
||||||
@@ -614,7 +614,7 @@ fn test_external_product_inplace(
|
|||||||
// gglwe_(m) (x) RGSW_(X^k) = gglwe_(m * X^k)
|
// gglwe_(m) (x) RGSW_(X^k) = gglwe_(m * X^k)
|
||||||
ct_gglwe.external_product_inplace(&module, &ct_rgsw, scratch.borrow());
|
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);
|
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct);
|
||||||
|
|
||||||
(0..rank_in).for_each(|i| {
|
(0..rank_in).for_each(|i| {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use backend::{
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
GGSWCiphertext, GLWECiphertextFourier, GLWEPlaintext, GLWESecret, GLWESwitchingKey, GetRow, Infos, TensorKey,
|
FourierGLWECiphertext, GGSWCiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, GetRow, Infos, TensorKey,
|
||||||
automorphism::AutomorphismKey,
|
automorphism::AutomorphismKey,
|
||||||
test_fft64::{noise_ggsw_keyswitch, noise_ggsw_product},
|
test_fft64::{noise_ggsw_keyswitch, noise_ggsw_product},
|
||||||
};
|
};
|
||||||
@@ -139,7 +139,7 @@ fn test_encrypt_sk(log_n: usize, basek: usize, k: usize, digits: usize, rank: us
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k, rank)
|
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);
|
let mut sk: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
|
||||||
@@ -155,7 +155,7 @@ fn test_encrypt_sk(log_n: usize, basek: usize, k: usize, digits: usize, rank: us
|
|||||||
scratch.borrow(),
|
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_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());
|
let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct.size());
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ fn test_keyswitch(
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_in, rank)
|
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)
|
| GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank)
|
||||||
| TensorKey::generate_from_sk_scratch_space(&module, basek, k_tsk, rank)
|
| TensorKey::generate_from_sk_scratch_space(&module, basek, k_tsk, rank)
|
||||||
| GGSWCiphertext::keyswitch_scratch_space(
|
| GGSWCiphertext::keyswitch_scratch_space(
|
||||||
@@ -269,7 +269,7 @@ fn test_keyswitch(
|
|||||||
|
|
||||||
ct_out.keyswitch(&module, &ct_in, &ksk, &tsk, scratch.borrow());
|
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_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());
|
let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_out.size());
|
||||||
|
|
||||||
@@ -348,7 +348,7 @@ fn test_keyswitch_inplace(
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_ct, rank)
|
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)
|
| GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank)
|
||||||
| TensorKey::generate_from_sk_scratch_space(&module, basek, k_tsk, 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),
|
| GGSWCiphertext::keyswitch_inplace_scratch_space(&module, basek, k_ct, k_ksk, digits, k_tsk, digits, rank),
|
||||||
@@ -394,7 +394,7 @@ fn test_keyswitch_inplace(
|
|||||||
|
|
||||||
ct.keyswitch_inplace(&module, &ksk, &tsk, scratch.borrow());
|
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_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());
|
let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct.size());
|
||||||
|
|
||||||
@@ -483,7 +483,7 @@ fn test_automorphism(
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_in, rank)
|
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)
|
| AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_ksk, rank)
|
||||||
| TensorKey::generate_from_sk_scratch_space(&module, basek, k_tsk, rank)
|
| TensorKey::generate_from_sk_scratch_space(&module, basek, k_tsk, rank)
|
||||||
| GGSWCiphertext::automorphism_scratch_space(
|
| GGSWCiphertext::automorphism_scratch_space(
|
||||||
@@ -530,7 +530,7 @@ fn test_automorphism(
|
|||||||
|
|
||||||
module.scalar_znx_automorphism_inplace(p, &mut pt_scalar, 0);
|
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_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());
|
let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_out.size());
|
||||||
|
|
||||||
@@ -608,7 +608,7 @@ fn test_automorphism_inplace(
|
|||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, k_ct, rank)
|
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)
|
| AutomorphismKey::generate_from_sk_scratch_space(&module, basek, k_ksk, rank)
|
||||||
| TensorKey::generate_from_sk_scratch_space(&module, basek, k_tsk, 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),
|
| GGSWCiphertext::automorphism_inplace_scratch_space(&module, basek, k_ct, k_ksk, digits, k_tsk, digits, rank),
|
||||||
@@ -653,7 +653,7 @@ fn test_automorphism_inplace(
|
|||||||
|
|
||||||
module.scalar_znx_automorphism_inplace(p, &mut pt_scalar, 0);
|
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_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());
|
let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct.size());
|
||||||
|
|
||||||
@@ -737,7 +737,7 @@ fn test_external_product(
|
|||||||
pt_ggsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k}
|
pt_ggsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k}
|
||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
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::encrypt_sk_scratch_space(&module, basek, k_ggsw, rank)
|
||||||
| GGSWCiphertext::external_product_scratch_space(&module, basek, k_out, k_in, k_ggsw, digits, rank),
|
| GGSWCiphertext::external_product_scratch_space(&module, basek, k_out, k_in, k_ggsw, digits, rank),
|
||||||
);
|
);
|
||||||
@@ -767,7 +767,7 @@ fn test_external_product(
|
|||||||
|
|
||||||
ct_ggsw_lhs_out.external_product(&module, &ct_ggsw_lhs_in, &ct_ggsw_rhs, scratch.borrow());
|
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: 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_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());
|
let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_ggsw_lhs_out.size());
|
||||||
@@ -857,7 +857,7 @@ fn test_external_product_inplace(log_n: usize, basek: usize, k_ct: usize, k_ggsw
|
|||||||
pt_ggsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k}
|
pt_ggsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k}
|
||||||
|
|
||||||
let mut scratch: ScratchOwned = ScratchOwned::new(
|
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::encrypt_sk_scratch_space(&module, basek, k_ggsw, rank)
|
||||||
| GGSWCiphertext::external_product_inplace_scratch_space(&module, basek, k_ct, k_ggsw, digits, rank),
|
| GGSWCiphertext::external_product_inplace_scratch_space(&module, basek, k_ct, k_ggsw, digits, rank),
|
||||||
);
|
);
|
||||||
@@ -887,7 +887,7 @@ fn test_external_product_inplace(log_n: usize, basek: usize, k_ct: usize, k_ggsw
|
|||||||
|
|
||||||
ct_ggsw_lhs.external_product_inplace(&module, &ct_ggsw_rhs, scratch.borrow());
|
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: 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_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());
|
let mut pt_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, ct_ggsw_lhs.size());
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use itertools::izip;
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
GGSWCiphertext, GLWECiphertext, GLWECiphertextFourier, GLWEPlaintext, GLWEPublicKey, GLWESecret, Infos,
|
FourierGLWECiphertext, GGSWCiphertext, GLWECiphertext, GLWEPlaintext, GLWEPublicKey, GLWESecret, Infos,
|
||||||
automorphism::AutomorphismKey,
|
automorphism::AutomorphismKey,
|
||||||
keyswitch_key::GLWESwitchingKey,
|
keyswitch_key::GLWESwitchingKey,
|
||||||
test_fft64::{log2_std_noise_gglwe_product, noise_ggsw_product},
|
test_fft64::{log2_std_noise_gglwe_product, noise_ggsw_product},
|
||||||
@@ -207,11 +207,11 @@ fn test_encrypt_zero_sk(log_n: usize, basek: usize, k_ct: usize, sigma: f64, ran
|
|||||||
let mut sk: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
|
let mut sk: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
|
||||||
sk.fill_ternary_prob(&module, 0.5, &mut source_xs);
|
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(
|
let mut scratch: ScratchOwned = ScratchOwned::new(
|
||||||
GLWECiphertextFourier::decrypt_scratch_space(&module, basek, k_ct)
|
FourierGLWECiphertext::decrypt_scratch_space(&module, basek, k_ct)
|
||||||
| GLWECiphertextFourier::encrypt_sk_scratch_space(&module, basek, k_ct, rank),
|
| FourierGLWECiphertext::encrypt_sk_scratch_space(&module, basek, k_ct, rank),
|
||||||
);
|
);
|
||||||
|
|
||||||
ct_dft.encrypt_zero_sk(
|
ct_dft.encrypt_zero_sk(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
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},
|
test_fft64::{log2_std_noise_gglwe_product, noise_ggsw_product},
|
||||||
};
|
};
|
||||||
use backend::{FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, ZnxViewMut};
|
use backend::{FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, ZnxViewMut};
|
||||||
@@ -90,10 +90,10 @@ fn test_keyswitch(
|
|||||||
let mut ksk: GLWESwitchingKey<Vec<u8>, FFT64> =
|
let mut ksk: GLWESwitchingKey<Vec<u8>, FFT64> =
|
||||||
GLWESwitchingKey::alloc(&module, basek, k_ksk, rows, digits, rank_in, rank_out);
|
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_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_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_out, rank_out);
|
||||||
let mut ct_glwe_dft_out: GLWECiphertextFourier<Vec<u8>, FFT64> =
|
let mut ct_glwe_dft_out: FourierGLWECiphertext<Vec<u8>, FFT64> =
|
||||||
GLWECiphertextFourier::alloc(&module, basek, k_out, rank_out);
|
FourierGLWECiphertext::alloc(&module, basek, k_out, rank_out);
|
||||||
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_in);
|
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);
|
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out);
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ fn test_keyswitch(
|
|||||||
GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank_out)
|
GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, k_ksk, rank_out)
|
||||||
| GLWECiphertext::decrypt_scratch_space(&module, basek, k_out)
|
| GLWECiphertext::decrypt_scratch_space(&module, basek, k_out)
|
||||||
| GLWECiphertext::encrypt_sk_scratch_space(&module, basek, k_in)
|
| GLWECiphertext::encrypt_sk_scratch_space(&module, basek, k_in)
|
||||||
| GLWECiphertextFourier::keyswitch_scratch_space(
|
| FourierGLWECiphertext::keyswitch_scratch_space(
|
||||||
&module,
|
&module,
|
||||||
basek,
|
basek,
|
||||||
ct_glwe_out.k(),
|
ct_glwe_out.k(),
|
||||||
@@ -185,7 +185,7 @@ fn test_keyswitch_inplace(log_n: usize, basek: usize, k_ct: usize, k_ksk: usize,
|
|||||||
|
|
||||||
let mut ksk: GLWESwitchingKey<Vec<u8>, FFT64> = GLWESwitchingKey::alloc(&module, basek, k_ksk, rows, digits, rank, rank);
|
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_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_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct);
|
||||||
let mut pt_have: 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 @@ fn test_keyswitch_inplace(log_n: usize, basek: usize, k_ct: usize, k_ksk: usize,
|
|||||||
GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, ksk.k(), rank)
|
GLWESwitchingKey::encrypt_sk_scratch_space(&module, basek, ksk.k(), rank)
|
||||||
| GLWECiphertext::decrypt_scratch_space(&module, basek, ct_glwe.k())
|
| GLWECiphertext::decrypt_scratch_space(&module, basek, ct_glwe.k())
|
||||||
| GLWECiphertext::encrypt_sk_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);
|
let mut sk_in: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
|
||||||
@@ -278,8 +278,8 @@ fn test_external_product(
|
|||||||
let mut ct_ggsw: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::alloc(&module, basek, k_ggsw, rows, digits, rank);
|
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_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_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_in_dft: FourierGLWECiphertext<Vec<u8>, FFT64> = FourierGLWECiphertext::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_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_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_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_in);
|
||||||
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out);
|
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_out);
|
||||||
@@ -304,7 +304,7 @@ fn test_external_product(
|
|||||||
GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, ct_ggsw.k(), rank)
|
GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, ct_ggsw.k(), rank)
|
||||||
| GLWECiphertext::decrypt_scratch_space(&module, basek, ct_out.k())
|
| GLWECiphertext::decrypt_scratch_space(&module, basek, ct_out.k())
|
||||||
| GLWECiphertext::encrypt_sk_scratch_space(&module, basek, ct_in.k())
|
| GLWECiphertext::encrypt_sk_scratch_space(&module, basek, ct_in.k())
|
||||||
| GLWECiphertextFourier::external_product_scratch_space(
|
| FourierGLWECiphertext::external_product_scratch_space(
|
||||||
&module,
|
&module,
|
||||||
basek,
|
basek,
|
||||||
ct_out.k(),
|
ct_out.k(),
|
||||||
@@ -384,7 +384,7 @@ fn test_external_product_inplace(log_n: usize, basek: usize, k_ct: usize, k_ggsw
|
|||||||
|
|
||||||
let mut ct_ggsw: GGSWCiphertext<Vec<u8>, FFT64> = GGSWCiphertext::alloc(&module, basek, k_ggsw, rows, digits, rank);
|
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: 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_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_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_ct);
|
||||||
let mut pt_have: 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 @@ fn test_external_product_inplace(log_n: usize, basek: usize, k_ct: usize, k_ggsw
|
|||||||
GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, ct_ggsw.k(), rank)
|
GGSWCiphertext::encrypt_sk_scratch_space(&module, basek, ct_ggsw.k(), rank)
|
||||||
| GLWECiphertext::decrypt_scratch_space(&module, basek, ct.k())
|
| GLWECiphertext::decrypt_scratch_space(&module, basek, ct.k())
|
||||||
| GLWECiphertext::encrypt_sk_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);
|
let mut sk: GLWESecret<Vec<u8>, FFT64> = GLWESecret::alloc(&module, rank);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use backend::{FFT64, Module, ScalarZnxDftOps, ScratchOwned, Stats, VecZnxOps};
|
use backend::{FFT64, Module, ScalarZnxDftOps, ScratchOwned, Stats, VecZnxOps};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{GLWECiphertextFourier, GLWEPlaintext, GLWESecret, GetRow, Infos, TensorKey};
|
use crate::{FourierGLWECiphertext, GLWEPlaintext, GLWESecret, GetRow, Infos, TensorKey};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encrypt_sk() {
|
fn encrypt_sk() {
|
||||||
@@ -42,7 +42,7 @@ fn test_encrypt_sk(log_n: usize, basek: usize, k: usize, sigma: f64, rank: usize
|
|||||||
scratch.borrow(),
|
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 pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k);
|
||||||
|
|
||||||
let mut sk_ij = GLWESecret::alloc(&module, 1);
|
let mut sk_ij = GLWESecret::alloc(&module, 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user