wip on BR + added enc/dec for LWE

This commit is contained in:
Jean-Philippe Bossuat
2025-06-13 20:45:24 +02:00
parent e8cfb5e2ab
commit 829b8be610
43 changed files with 745 additions and 688 deletions

View File

@@ -0,0 +1,139 @@
use std::time::Instant;
use backend::{MatZnxDftOps, MatZnxDftScratch, Module, ScalarZnxDftOps, Scratch, VecZnxDftOps, VecZnxOps, ZnxView, ZnxViewMut, ZnxZero, FFT64};
use itertools::izip;
use crate::{
GGSWCiphertext, GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, GLWEPlaintext, Infos, LWECiphertext,
ScratchCore, blind_rotation::key::BlindRotationKeyCGGI, lwe::ciphertext::LWECiphertextToRef,
};
pub fn cggi_blind_rotate_scratch_space(
module: &Module<FFT64>,
basek: usize,
k_lut: usize,
k_brk: usize,
rows: usize,
rank: usize,
) -> usize {
let size = k_brk.div_ceil(basek);
GGSWCiphertext::<Vec<u8>, FFT64>::bytes_of(module, basek, k_brk, rows, 1, rank)
+ (module.mat_znx_dft_mul_x_pow_minus_one_scratch_space(size, rank + 1)
| GLWECiphertext::external_product_inplace_scratch_space(module, basek, k_lut, k_brk, 1, rank))
}
pub fn cggi_blind_rotate<DataRes, DataIn, DataLUT>(
module: &Module<FFT64>,
res: &mut GLWECiphertext<DataRes>,
lwe: &LWECiphertext<DataIn>,
lut: &GLWEPlaintext<DataLUT>,
brk: &BlindRotationKeyCGGI<FFT64>,
scratch: &mut Scratch,
) where
DataRes: AsRef<[u8]> + AsMut<[u8]>,
DataIn: AsRef<[u8]>,
DataLUT: AsRef<[u8]>,
{
println!("{}", lwe.n());
let mut lwe_2n: Vec<i64> = vec![0i64; lwe.n() + 1]; // TODO: from scratch space
let mut out_mut: GLWECiphertext<&mut [u8]> = res.to_mut();
let lwe_ref: LWECiphertext<&[u8]> = lwe.to_ref();
let lut_ref: GLWECiphertext<&[u8]> = lut.to_ref();
let cols = out_mut.rank()+1;
mod_switch_2n(module, &mut lwe_2n, &lwe_ref);
let a: &[i64] = &lwe_2n[1..];
let b: i64 = lwe_2n[0];
out_mut.data.zero();
// Initialize out to X^{b} * LUT(X)
module.vec_znx_rotate(b, &mut out_mut.data, 0, &lut_ref.data, 0);
let block_size: usize = brk.block_size();
// ACC + [sum DFT(X^ai -1) * (DFT(ACC) x BRKi)]
let (mut acc_dft, scratch1) = scratch.tmp_glwe_fourier(module, brk.basek(), out_mut.k(), out_mut.rank());
let (mut acc_add_dft, scratch2) = scratch1.tmp_glwe_fourier(module, brk.basek(), out_mut.k(), out_mut.rank());
let (mut vmp_res, scratch3) = scratch2.tmp_vec_znx_dft(module, acc_dft.rank()+1, acc_dft.size());
let (mut xai_minus_one, scratch4) = scratch3.tmp_scalar_znx(module, 1);
let (mut xai_minus_one_dft, scratch5) = scratch4.tmp_scalar_znx_dft(module, 1);
let start: Instant = Instant::now();
izip!(
a.chunks_exact(block_size),
brk.data.chunks_exact(block_size)
)
.for_each(|(ai, ski)| {
out_mut.dft(module, &mut acc_dft);
acc_add_dft.data.zero();
izip!(ai.iter(), ski.iter())
.enumerate()
.for_each(|(i, (aii, skii))| {
// vmp_res = DFT(acc) * BRK[i]
module.vmp_apply(&mut vmp_res, &acc_dft.data, &skii.data, scratch5);
// DFT(X^ai -1)
xai_minus_one.zero();
xai_minus_one.at_mut(0, 0)[0] = 1;
module.vec_znx_rotate_inplace(*aii, &mut xai_minus_one, 0);
xai_minus_one.at_mut(0, 0)[0] -= 1;
module.svp_prepare(&mut xai_minus_one_dft, 0, &xai_minus_one, 0);
// DFT(X^ai -1) * (DFT(acc) * BRK[i])
(0..cols).for_each(|i|{
module.svp_apply_inplace(&mut vmp_res, i, &xai_minus_one_dft, 0);
module.vec_znx_dft_add_inplace(&mut acc_add_dft.data, i, &vmp_res, i);
});
});
acc_add_dft.idft(module, &mut out_mut, scratch5);
});
let duration: std::time::Duration = start.elapsed();
println!("external products: {} us", duration.as_micros());
}
fn mod_switch_2n(module: &Module<FFT64>, res: &mut [i64], lwe: &LWECiphertext<&[u8]>) {
let basek: usize = lwe.basek();
let log2n: usize = module.log_n() + 1;
res.copy_from_slice(&lwe.data.at(0, 0));
if basek > log2n {
let diff: usize = basek - log2n;
res.iter_mut().for_each(|x| {
*x = div_signed_by_pow2(x, diff);
})
} else {
let rem: usize = basek - (log2n % basek);
let size: usize = log2n.div_ceil(basek);
(1..size).for_each(|i| {
if i == size - 1 && rem != basek {
let k_rem: usize = basek - rem;
izip!(lwe.data.at(0, i).iter(), res.iter_mut()).for_each(|(x, y)| {
*y = (*y << k_rem) + (x >> rem);
});
} else {
izip!(lwe.data.at(0, i).iter(), res.iter_mut()).for_each(|(x, y)| {
*y = (*y << basek) + x;
});
}
})
}
}
#[inline(always)]
fn div_signed_by_pow2(x: &i64, k: usize) -> i64 {
let bias: i64 = (1 << k) - 1;
(x + ((x >> 63) & bias)) >> k
}

View File

@@ -1,22 +1,22 @@
use backend::{Backend, FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxToRef, Scratch, ZnxView, ZnxViewMut};
use sampling::source::Source;
use crate::{Distribution, FourierGLWESecret, GGSWCiphertext, GLWEAutomorphismKey, LWESecret};
use crate::{Distribution, FourierGLWESecret, GGSWCiphertext, Infos, LWESecret};
pub struct BlindRotationKeyCGGI<B: Backend> {
pub(crate) data: Vec<GGSWCiphertext<Vec<u8>, B>>,
pub(crate) dist: Distribution,
}
pub struct BlindRotationKeyFHEW<B: Backend> {
pub(crate) data: Vec<GGSWCiphertext<Vec<u8>, B>>,
pub(crate) auto: Vec<GLWEAutomorphismKey<Vec<u8>, B>>,
}
// pub struct BlindRotationKeyFHEW<B: Backend> {
// pub(crate) data: Vec<GGSWCiphertext<Vec<u8>, B>>,
// pub(crate) auto: Vec<GLWEAutomorphismKey<Vec<u8>, B>>,
//}
impl BlindRotationKeyCGGI<FFT64> {
pub fn allocate(module: &Module<FFT64>, lwe_degree: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self {
let mut data: Vec<GGSWCiphertext<Vec<u8>, FFT64>> = Vec::with_capacity(lwe_degree);
(0..lwe_degree).for_each(|_| data.push(GGSWCiphertext::alloc(module, basek, k, rows, 1, rank)));
pub fn allocate(module: &Module<FFT64>, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self {
let mut data: Vec<GGSWCiphertext<Vec<u8>, FFT64>> = Vec::with_capacity(n_lwe);
(0..n_lwe).for_each(|_| data.push(GGSWCiphertext::alloc(module, basek, k, rows, 1, rank)));
Self {
data,
dist: Distribution::NONE,
@@ -61,4 +61,27 @@ impl BlindRotationKeyCGGI<FFT64> {
ggsw.encrypt_sk(module, &pt, sk_glwe, source_xa, source_xe, sigma, scratch);
})
}
pub(crate) fn block_size(&self) -> usize {
match self.dist {
Distribution::BinaryBlock(value) => value,
_ => 1,
}
}
pub(crate) fn rows(&self) -> usize {
self.data[0].rows()
}
pub(crate) fn k(&self) -> usize {
self.data[0].k()
}
pub(crate) fn rank(&self) -> usize {
self.data[0].rank()
}
pub(crate) fn basek(&self) -> usize {
self.data[0].basek()
}
}

View File

@@ -1,2 +1,6 @@
// pub mod cggi;
pub mod ccgi;
pub mod key;
#[cfg(test)]
pub mod test_fft64;

View File

@@ -0,0 +1,85 @@
use core::time;
use std::time::Instant;
use backend::{Encoding, Module, ScratchOwned, FFT64};
use sampling::source::Source;
use crate::{
blind_rotation::{ccgi::{cggi_blind_rotate, cggi_blind_rotate_scratch_space}, key::BlindRotationKeyCGGI}, lwe::LWEPlaintext, FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWESecret, LWECiphertext, LWESecret
};
#[test]
fn blind_rotation() {
let module: Module<FFT64> = Module::<FFT64>::new(2048);
let basek: usize = 17;
let n_lwe: usize = 1071;
let k_lwe: usize = 22;
let k_brk: usize = 54;
let rows_brk: usize = 1;
let k_lut: usize = 44;
let rank: usize = 1;
let block_size: usize = 7;
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(&module, rank);
sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
let sk_glwe_dft: FourierGLWESecret<Vec<u8>, FFT64> = FourierGLWESecret::from(&module, &sk_glwe);
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
sk_lwe.fill_binary_block(block_size, &mut source_xs);
let mut scratch: ScratchOwned = ScratchOwned::new(BlindRotationKeyCGGI::generate_from_sk_scratch_space(
&module, basek, k_brk, rank,
) | cggi_blind_rotate_scratch_space(&module, basek, k_lut, k_brk, rows_brk, rank));
let start: Instant = Instant::now();
let mut brk: BlindRotationKeyCGGI<FFT64> = BlindRotationKeyCGGI::allocate(&module, n_lwe, basek, k_brk, rows_brk, rank);
brk.generate_from_sk(
&module,
&sk_glwe_dft,
&sk_lwe,
&mut source_xa,
&mut source_xe,
3.2,
scratch.borrow(),
);
let duration: std::time::Duration = start.elapsed();
println!("brk-gen: {} ms", duration.as_millis());
let mut lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe);
let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe);
pt_lwe.data.encode_coeff_i64(0, basek, 7, 0, 63, 7);
println!("{}", pt_lwe.data);
lwe.encrypt_sk(&pt_lwe, &sk_lwe, &mut source_xa, &mut source_xe, 3.2);
lwe.decrypt(&mut pt_lwe, &sk_lwe);
println!("{}", pt_lwe.data);
let lut: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_lut);
let mut res: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_lut, rank);
let start: Instant = Instant::now();
(0..32).for_each(|i|{
cggi_blind_rotate(&module, &mut res, &lwe, &lut, &brk, scratch.borrow());
});
let duration: std::time::Duration = start.elapsed();
println!("blind-rotate: {} ms", duration.as_millis());
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&module, basek, k_lut);
res.decrypt(&module , &mut pt, &sk_glwe_dft, scratch.borrow());
println!("{}", pt.data);
}

View File

@@ -0,0 +1 @@
pub mod cggi;

View File

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

View File

@@ -1,321 +0,0 @@
use backend::{
Backend, FFT64, MatZnxDftOps, MatZnxDftScratch, Module, ScalarZnxDftOps, Scratch, VecZnxAlloc, VecZnxBig, VecZnxBigAlloc,
VecZnxBigOps, VecZnxBigScratch, VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, ZnxZero,
};
use sampling::source::Source;
use crate::{GGSWCiphertext, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos, ScratchCore};
pub struct FourierGLWECiphertext<C, B: Backend> {
pub data: VecZnxDft<C, B>,
pub basek: usize,
pub k: usize,
}
impl<B: Backend> FourierGLWECiphertext<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self {
Self {
data: module.new_vec_znx_dft(rank + 1, k.div_ceil(basek)),
basek: basek,
k: k,
}
}
pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize {
module.bytes_of_vec_znx_dft(rank + 1, k.div_ceil(basek))
}
}
impl<T, B: Backend> Infos for FourierGLWECiphertext<T, B> {
type Inner = VecZnxDft<T, B>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<T, B: Backend> FourierGLWECiphertext<T, B> {
pub fn rank(&self) -> usize {
self.cols() - 1
}
}
impl FourierGLWECiphertext<Vec<u8>, FFT64> {
#[allow(dead_code)]
pub(crate) fn idft_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize {
module.bytes_of_vec_znx(1, k.div_ceil(basek))
+ (module.vec_znx_big_normalize_tmp_bytes() | module.vec_znx_idft_tmp_bytes())
}
pub fn encrypt_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
module.bytes_of_vec_znx(rank + 1, k.div_ceil(basek)) + GLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
}
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) + module.vec_znx_idft_tmp_bytes()))
+ 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 {
GLWECiphertext::bytes_of(module, basek, k_out, rank_out)
+ GLWECiphertext::keyswitch_from_fourier_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)
}
// WARNING TODO: UPDATE
pub fn external_product_scratch_space(
module: &Module<FFT64>,
basek: usize,
_k_out: usize,
k_in: usize,
k_ggsw: usize,
digits: usize,
rank: usize,
) -> usize {
let ggsw_size: usize = k_ggsw.div_ceil(basek);
let res_dft: usize = module.bytes_of_vec_znx_dft(rank + 1, ggsw_size);
let in_size: usize = k_in.div_ceil(basek).div_ceil(digits);
let ggsw_size: usize = k_ggsw.div_ceil(basek);
let vmp: usize = module.bytes_of_vec_znx_dft(rank + 1, in_size)
+ module.vmp_apply_tmp_bytes(ggsw_size, in_size, in_size, rank + 1, rank + 1, ggsw_size);
let res_small: usize = module.bytes_of_vec_znx(rank + 1, ggsw_size);
let normalize: usize = module.vec_znx_big_normalize_tmp_bytes();
res_dft + (vmp | (res_small + normalize))
}
pub fn external_product_inplace_scratch_space(
module: &Module<FFT64>,
basek: usize,
k_out: usize,
k_ggsw: usize,
digits: usize,
rank: usize,
) -> usize {
Self::external_product_scratch_space(module, basek, k_out, k_out, k_ggsw, digits, rank)
}
}
impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> FourierGLWECiphertext<DataSelf, FFT64> {
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,
) {
let (mut tmp_ct, scratch1) = scratch.tmp_glwe_ct(module, self.basek(), self.k(), self.rank());
tmp_ct.encrypt_zero_sk(module, sk, source_xa, source_xe, sigma, scratch1);
tmp_ct.dft(module, self);
}
pub fn keyswitch<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>(
&mut self,
module: &Module<FFT64>,
lhs: &FourierGLWECiphertext<DataLhs, FFT64>,
rhs: &GLWESwitchingKey<DataRhs, FFT64>,
scratch: &mut Scratch,
) {
let (mut tmp_ct, scratch1) = scratch.tmp_glwe_ct(module, self.basek(), self.k(), self.rank());
tmp_ct.keyswitch_from_fourier(module, lhs, rhs, scratch1);
tmp_ct.dft(module, self);
}
pub fn keyswitch_inplace<DataRhs: AsRef<[u8]>>(
&mut self,
module: &Module<FFT64>,
rhs: &GLWESwitchingKey<DataRhs, FFT64>,
scratch: &mut Scratch,
) {
unsafe {
let self_ptr: *mut FourierGLWECiphertext<DataSelf, FFT64> = self as *mut FourierGLWECiphertext<DataSelf, FFT64>;
self.keyswitch(&module, &*self_ptr, rhs, scratch);
}
}
pub fn external_product<DataLhs: AsRef<[u8]>, DataRhs: AsRef<[u8]>>(
&mut self,
module: &Module<FFT64>,
lhs: &FourierGLWECiphertext<DataLhs, FFT64>,
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()
>= FourierGLWECiphertext::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 = rhs.digits();
// Space for VMP result in DFT domain and high precision
let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, cols, rhs.size());
let (mut a_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, cols, (lhs.size() + digits - 1) / digits);
{
(0..digits).for_each(|di| {
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_copy(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);
}
});
}
// VMP result in high precision
let res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume::<&mut [u8]>(res_dft);
// Space for VMP result normalized
let (mut res_small, scratch2) = scratch1.tmp_vec_znx(module, cols, rhs.size());
(0..cols).for_each(|i| {
module.vec_znx_big_normalize(basek, &mut res_small, i, &res_big, i, scratch2);
module.vec_znx_dft(1, 0, &mut self.data, i, &res_small, i);
});
}
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 FourierGLWECiphertext<DataSelf, FFT64> = self as *mut FourierGLWECiphertext<DataSelf, FFT64>;
self.external_product(&module, &*self_ptr, rhs, scratch);
}
}
}
impl<DataSelf: AsRef<[u8]>> FourierGLWECiphertext<DataSelf, FFT64> {
pub fn decrypt<DataPt: AsRef<[u8]> + AsMut<[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 = self.rank() + 1;
let (mut pt_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, self.size()); // TODO optimize size when pt << ct
pt_big.zero();
{
(1..cols).for_each(|i| {
let (mut ci_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, self.size()); // TODO optimize size when pt << ct
module.svp_apply(&mut ci_dft, 0, &sk.data_fourier, i - 1, &self.data, i);
let ci_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(ci_dft);
module.vec_znx_big_add_inplace(&mut pt_big, 0, &ci_big, 0);
});
}
{
let (mut c0_big, scratch_2) = scratch_1.tmp_vec_znx_big(module, 1, self.size());
// c0_big = (a * s) + (-a * s + m + e) = BIG(m + e)
module.vec_znx_idft(&mut c0_big, 0, &self.data, 0, scratch_2);
module.vec_znx_big_add_inplace(&mut pt_big, 0, &c0_big, 0);
}
// pt = norm(BIG(m + e))
module.vec_znx_big_normalize(self.basek(), &mut pt.data, 0, &mut pt_big, 0, scratch_1);
pt.basek = self.basek();
pt.k = pt.k().min(self.k());
}
#[allow(dead_code)]
pub(crate) fn idft<DataRes: AsRef<[u8]> + AsMut<[u8]>>(
&self,
module: &Module<FFT64>,
res: &mut GLWECiphertext<DataRes>,
scratch: &mut Scratch,
) {
#[cfg(debug_assertions)]
{
assert_eq!(self.rank(), res.rank());
assert_eq!(self.basek(), res.basek())
}
let min_size: usize = self.size().min(res.size());
let (mut res_big, scratch1) = scratch.tmp_vec_znx_big(module, 1, min_size);
(0..self.rank() + 1).for_each(|i| {
module.vec_znx_idft(&mut res_big, 0, &self.data, i, scratch1);
module.vec_znx_big_normalize(self.basek(), &mut res.data, i, &res_big, 0, scratch1);
});
}
}

View File

@@ -1,6 +1,6 @@
use backend::{Backend, Module, VecZnxDft, VecZnxDftAlloc};
use crate::{Infos, div_ceil};
use crate::Infos;
pub struct FourierGLWECiphertext<C, B: Backend> {
pub data: VecZnxDft<C, B>,
@@ -11,14 +11,14 @@ pub struct FourierGLWECiphertext<C, B: Backend> {
impl<B: Backend> FourierGLWECiphertext<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self {
Self {
data: module.new_vec_znx_dft(rank + 1, div_ceil(k, basek)),
data: module.new_vec_znx_dft(rank + 1, k.div_ceil(basek)),
basek: basek,
k: k,
}
}
pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize {
module.bytes_of_vec_znx_dft(rank + 1, div_ceil(k, basek))
module.bytes_of_vec_znx_dft(rank + 1, k.div_ceil(basek))
}
}

View File

@@ -3,11 +3,11 @@ use backend::{
VecZnxDftOps, ZnxZero,
};
use crate::{FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, GLWEPlaintext, Infos, div_ceil};
use crate::{FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, GLWEPlaintext, Infos};
impl FourierGLWECiphertext<Vec<u8>, FFT64> {
pub fn decrypt_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize {
let size: usize = div_ceil(k, basek);
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) + module.vec_znx_idft_tmp_bytes()))

View File

@@ -1,17 +1,17 @@
use backend::{FFT64, Module, Scratch, VecZnxAlloc, VecZnxBigScratch, VecZnxDftOps};
use sampling::source::Source;
use crate::{FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, Infos, ScratchCore, div_ceil};
use crate::{FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, Infos, ScratchCore};
impl FourierGLWECiphertext<Vec<u8>, FFT64> {
#[allow(dead_code)]
pub(crate) fn idft_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize {
module.bytes_of_vec_znx(1, div_ceil(k, basek))
module.bytes_of_vec_znx(1, k.div_ceil(basek))
+ (module.vec_znx_big_normalize_tmp_bytes() | module.vec_znx_idft_tmp_bytes())
}
pub fn encrypt_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
module.bytes_of_vec_znx(rank + 1, div_ceil(k, basek)) + GLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
module.bytes_of_vec_znx(rank + 1, k.div_ceil(basek)) + GLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
}
}

View File

@@ -3,7 +3,7 @@ use backend::{
VecZnxDftAlloc, VecZnxDftOps,
};
use crate::{FourierGLWECiphertext, GGSWCiphertext, Infos, div_ceil};
use crate::{FourierGLWECiphertext, GGSWCiphertext, Infos};
impl FourierGLWECiphertext<Vec<u8>, FFT64> {
// WARNING TODO: UPDATE
@@ -16,10 +16,10 @@ impl FourierGLWECiphertext<Vec<u8>, FFT64> {
digits: usize,
rank: usize,
) -> usize {
let ggsw_size: usize = div_ceil(k_ggsw, basek);
let ggsw_size: usize = k_ggsw.div_ceil(basek);
let res_dft: usize = module.bytes_of_vec_znx_dft(rank + 1, ggsw_size);
let in_size: usize = div_ceil(div_ceil(k_in, basek), digits);
let ggsw_size: usize = div_ceil(k_ggsw, basek);
let in_size: usize = k_in.div_ceil(basek).div_ceil(digits);
let ggsw_size: usize = k_ggsw.div_ceil(basek);
let vmp: usize = module.bytes_of_vec_znx_dft(rank + 1, in_size)
+ module.vmp_apply_tmp_bytes(ggsw_size, in_size, in_size, rank + 1, rank + 1, ggsw_size);
let res_small: usize = module.bytes_of_vec_znx(rank + 1, ggsw_size);

View File

@@ -1,6 +1,6 @@
use crate::{
FourierGLWECiphertext, FourierGLWESecret, GGSWCiphertext, GLWECiphertext, GLWEOps, GLWEPlaintext, GLWESecret, Infos,
div_ceil, noise::noise_ggsw_product,
noise::noise_ggsw_product,
};
use backend::{FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, ZnxViewMut};
use sampling::source::Source;
@@ -10,7 +10,7 @@ fn apply() {
let log_n: usize = 8;
let basek: usize = 12;
let k_in: usize = 45;
let digits: usize = div_ceil(k_in, basek);
let digits: usize = k_in.div_ceil(basek);
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ggsw: usize = k_in + basek * di;
@@ -26,7 +26,7 @@ fn apply_inplace() {
let log_n: usize = 8;
let basek: usize = 12;
let k_ct: usize = 60;
let digits: usize = div_ceil(k_ct, basek);
let digits: usize = k_ct.div_ceil(basek);
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ggsw: usize = k_ct + basek * di;
@@ -39,7 +39,7 @@ fn apply_inplace() {
fn test_apply(log_n: usize, basek: usize, k_out: usize, k_in: usize, k_ggsw: usize, digits: usize, rank: usize, sigma: f64) {
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
let rows: usize = div_ceil(k_in, digits * basek);
let rows: usize = k_in.div_ceil(digits * basek);
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);
@@ -147,7 +147,7 @@ fn test_apply(log_n: usize, basek: usize, k_out: usize, k_in: usize, k_ggsw: usi
fn test_apply_inplace(log_n: usize, basek: usize, k_ct: usize, k_ggsw: usize, digits: usize, rank: usize, sigma: f64) {
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
let rows: usize = div_ceil(k_ct, digits * basek);
let rows: usize = k_ct.div_ceil(digits * basek);
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);

View File

@@ -1,5 +1,5 @@
use crate::{
FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos, div_ceil,
FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos,
noise::log2_std_noise_gglwe_product,
};
use backend::{FFT64, FillUniform, Module, ScratchOwned, Stats, VecZnxOps};
@@ -10,7 +10,7 @@ fn apply() {
let log_n: usize = 8;
let basek: usize = 12;
let k_in: usize = 45;
let digits: usize = div_ceil(k_in, basek);
let digits: usize = k_in.div_ceil(basek);
(1..4).for_each(|rank_in| {
(1..4).for_each(|rank_out| {
(1..digits + 1).for_each(|di| {
@@ -31,7 +31,7 @@ fn apply_inplace() {
let log_n: usize = 8;
let basek: usize = 12;
let k_ct: usize = 45;
let digits: usize = div_ceil(k_ct, basek);
let digits: usize = k_ct.div_ceil(basek);
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_ct + basek * di;
@@ -54,7 +54,7 @@ fn test_apply(
) {
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
let rows: usize = div_ceil(k_in, basek * digits);
let rows: usize = k_in.div_ceil(basek * digits);
let mut ksk: GLWESwitchingKey<Vec<u8>, FFT64> =
GLWESwitchingKey::alloc(&module, basek, k_ksk, rows, digits, rank_in, rank_out);
@@ -152,7 +152,7 @@ fn test_apply(
fn test_apply_inplace(log_n: usize, basek: usize, k_ct: usize, k_ksk: usize, digits: usize, rank: usize, sigma: f64) {
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
let rows: usize = div_ceil(k_ct, basek * digits);
let rows: usize = k_ct.div_ceil(basek * digits);
let mut ksk: GLWESwitchingKey<Vec<u8>, FFT64> = GLWESwitchingKey::alloc(&module, basek, k_ksk, rows, digits, rank, rank);
let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_ct, rank);

View File

@@ -1,236 +0,0 @@
use backend::{
Backend, FFT64, MatZnxDft, MatZnxDftAlloc, MatZnxDftOps, Module, ScalarZnx, Scratch, VecZnxAlloc, VecZnxDftAlloc, VecZnxOps,
ZnxInfos, ZnxZero,
};
use sampling::source::Source;
use crate::{FourierGLWECiphertext, GLWECiphertext, GLWESecret, GetRow, Infos, ScratchCore, SetRow, div_ceil};
pub struct GGLWECiphertext<C, B: Backend> {
pub(crate) data: MatZnxDft<C, B>,
pub(crate) basek: usize,
pub(crate) k: usize,
pub(crate) digits: usize,
}
impl<B: Backend> GGLWECiphertext<Vec<u8>, B> {
pub fn alloc(
module: &Module<B>,
basek: usize,
k: usize,
rows: usize,
digits: usize,
rank_in: usize,
rank_out: usize,
) -> Self {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
size,
digits
);
debug_assert!(
rows * digits <= size,
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
Self {
data: module.new_mat_znx_dft(rows, rank_in, rank_out + 1, size),
basek: basek,
k,
digits,
}
}
pub fn bytes_of(
module: &Module<FFT64>,
basek: usize,
k: usize,
rows: usize,
digits: usize,
rank_in: usize,
rank_out: usize,
) -> usize {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
size,
digits
);
assert!(
rows * digits <= size,
"invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
rows,
digits,
size
);
module.bytes_of_mat_znx_dft(rows, rank_in, rank_out + 1, size)
}
}
impl<T, B: Backend> Infos for GGLWECiphertext<T, B> {
type Inner = MatZnxDft<T, B>;
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<T, B: Backend> GGLWECiphertext<T, B> {
pub fn rank(&self) -> usize {
self.data.cols_out() - 1
}
pub fn digits(&self) -> usize {
self.digits
}
pub fn rank_in(&self) -> usize {
self.data.cols_in()
}
pub fn rank_out(&self) -> usize {
self.data.cols_out() - 1
}
}
impl GGLWECiphertext<Vec<u8>, FFT64> {
pub fn generate_from_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
let size = k.div_ceil(basek);
GLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
+ module.bytes_of_vec_znx(rank + 1, size)
+ module.bytes_of_vec_znx(1, size)
+ module.bytes_of_vec_znx_dft(rank + 1, size)
}
pub fn generate_from_pk_scratch_space(_module: &Module<FFT64>, _basek: usize, _k: usize, _rank: usize) -> usize {
unimplemented!()
}
}
impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GGLWECiphertext<DataSelf, FFT64> {
pub fn encrypt_sk<DataPt: AsRef<[u8]>, DataSk: AsRef<[u8]>>(
&mut self,
module: &Module<FFT64>,
pt: &ScalarZnx<DataPt>,
sk: &GLWESecret<DataSk, FFT64>,
source_xa: &mut Source,
source_xe: &mut Source,
sigma: f64,
scratch: &mut Scratch,
) {
#[cfg(debug_assertions)]
{
assert_eq!(self.rank_in(), pt.cols());
assert_eq!(self.rank_out(), sk.rank());
assert_eq!(self.n(), module.n());
assert_eq!(sk.n(), module.n());
assert_eq!(pt.n(), module.n());
assert!(
scratch.available()
>= GGLWECiphertext::generate_from_sk_scratch_space(module, self.basek(), self.k(), self.rank()),
"scratch.available: {} < GGLWECiphertext::generate_from_sk_scratch_space(module, self.rank()={}, \
self.size()={}): {}",
scratch.available(),
self.rank(),
self.size(),
GGLWECiphertext::generate_from_sk_scratch_space(module, self.basek(), self.k(), self.rank())
);
assert!(
self.rows() * self.digits() * self.basek() <= self.k(),
"self.rows() : {} * self.digits() : {} * self.basek() : {} = {} >= self.k() = {}",
self.rows(),
self.digits(),
self.basek(),
self.rows() * self.digits() * self.basek(),
self.k()
);
}
let rows: usize = self.rows();
let digits: usize = self.digits();
let basek: usize = self.basek();
let k: usize = self.k();
let rank_in: usize = self.rank_in();
let rank_out: usize = self.rank_out();
let (mut tmp_pt, scrach_1) = scratch.tmp_glwe_pt(module, basek, k);
let (mut tmp_ct, scrach_2) = scrach_1.tmp_glwe_ct(module, basek, k, rank_out);
let (mut tmp_ct_dft, scratch_3) = scrach_2.tmp_glwe_fourier(module, basek, k, rank_out);
// For each input column (i.e. rank) produces a GGLWE ciphertext of rank_out+1 columns
//
// Example for ksk rank 2 to rank 3:
//
// (-(a0*s0 + a1*s1 + a2*s2) + s0', a0, a1, a2)
// (-(b0*s0 + b1*s1 + b2*s2) + s0', b0, b1, b2)
//
// Example ksk rank 2 to rank 1
//
// (-(a*s) + s0, a)
// (-(b*s) + s1, b)
(0..rank_in).for_each(|col_i| {
(0..rows).for_each(|row_i| {
// Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
tmp_pt.data.zero(); // zeroes for next iteration
module.vec_znx_add_scalar_inplace(
&mut tmp_pt.data,
0,
(digits - 1) + row_i * digits,
pt,
col_i,
);
module.vec_znx_normalize_inplace(basek, &mut tmp_pt.data, 0, scratch_3);
// rlwe encrypt of vec_znx_pt into vec_znx_ct
tmp_ct.encrypt_sk(module, &tmp_pt, sk, source_xa, source_xe, sigma, scratch_3);
// Switch vec_znx_ct into DFT domain
tmp_ct.dft(module, &mut tmp_ct_dft);
// Stores vec_znx_dft_ct into thw i-th row of the MatZnxDft
self.set_row(module, row_i, col_i, &tmp_ct_dft);
});
});
}
}
impl<C: AsRef<[u8]>> GetRow<FFT64> for GGLWECiphertext<C, FFT64> {
fn get_row<R: AsMut<[u8]> + AsRef<[u8]>>(
&self,
module: &Module<FFT64>,
row_i: usize,
col_j: usize,
res: &mut FourierGLWECiphertext<R, FFT64>,
) {
module.mat_znx_dft_get_row(&mut res.data, &self.data, row_i, col_j);
}
}
impl<C: AsMut<[u8]> + AsRef<[u8]>> SetRow<FFT64> for GGLWECiphertext<C, FFT64> {
fn set_row<R: AsRef<[u8]>>(
&mut self,
module: &Module<FFT64>,
row_i: usize,
col_j: usize,
a: &FourierGLWECiphertext<R, FFT64>,
) {
module.mat_znx_dft_set_row(&mut self.data, row_i, col_j, &a.data);
}
}

View File

@@ -62,24 +62,33 @@ impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWEAutomorphismKey<DataSelf, FFT64> {
self.rank_out(),
rhs.rank_out()
);
assert!(
self.k() <= lhs.k(),
"output k={} cannot be greater than input k={}",
self.k(),
lhs.k()
)
}
let cols_out: usize = rhs.rank_out() + 1;
let (mut tmp_dft, scratch1) = scratch.tmp_glwe_fourier(module, lhs.basek(), lhs.k(), lhs.rank());
(0..self.rank_in()).for_each(|col_i| {
(0..self.rows()).for_each(|row_j| {
// Extracts relevant row
lhs.get_row(module, row_j, col_i, &mut tmp_dft);
let (mut tmp_idft_data, scratct1) = scratch.tmp_vec_znx_big(module, cols_out, self.size());
// Get a VecZnxBig from scratch space
let (mut tmp_idft_data, scratch2) = scratch1.tmp_vec_znx_big(module, cols_out, self.size());
{
let (mut tmp_dft, scratch2) = scratct1.tmp_glwe_fourier(module, lhs.basek(), lhs.k(), lhs.rank());
// Switches input outside of DFT
(0..cols_out).for_each(|i| {
module.vec_znx_idft(&mut tmp_idft_data, i, &tmp_dft.data, i, scratch2);
});
// Extracts relevant row
lhs.get_row(module, row_j, col_i, &mut tmp_dft);
// Get a VecZnxBig from scratch space
// Switches input outside of DFT
(0..cols_out).for_each(|i| {
module.vec_znx_idft(&mut tmp_idft_data, i, &tmp_dft.data, i, scratch2);
});
}
// Consumes to small vec znx
let mut tmp_idft_small_data: VecZnx<&mut [u8]> = tmp_idft_data.to_vec_znx_small();
@@ -97,20 +106,25 @@ impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWEAutomorphismKey<DataSelf, FFT64> {
};
// Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a)
tmp_idft.keyswitch_inplace(module, &rhs.key, scratch2);
tmp_idft.keyswitch_inplace(module, &rhs.key, scratct1);
// Applies back the automorphism X^{k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) -> (-pi^{-1}_{k'+k}(s)a + s, a)
// and switches back to DFT domain
(0..self.rank_out() + 1).for_each(|i| {
module.vec_znx_automorphism_inplace(lhs.p(), &mut tmp_idft.data, i);
module.vec_znx_dft(1, 0, &mut tmp_dft.data, i, &tmp_idft.data, i);
});
{
let (mut tmp_dft, _) = scratct1.tmp_glwe_fourier(module, self.basek(), self.k(), self.rank());
// Sets back the relevant row
self.set_row(module, row_j, col_i, &tmp_dft);
// Applies back the automorphism X^{k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) -> (-pi^{-1}_{k'+k}(s)a + s, a)
// and switches back to DFT domain
(0..self.rank_out() + 1).for_each(|i| {
module.vec_znx_automorphism_inplace(lhs.p(), &mut tmp_idft.data, i);
module.vec_znx_dft(1, 0, &mut tmp_dft.data, i, &tmp_idft.data, i);
});
// Sets back the relevant row
self.set_row(module, row_j, col_i, &tmp_dft);
}
});
});
let (mut tmp_dft, _) = scratch.tmp_glwe_fourier(module, self.basek(), self.k(), self.rank());
tmp_dft.data.zero();
(self.rows().min(lhs.rows())..self.rows()).for_each(|row_i| {

View File

@@ -1,6 +1,6 @@
use backend::{Backend, FFT64, MatZnxDft, MatZnxDftAlloc, MatZnxDftOps, Module};
use crate::{FourierGLWECiphertext, GetRow, Infos, SetRow, div_ceil};
use crate::{FourierGLWECiphertext, GetRow, Infos, SetRow};
pub struct GGLWECiphertext<C, B: Backend> {
pub(crate) data: MatZnxDft<C, B>,
@@ -19,7 +19,7 @@ impl<B: Backend> GGLWECiphertext<Vec<u8>, B> {
rank_in: usize,
rank_out: usize,
) -> Self {
let size: usize = div_ceil(k, basek);
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
@@ -52,7 +52,7 @@ impl<B: Backend> GGLWECiphertext<Vec<u8>, B> {
rank_in: usize,
rank_out: usize,
) -> usize {
let size: usize = div_ceil(k, basek);
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,
"invalid gglwe: ceil(k/basek): {} <= digits: {}",

View File

@@ -5,12 +5,12 @@ use sampling::source::Source;
use crate::{
FourierGLWESecret, GGLWECiphertext, GLWEAutomorphismKey, GLWECiphertext, GLWESecret, GLWESwitchingKey, GLWETensorKey, Infos,
ScratchCore, SetRow, div_ceil,
ScratchCore, SetRow,
};
impl GGLWECiphertext<Vec<u8>, FFT64> {
pub fn generate_from_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
let size = div_ceil(k, basek);
let size = k.div_ceil(basek);
GLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
+ module.bytes_of_vec_znx(rank + 1, size)
+ module.bytes_of_vec_znx(1, size)

View File

@@ -2,7 +2,7 @@ use backend::{FFT64, Module, ScalarZnxOps, ScratchOwned, Stats, VecZnxOps};
use sampling::source::Source;
use crate::{
FourierGLWECiphertext, FourierGLWESecret, GLWEAutomorphismKey, GLWEPlaintext, GLWESecret, GetRow, Infos, div_ceil,
FourierGLWECiphertext, FourierGLWESecret, GLWEAutomorphismKey, GLWEPlaintext, GLWESecret, GetRow, Infos,
noise::log2_std_noise_gglwe_product,
};

View File

@@ -3,7 +3,6 @@ use sampling::source::Source;
use crate::{
FourierGLWECiphertext, FourierGLWESecret, GGSWCiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, GetRow, Infos,
div_ceil,
noise::{log2_std_noise_gglwe_product, noise_ggsw_product},
};

View File

@@ -7,7 +7,7 @@ use sampling::source::Source;
use crate::{
FourierGLWECiphertext, FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWESwitchingKey, GLWETensorKey, GetRow,
Infos, ScratchCore, SetRow, div_ceil,
Infos, ScratchCore, SetRow,
};
pub struct GGSWCiphertext<C, B: Backend> {
@@ -17,8 +17,8 @@ pub struct GGSWCiphertext<C, B: Backend> {
pub(crate) digits: usize,
}
impl<B: Backend> GGSWCiphertext<Vec<u8>, B> {
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
impl GGSWCiphertext<Vec<u8>, FFT64> {
pub fn alloc(module: &Module<FFT64>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
let size: usize = k.div_ceil(basek);
debug_assert!(
size > digits,

View File

@@ -6,7 +6,7 @@ use sampling::source::Source;
use crate::{
FourierGLWECiphertext, FourierGLWESecret, GGSWCiphertext, GLWEAutomorphismKey, GLWEPlaintext, GLWESecret, GLWESwitchingKey,
GLWETensorKey, GetRow, Infos, div_ceil,
GLWETensorKey, GetRow, Infos,
noise::{noise_ggsw_keyswitch, noise_ggsw_product},
};

View File

@@ -1,9 +1,6 @@
use backend::{
Backend, FFT64, Module, VecZnx, VecZnxAlloc, VecZnxBigAlloc, VecZnxBigScratch, VecZnxDftAlloc, VecZnxDftOps, VecZnxToMut,
VecZnxToRef,
};
use backend::{Backend, FFT64, Module, VecZnx, VecZnxAlloc, VecZnxDftOps, VecZnxToMut, VecZnxToRef};
use crate::{FourierGLWECiphertext, GLWEOps, Infos, SetMetaData, div_ceil};
use crate::{FourierGLWECiphertext, GLWEOps, Infos, SetMetaData};
pub struct GLWECiphertext<C> {
pub data: VecZnx<C>,
@@ -14,14 +11,14 @@ pub struct GLWECiphertext<C> {
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)),
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, div_ceil(k, basek))
module.bytes_of_vec_znx(rank + 1, k.div_ceil(basek))
}
}
@@ -62,10 +59,13 @@ impl<C: AsRef<[u8]>> GLWECiphertext<C> {
}
}
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: AsRef<[u8]>> GLWECiphertext<DataSelf> {
pub fn clone(&self) -> GLWECiphertext<Vec<u8>> {
GLWECiphertext {
data: self.data.clone(),
basek: self.basek(),
k: self.k(),
}
}
}

View File

@@ -1,16 +1,18 @@
use backend::{FFT64, Module, ScalarZnxDftOps, Scratch, VecZnxBigOps, VecZnxDftOps, ZnxZero};
use backend::{
FFT64, Module, ScalarZnxDftOps, Scratch, VecZnxBigAlloc, VecZnxBigOps, VecZnxBigScratch, VecZnxDftAlloc, VecZnxDftOps,
ZnxZero,
};
use crate::{FourierGLWESecret, GLWECiphertext, GLWEPlaintext, 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(),
}
impl GLWECiphertext<Vec<u8>> {
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)
}
}
impl<DataSelf: AsRef<[u8]>> GLWECiphertext<DataSelf> {
pub fn decrypt<DataPt: AsMut<[u8]> + AsRef<[u8]>, DataSk: AsRef<[u8]>>(
&self,
module: &Module<FFT64>,

View File

@@ -4,15 +4,15 @@ use backend::{
};
use sampling::source::Source;
use crate::{FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWEPublicKey, Infos, SIX_SIGMA, dist::Distribution, div_ceil};
use crate::{FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWEPublicKey, Infos, SIX_SIGMA, dist::Distribution};
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);
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 = div_ceil(k, basek);
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()
@@ -71,7 +71,7 @@ impl<DataSelf: AsRef<[u8]> + AsMut<[u8]>> GLWECiphertext<DataSelf> {
sigma: f64,
scratch: &mut Scratch,
) {
self.encrypt_pk_private(
self.encrypt_pk_private::<DataPt, DataPk>(
module,
Some((pt, 0)),
pk,
@@ -91,7 +91,7 @@ impl<DataSelf: AsRef<[u8]> + AsMut<[u8]>> GLWECiphertext<DataSelf> {
sigma: f64,
scratch: &mut Scratch,
) {
self.encrypt_pk_private(
self.encrypt_pk_private::<Vec<u8>, DataPk>(
module,
None::<(&GLWEPlaintext<Vec<u8>>, usize)>,
pk,

View File

@@ -2,7 +2,7 @@ use backend::{
FFT64, MatZnxDftOps, MatZnxDftScratch, Module, Scratch, VecZnxBig, VecZnxBigOps, VecZnxDftAlloc, VecZnxDftOps, VecZnxScratch,
};
use crate::{FourierGLWECiphertext, GGSWCiphertext, GLWECiphertext, Infos, div_ceil};
use crate::{FourierGLWECiphertext, GGSWCiphertext, GLWECiphertext, Infos};
impl GLWECiphertext<Vec<u8>> {
pub fn external_product_scratch_space(
@@ -10,14 +10,14 @@ impl GLWECiphertext<Vec<u8>> {
basek: usize,
k_out: usize,
k_in: usize,
ggsw_k: usize,
k_ggsw: 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 in_size: usize = k_in.div_ceil(basek).div_ceil(digits);
let out_size: usize = k_out.div_ceil(basek);
let ggsw_size: usize = k_ggsw.div_ceil(basek);
let vmp: usize = module.bytes_of_vec_znx_dft(rank + 1, in_size)
+ module.vmp_apply_tmp_bytes(
out_size,
@@ -35,11 +35,11 @@ impl GLWECiphertext<Vec<u8>> {
module: &Module<FFT64>,
basek: usize,
k_out: usize,
ggsw_k: usize,
k_ggsw: usize,
digits: usize,
rank: usize,
) -> usize {
Self::external_product_scratch_space(module, basek, k_out, k_out, ggsw_k, digits, rank)
Self::external_product_scratch_space(module, basek, k_out, k_out, k_ggsw, digits, rank)
}
}

View File

@@ -3,7 +3,7 @@ use backend::{
VecZnxDftOps, ZnxZero,
};
use crate::{FourierGLWECiphertext, GLWECiphertext, GLWESwitchingKey, Infos, div_ceil};
use crate::{FourierGLWECiphertext, GLWECiphertext, GLWESwitchingKey, Infos};
impl GLWECiphertext<Vec<u8>> {
pub fn keyswitch_scratch_space(
@@ -17,9 +17,9 @@ impl GLWECiphertext<Vec<u8>> {
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 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);

View File

@@ -1,6 +1,6 @@
use backend::{Backend, FFT64, Module, VecZnx, VecZnxAlloc, VecZnxToMut, VecZnxToRef};
use crate::{GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, GLWEOps, Infos, SetMetaData, div_ceil};
use crate::{GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, GLWEOps, Infos, SetMetaData};
pub struct GLWEPlaintext<C> {
pub data: VecZnx<C>,

View File

@@ -3,7 +3,7 @@ use backend::{FFT64, FillUniform, Module, ScratchOwned, Stats, VecZnxOps};
use sampling::source::Source;
use crate::{
FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos, div_ceil,
FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos,
noise::log2_std_noise_gglwe_product,
};
@@ -12,7 +12,7 @@ fn apply_inplace() {
let log_n: usize = 8;
let basek: usize = 12;
let k_ct: usize = 60;
let digits: usize = div_ceil(k_ct, basek);
let digits: usize = k_ct.div_ceil(basek);
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_ct + basek * di;
@@ -27,7 +27,7 @@ fn apply() {
let log_n: usize = 8;
let basek: usize = 12;
let k_in: usize = 60;
let digits: usize = div_ceil(k_in, basek);
let digits: usize = k_in.div_ceil(basek);
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_in + basek * di;
@@ -51,7 +51,7 @@ fn test_automorphism(
) {
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
let rows: usize = div_ceil(k_in, basek * digits);
let rows: usize = k_in.div_ceil(basek * digits);
let mut autokey: GLWEAutomorphismKey<Vec<u8>, FFT64> = GLWEAutomorphismKey::alloc(&module, basek, k_ksk, rows, digits, rank);
let mut ct_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_in, rank);
@@ -149,7 +149,7 @@ fn test_automorphism_inplace(
) {
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
let rows: usize = div_ceil(k_ct, basek * digits);
let rows: usize = k_ct.div_ceil(basek * digits);
let mut autokey: GLWEAutomorphismKey<Vec<u8>, FFT64> = GLWEAutomorphismKey::alloc(&module, basek, k_ksk, rows, digits, rank);
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_ct, rank);

View File

@@ -2,7 +2,7 @@ use backend::{FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwne
use sampling::source::Source;
use crate::{
FourierGLWESecret, GGSWCiphertext, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos, div_ceil, noise::noise_ggsw_product,
FourierGLWESecret, GGSWCiphertext, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos, noise::noise_ggsw_product,
};
#[test]
@@ -10,7 +10,7 @@ fn apply() {
let log_n: usize = 8;
let basek: usize = 12;
let k_in: usize = 45;
let digits: usize = div_ceil(k_in, basek);
let digits: usize = k_in.div_ceil(basek);
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ggsw: usize = k_in + basek * di;

View File

@@ -2,7 +2,7 @@ use backend::{FFT64, FillUniform, Module, ScratchOwned, Stats, VecZnxOps};
use sampling::source::Source;
use crate::{
FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos, div_ceil,
FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos,
noise::log2_std_noise_gglwe_product,
};
@@ -11,7 +11,7 @@ fn apply() {
let log_n: usize = 8;
let basek: usize = 12;
let k_in: usize = 45;
let digits: usize = div_ceil(k_in, basek);
let digits: usize = k_in.div_ceil(basek);
(1..4).for_each(|rank_in| {
(1..4).for_each(|rank_out| {
(1..digits + 1).for_each(|di| {
@@ -32,7 +32,7 @@ fn apply_inplace() {
let log_n: usize = 8;
let basek: usize = 12;
let k_ct: usize = 45;
let digits: usize = div_ceil(k_ct, basek);
let digits: usize = k_ct.div_ceil(basek);
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_ct + basek * di;
@@ -55,7 +55,7 @@ fn test_keyswitch(
) {
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
let rows: usize = div_ceil(k_in, basek * digits);
let rows: usize = k_in.div_ceil(basek * digits);
let mut ksk: GLWESwitchingKey<Vec<u8>, FFT64> =
GLWESwitchingKey::alloc(&module, basek, k_ksk, rows, digits, rank_in, rank_out);
@@ -148,7 +148,7 @@ fn test_keyswitch(
fn test_keyswitch_inplace(log_n: usize, basek: usize, k_ct: usize, k_ksk: usize, digits: usize, rank: usize, sigma: f64) {
let module: Module<FFT64> = Module::<FFT64>::new(1 << log_n);
let rows: usize = div_ceil(k_ct, basek * digits);
let rows: usize = k_ct.div_ceil(basek * digits);
let mut ct_grlwe: 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);

View File

@@ -1,4 +1,4 @@
use crate::{FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWEOps, GLWEPacker, GLWEPlaintext, GLWESecret, div_ceil};
use crate::{FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWEOps, GLWEPacker, GLWEPlaintext, GLWESecret};
use std::collections::HashMap;
use backend::{Encoding, FFT64, Module, ScratchOwned, Stats};

View File

@@ -4,7 +4,7 @@ use backend::{FFT64, FillUniform, Module, ScratchOwned, Stats, VecZnxOps, ZnxVie
use sampling::source::Source;
use crate::{
FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos, div_ceil,
FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos,
noise::var_noise_gglwe_product,
};

View File

@@ -7,18 +7,17 @@ pub mod ggsw;
pub mod glwe;
pub mod lwe;
pub mod noise;
mod utils;
use backend::Backend;
use backend::FFT64;
use backend::Module;
pub use elem::*;
pub use elem::{GetRow, Infos, SetMetaData, SetRow};
pub use fourier_glwe::{FourierGLWECiphertext, FourierGLWESecret};
pub use gglwe::{GGLWECiphertext, GLWEAutomorphismKey, GLWESwitchingKey, GLWETensorKey};
pub use ggsw::*;
pub use ggsw::GGSWCiphertext;
pub use glwe::{GLWECiphertext, GLWEOps, GLWEPacker, GLWEPlaintext, GLWEPublicKey, GLWESecret};
pub(crate) use glwe::{GLWECiphertextToMut, GLWECiphertextToRef};
pub use lwe::*;
pub use lwe::{LWECiphertext, LWESecret};
pub use backend::Scratch;
pub use backend::ScratchOwned;
@@ -174,7 +173,7 @@ impl ScratchCore<FFT64> for Scratch {
k: usize,
rank: usize,
) -> (FourierGLWECiphertext<&mut [u8], FFT64>, &mut Self) {
let (data, scratch) = self.tmp_vec_znx_dft(module, rank + 1, div_ceil(k, basek));
let (data, scratch) = self.tmp_vec_znx_dft(module, rank + 1, k.div_ceil(basek));
(FourierGLWECiphertext { data, basek, k }, scratch)
}

View File

@@ -0,0 +1,77 @@
use backend::{VecZnx, VecZnxToMut, VecZnxToRef};
use crate::{Infos, SetMetaData};
pub struct LWECiphertext<D> {
pub(crate) data: VecZnx<D>,
pub(crate) k: usize,
pub(crate) basek: usize,
}
impl LWECiphertext<Vec<u8>> {
pub fn alloc(n: usize, basek: usize, k: usize) -> Self {
Self {
data: VecZnx::new::<i64>(n, 1, k.div_ceil(basek)),
k: k,
basek: basek,
}
}
}
impl<T> Infos for LWECiphertext<T> {
type Inner = VecZnx<T>;
fn n(&self) -> usize{
&self.inner().n-1
}
fn inner(&self) -> &Self::Inner {
&self.data
}
fn basek(&self) -> usize {
self.basek
}
fn k(&self) -> usize {
self.k
}
}
impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> SetMetaData for LWECiphertext<DataSelf> {
fn set_k(&mut self, k: usize) {
self.k = k
}
fn set_basek(&mut self, basek: usize) {
self.basek = basek
}
}
pub trait LWECiphertextToRef {
fn to_ref(&self) -> LWECiphertext<&[u8]>;
}
impl<D: AsRef<[u8]>> LWECiphertextToRef for LWECiphertext<D> {
fn to_ref(&self) -> LWECiphertext<&[u8]> {
LWECiphertext {
data: self.data.to_ref(),
basek: self.basek,
k: self.k,
}
}
}
pub trait LWECiphertextToMut {
fn to_mut(&mut self) -> LWECiphertext<&mut [u8]>;
}
impl<D: AsMut<[u8]> + AsRef<[u8]>> LWECiphertextToMut for LWECiphertext<D> {
fn to_mut(&mut self) -> LWECiphertext<&mut [u8]> {
LWECiphertext {
data: self.data.to_mut(),
basek: self.basek,
k: self.k,
}
}
}

View File

@@ -0,0 +1,21 @@
use backend::{alloc_aligned, ZnxView, ZnxViewMut};
use crate::{lwe::{LWEPlaintext}, Infos, LWECiphertext, LWESecret, SetMetaData};
impl<DataSelf> LWECiphertext<DataSelf> where DataSelf: AsRef<[u8]>{
pub fn decrypt<DataPt, DataSk>(&self, pt: &mut LWEPlaintext<DataPt>, sk: &LWESecret<DataSk>) where DataPt: AsRef<[u8]> + AsMut<[u8]>, DataSk: AsRef<[u8]>{
#[cfg(debug_assertions)]{
assert_eq!(self.n(), sk.n());
}
(0..pt.size().min(self.size())).for_each(|i|{
pt.data.at_mut(0, i)[0] = self.data.at(0, i)[0] + self.data.at(0, i)[1..].iter().zip(sk.data.at(0, 0)).map(|(x, y)| x * y).sum::<i64>();
});
let mut tmp_bytes: Vec<u8> = alloc_aligned(size_of::<i64>());
pt.data.normalize(self.basek(), 0, &mut tmp_bytes);
pt.set_basek(self.basek());
pt.set_k(self.k().min(pt.size() * self.basek()));
}
}

View File

@@ -0,0 +1,35 @@
use backend::{alloc_aligned, AddNormal, FillUniform, VecZnx, ZnxView, ZnxViewMut};
use sampling::source::Source;
use crate::{lwe::LWEPlaintext, Infos, LWECiphertext, LWESecret, SIX_SIGMA};
impl<DataSelf> LWECiphertext<DataSelf> where DataSelf: AsMut<[u8]> + AsRef<[u8]>{
pub fn encrypt_sk<DataPt, DataSk>(&mut self, pt: &LWEPlaintext<DataPt>, sk: &LWESecret<DataSk>, source_xa: &mut Source, source_xe: &mut Source, sigma: f64) where DataPt: AsRef<[u8]>, DataSk: AsRef<[u8]>{
#[cfg(debug_assertions)]{
assert_eq!(self.n(), sk.n())
}
let basek: usize = self.basek();
self.data.fill_uniform(basek, 0, self.size(), source_xa);
let mut tmp_znx: VecZnx<Vec<u8>> = VecZnx::<Vec<u8>>::new::<i64>(1, 1, self.size());
(0..self.size()).for_each(|i|{
tmp_znx.at_mut(0, i)[0] = pt.data.at(0, i)[0] - self.data.at(0, i)[1..].iter().zip(sk.data.at(0, 0)).map(|(x, y)| x * y).sum::<i64>();
});
tmp_znx.add_normal(basek, 0, self.k(), source_xe, sigma, sigma*SIX_SIGMA);
let mut tmp_bytes: Vec<u8> = alloc_aligned(size_of::<i64>());
tmp_znx.normalize(basek, 0, &mut tmp_bytes);
(0..self.size()).for_each(|i|{
self.data.at_mut(0, i)[0] = tmp_znx.at(0, i)[0];
});
}
}

View File

@@ -1,3 +1,9 @@
pub mod ciphertext;
pub mod secret;
pub mod encryption;
pub mod decryption;
pub mod plaintext;
pub use ciphertext::LWECiphertext;
pub use secret::LWESecret;
pub use plaintext::LWEPlaintext;

73
core/src/lwe/plaintext.rs Normal file
View File

@@ -0,0 +1,73 @@
use backend::{VecZnx, VecZnxToMut, VecZnxToRef};
use crate::{Infos, SetMetaData};
pub struct LWEPlaintext<D>{
pub(crate) data: VecZnx<D>,
pub(crate) k: usize,
pub(crate) basek: usize,
}
impl LWEPlaintext<Vec<u8>> {
pub fn alloc(basek: usize, k: usize) -> Self {
Self {
data: VecZnx::new::<i64>(1, 1, k.div_ceil(basek)),
k: k,
basek: basek,
}
}
}
impl<T> Infos for LWEPlaintext<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<DataSelf: AsMut<[u8]> + AsRef<[u8]>> SetMetaData for LWEPlaintext<DataSelf> {
fn set_k(&mut self, k: usize) {
self.k = k
}
fn set_basek(&mut self, basek: usize) {
self.basek = basek
}
}
pub trait LWEPlaintextToRef {
fn to_ref(&self) -> LWEPlaintext<&[u8]>;
}
impl<D: AsRef<[u8]>> LWEPlaintextToRef for LWEPlaintext<D> {
fn to_ref(&self) -> LWEPlaintext<&[u8]> {
LWEPlaintext {
data: self.data.to_ref(),
basek: self.basek,
k: self.k,
}
}
}
pub trait LWEPlaintextToMut {
fn to_mut(&mut self) -> LWEPlaintext<&mut [u8]>;
}
impl<D: AsMut<[u8]> + AsRef<[u8]>> LWEPlaintextToMut for LWEPlaintext<D> {
fn to_mut(&mut self) -> LWEPlaintext<&mut [u8]> {
LWEPlaintext {
data: self.data.to_mut(),
basek: self.basek,
k: self.k,
}
}
}