mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 13:16:44 +01:00
wip on BR + added enc/dec for LWE
This commit is contained in:
@@ -103,7 +103,7 @@ fn alloc_aligned_custom_u8(size: usize, align: usize) -> Vec<u8> {
|
|||||||
/// Size of T * size msut be a multiple of [DEFAULTALIGN].
|
/// Size of T * size msut be a multiple of [DEFAULTALIGN].
|
||||||
pub fn alloc_aligned_custom<T>(size: usize, align: usize) -> Vec<T> {
|
pub fn alloc_aligned_custom<T>(size: usize, align: usize) -> Vec<T> {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
(size * size_of::<T>()) % align,
|
(size * size_of::<T>()) % (align/ size_of::<T>()),
|
||||||
0,
|
0,
|
||||||
"size={} must be a multiple of align={}",
|
"size={} must be a multiple of align={}",
|
||||||
size,
|
size,
|
||||||
@@ -121,7 +121,7 @@ pub fn alloc_aligned_custom<T>(size: usize, align: usize) -> Vec<T> {
|
|||||||
/// of [DEFAULTALIGN]/size_of::<T>() that is equal or greater to `size`.
|
/// of [DEFAULTALIGN]/size_of::<T>() that is equal or greater to `size`.
|
||||||
pub fn alloc_aligned<T>(size: usize) -> Vec<T> {
|
pub fn alloc_aligned<T>(size: usize) -> Vec<T> {
|
||||||
alloc_aligned_custom::<T>(
|
alloc_aligned_custom::<T>(
|
||||||
size + (size % (DEFAULTALIGN / size_of::<T>())),
|
size + (DEFAULTALIGN - (size % (DEFAULTALIGN / size_of::<T>()))),
|
||||||
DEFAULTALIGN,
|
DEFAULTALIGN,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,12 @@ pub trait MatZnxDftOps<BACKEND: Backend> {
|
|||||||
where
|
where
|
||||||
A: MatZnxToMut<FFT64>;
|
A: MatZnxToMut<FFT64>;
|
||||||
|
|
||||||
|
/// Multiplies A by (X^{k} - 1).
|
||||||
|
fn mat_znx_dft_mul_x_pow_minus_one_add_inplace<R, A>(&self, k: i64, res: &mut R, a: &A, scratch: &mut Scratch)
|
||||||
|
where
|
||||||
|
R: MatZnxToMut<FFT64>,
|
||||||
|
A: MatZnxToRef<FFT64>;
|
||||||
|
|
||||||
/// Applies the vector matrix product [VecZnxDft] x [MatZnxDft].
|
/// Applies the vector matrix product [VecZnxDft] x [MatZnxDft].
|
||||||
/// The size of `buf` is given by [MatZnxDftOps::vmp_apply_dft_to_dft_tmp_bytes].
|
/// The size of `buf` is given by [MatZnxDftOps::vmp_apply_dft_to_dft_tmp_bytes].
|
||||||
///
|
///
|
||||||
@@ -212,7 +218,7 @@ impl MatZnxDftOps<FFT64> for Module<FFT64> {
|
|||||||
|
|
||||||
self.mat_znx_dft_set_row(&mut res, row_i, col_j, &tmp_1);
|
self.mat_znx_dft_set_row(&mut res, row_i, col_j, &tmp_1);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mat_znx_dft_mul_x_pow_minus_one_inplace<A>(&self, k: i64, a: &mut A, scratch: &mut Scratch)
|
fn mat_znx_dft_mul_x_pow_minus_one_inplace<A>(&self, k: i64, a: &mut A, scratch: &mut Scratch)
|
||||||
@@ -249,7 +255,52 @@ impl MatZnxDftOps<FFT64> for Module<FFT64> {
|
|||||||
|
|
||||||
self.mat_znx_dft_set_row(&mut a, row_i, col_j, &tmp_1);
|
self.mat_znx_dft_set_row(&mut a, row_i, col_j, &tmp_1);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mat_znx_dft_mul_x_pow_minus_one_add_inplace<R, A>(&self, k: i64, res: &mut R, a: &A, scratch: &mut Scratch)
|
||||||
|
where
|
||||||
|
R: MatZnxToMut<FFT64>,
|
||||||
|
A: MatZnxToRef<FFT64>,
|
||||||
|
{
|
||||||
|
let mut res: MatZnxDft<&mut [u8], FFT64> = res.to_mut();
|
||||||
|
let a: MatZnxDft<&[u8], FFT64> = a.to_ref();
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
assert_eq!(a.n(), self.n());
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mut xpm1_dft, scratch1) = scratch.tmp_scalar_znx_dft(self, 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
let (mut xpm1, _) = scratch1.tmp_scalar_znx(self, 1);
|
||||||
|
xpm1.data[0] = 1;
|
||||||
|
self.vec_znx_rotate_inplace(k, &mut xpm1, 0);
|
||||||
|
self.svp_prepare(&mut xpm1_dft, 0, &xpm1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mut tmp_0, scratch2) = scratch1.tmp_vec_znx_dft(self, a.cols_out(), a.size());
|
||||||
|
let (mut tmp_1, _) = scratch2.tmp_vec_znx_dft(self, a.cols_out(), a.size());
|
||||||
|
|
||||||
|
(0..a.rows()).for_each(|row_i| {
|
||||||
|
(0..a.cols_in()).for_each(|col_j| {
|
||||||
|
self.mat_znx_dft_get_row(&mut tmp_0, &a, row_i, col_j);
|
||||||
|
|
||||||
|
(0..tmp_0.cols()).for_each(|i| {
|
||||||
|
self.svp_apply(&mut tmp_1, i, &xpm1_dft, 0, &tmp_0, i);
|
||||||
|
self.vec_znx_dft_sub_ab_inplace(&mut tmp_1, i, &tmp_0, i);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.mat_znx_dft_get_row(&mut tmp_0, &res, row_i, col_j);
|
||||||
|
|
||||||
|
(0..tmp_0.cols()).for_each(|i| {
|
||||||
|
self.vec_znx_dft_add_inplace(&mut tmp_0, i, &tmp_1, i);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.mat_znx_dft_set_row(&mut res, row_i, col_j, &tmp_0);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mat_znx_dft_set_row<R, A>(&self, res: &mut R, res_row: usize, res_col_in: usize, a: &A)
|
fn mat_znx_dft_set_row<R, A>(&self, res: &mut R, res_row: usize, res_col_in: usize, a: &A)
|
||||||
@@ -845,7 +896,6 @@ mod tests {
|
|||||||
|
|
||||||
(0..cols_out).for_each(|j| {
|
(0..cols_out).for_each(|j| {
|
||||||
module.vec_znx_idft(&mut tmp_big, 0, &tmp_dft, j, scratch.borrow());
|
module.vec_znx_idft(&mut tmp_big, 0, &tmp_dft, j, scratch.borrow());
|
||||||
// module.vec_znx_big_normalize(basek, &mut want, j, &tmp_big, 0, scratch.borrow());
|
|
||||||
module.vec_znx_big_normalize(basek, &mut tmp, 0, &tmp_big, 0, scratch.borrow());
|
module.vec_znx_big_normalize(basek, &mut tmp, 0, &tmp_big, 0, scratch.borrow());
|
||||||
module.vec_znx_rotate(k, &mut want, j, &tmp, 0);
|
module.vec_znx_rotate(k, &mut want, j, &tmp, 0);
|
||||||
module.vec_znx_sub_ab_inplace(&mut want, j, &tmp, 0);
|
module.vec_znx_sub_ab_inplace(&mut want, j, &tmp, 0);
|
||||||
@@ -863,4 +913,84 @@ mod tests {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mat_znx_dft_mul_x_pow_minus_one_add_inplace() {
|
||||||
|
let log_n: i32 = 5;
|
||||||
|
let n: usize = 1 << log_n;
|
||||||
|
|
||||||
|
let module: Module<FFT64> = Module::<FFT64>::new(n);
|
||||||
|
let basek: usize = 8;
|
||||||
|
let rows: usize = 2;
|
||||||
|
let cols_in: usize = 2;
|
||||||
|
let cols_out: usize = 2;
|
||||||
|
let size: usize = 4;
|
||||||
|
|
||||||
|
let mut scratch: ScratchOwned = ScratchOwned::new(module.mat_znx_dft_mul_x_pow_minus_one_scratch_space(size, cols_out));
|
||||||
|
|
||||||
|
let mut mat_want: MatZnxDft<Vec<u8>, FFT64> = module.new_mat_znx_dft(rows, cols_in, cols_out, size);
|
||||||
|
let mut mat_have: MatZnxDft<Vec<u8>, FFT64> = module.new_mat_znx_dft(rows, cols_in, cols_out, size);
|
||||||
|
|
||||||
|
let mut tmp: VecZnx<Vec<u8>> = module.new_vec_znx(1, size);
|
||||||
|
let mut tmp_dft: VecZnxDft<Vec<u8>, FFT64> = module.new_vec_znx_dft(cols_out, size);
|
||||||
|
|
||||||
|
let mut source: Source = Source::new([0u8; 32]);
|
||||||
|
|
||||||
|
(0..mat_have.rows()).for_each(|row_i| {
|
||||||
|
(0..mat_have.cols_in()).for_each(|col_i| {
|
||||||
|
(0..cols_out).for_each(|j| {
|
||||||
|
tmp.fill_uniform(basek, 0, size, &mut source);
|
||||||
|
module.vec_znx_dft(1, 0, &mut tmp_dft, j, &tmp, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.mat_znx_dft_set_row(&mut mat_have, row_i, col_i, &tmp_dft);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
(0..mat_want.rows()).for_each(|row_i| {
|
||||||
|
(0..mat_want.cols_in()).for_each(|col_i| {
|
||||||
|
(0..cols_out).for_each(|j| {
|
||||||
|
tmp.fill_uniform(basek, 0, size, &mut source);
|
||||||
|
module.vec_znx_dft(1, 0, &mut tmp_dft, j, &tmp, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.mat_znx_dft_set_row(&mut mat_want, row_i, col_i, &tmp_dft);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let k: i64 = 1;
|
||||||
|
|
||||||
|
module.mat_znx_dft_mul_x_pow_minus_one_add_inplace(k, &mut mat_have, &mat_want, scratch.borrow());
|
||||||
|
|
||||||
|
let mut have: VecZnx<Vec<u8>> = module.new_vec_znx(cols_out, size);
|
||||||
|
let mut want: VecZnx<Vec<u8>> = module.new_vec_znx(cols_out, size);
|
||||||
|
let mut tmp_big: VecZnxBig<Vec<u8>, FFT64> = module.new_vec_znx_big(1, size);
|
||||||
|
|
||||||
|
let mut source: Source = Source::new([0u8; 32]);
|
||||||
|
(0..mat_want.rows()).for_each(|row_i| {
|
||||||
|
(0..mat_want.cols_in()).for_each(|col_i| {
|
||||||
|
module.mat_znx_dft_get_row(&mut tmp_dft, &mat_want, row_i, col_i);
|
||||||
|
|
||||||
|
(0..cols_out).for_each(|j| {
|
||||||
|
module.vec_znx_idft(&mut tmp_big, 0, &tmp_dft, j, scratch.borrow());
|
||||||
|
module.vec_znx_big_normalize(basek, &mut tmp, 0, &tmp_big, 0, scratch.borrow());
|
||||||
|
module.vec_znx_rotate(k, &mut want, j, &tmp, 0);
|
||||||
|
module.vec_znx_sub_ab_inplace(&mut want, j, &tmp, 0);
|
||||||
|
|
||||||
|
tmp.fill_uniform(basek, 0, size, &mut source);
|
||||||
|
module.vec_znx_add_inplace(&mut want, j, &tmp, 0);
|
||||||
|
module.vec_znx_normalize_inplace(basek, &mut want, j, scratch.borrow());
|
||||||
|
});
|
||||||
|
|
||||||
|
module.mat_znx_dft_get_row(&mut tmp_dft, &mat_have, row_i, col_i);
|
||||||
|
|
||||||
|
(0..cols_out).for_each(|j| {
|
||||||
|
module.vec_znx_idft(&mut tmp_big, 0, &tmp_dft, j, scratch.borrow());
|
||||||
|
module.vec_znx_big_normalize(basek, &mut have, j, &tmp_big, 0, scratch.borrow());
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(have, want)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,9 +91,9 @@ impl<D: AsMut<[u8]> + AsRef<[u8]>> ScalarZnx<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn fill_binary_block(&mut self, col: usize, block_size: usize, source: &mut Source) {
|
pub fn fill_binary_block(&mut self, col: usize, block_size: usize, source: &mut Source) {
|
||||||
assert!(block_size & (block_size - 1) == 0);
|
assert!(self.n() % block_size == 0);
|
||||||
let max_idx: u64 = (block_size + 1) as u64;
|
let max_idx: u64 = (block_size + 1) as u64;
|
||||||
let mask_idx: u64 = (2 * block_size - 1) as u64;
|
let mask_idx: u64 = (1<<((u64::BITS - max_idx.leading_zeros())as u64)) - 1 ;
|
||||||
for block in self.at_mut(col, 0).chunks_mut(block_size) {
|
for block in self.at_mut(col, 0).chunks_mut(block_size) {
|
||||||
let idx: usize = source.next_u64n(max_idx, mask_idx) as usize;
|
let idx: usize = source.next_u64n(max_idx, mask_idx) as usize;
|
||||||
if idx != block_size {
|
if idx != block_size {
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ impl<D: From<Vec<u8>>> VecZnx<D> {
|
|||||||
n * cols * size * size_of::<Scalar>()
|
n * cols * size * size_of::<Scalar>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new<Scalar: Sized>(n: usize, cols: usize, size: usize) -> Self {
|
pub fn new<Scalar: Sized>(n: usize, cols: usize, size: usize) -> Self {
|
||||||
let data = alloc_aligned::<u8>(Self::bytes_of::<Scalar>(n, cols, size));
|
let data = alloc_aligned::<u8>(Self::bytes_of::<Scalar>(n, cols, size));
|
||||||
Self {
|
Self {
|
||||||
data: data.into(),
|
data: data.into(),
|
||||||
@@ -243,7 +243,13 @@ fn normalize_tmp_bytes(n: usize) -> usize {
|
|||||||
n * std::mem::size_of::<i64>()
|
n * std::mem::size_of::<i64>()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
impl<D: AsRef<[u8]> + AsMut<[u8]>> VecZnx<D>{
|
||||||
|
pub fn normalize(&mut self, basek: usize, a_col: usize, tmp_bytes: &mut [u8]){
|
||||||
|
normalize(basek, self, a_col, tmp_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn normalize<D: AsMut<[u8]> + AsRef<[u8]>>(basek: usize, a: &mut VecZnx<D>, a_col: usize, tmp_bytes: &mut [u8]) {
|
fn normalize<D: AsMut<[u8]> + AsRef<[u8]>>(basek: usize, a: &mut VecZnx<D>, a_col: usize, tmp_bytes: &mut [u8]) {
|
||||||
let n: usize = a.n();
|
let n: usize = a.n();
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ fn bench_external_product_glwe_fft64(c: &mut Criterion) {
|
|||||||
let rank: usize = p.rank;
|
let rank: usize = p.rank;
|
||||||
let digits: usize = 1;
|
let digits: usize = 1;
|
||||||
|
|
||||||
let rows: usize = (p.k_ct_in + p.basek - 1) / p.basek;
|
let rows: usize = 1; //(p.k_ct_in + p.basek - 1) / p.basek;
|
||||||
let sigma: f64 = 3.2;
|
let sigma: f64 = 3.2;
|
||||||
|
|
||||||
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);
|
||||||
@@ -81,11 +81,11 @@ fn bench_external_product_glwe_fft64(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let params_set: Vec<Params> = vec![Params {
|
let params_set: Vec<Params> = vec![Params {
|
||||||
log_n: 10,
|
log_n: 11,
|
||||||
basek: 7,
|
basek: 22,
|
||||||
k_ct_in: 27,
|
k_ct_in: 44,
|
||||||
k_ct_out: 27,
|
k_ct_out: 44,
|
||||||
k_ggsw: 27,
|
k_ggsw: 54,
|
||||||
rank: 1,
|
rank: 1,
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
use backend::{Backend, FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxToRef, Scratch, ZnxView, ZnxViewMut};
|
use backend::{Backend, FFT64, Module, ScalarZnx, ScalarZnxAlloc, ScalarZnxToRef, Scratch, ZnxView, ZnxViewMut};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{Distribution, FourierGLWESecret, GGSWCiphertext, GLWEAutomorphismKey, LWESecret};
|
use crate::{Distribution, FourierGLWESecret, GGSWCiphertext, Infos, LWESecret};
|
||||||
|
|
||||||
pub struct BlindRotationKeyCGGI<B: Backend> {
|
pub struct BlindRotationKeyCGGI<B: Backend> {
|
||||||
pub(crate) data: Vec<GGSWCiphertext<Vec<u8>, B>>,
|
pub(crate) data: Vec<GGSWCiphertext<Vec<u8>, B>>,
|
||||||
pub(crate) dist: Distribution,
|
pub(crate) dist: Distribution,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BlindRotationKeyFHEW<B: Backend> {
|
// pub struct BlindRotationKeyFHEW<B: Backend> {
|
||||||
pub(crate) data: Vec<GGSWCiphertext<Vec<u8>, B>>,
|
// pub(crate) data: Vec<GGSWCiphertext<Vec<u8>, B>>,
|
||||||
pub(crate) auto: Vec<GLWEAutomorphismKey<Vec<u8>, B>>,
|
// pub(crate) auto: Vec<GLWEAutomorphismKey<Vec<u8>, B>>,
|
||||||
}
|
//}
|
||||||
|
|
||||||
impl BlindRotationKeyCGGI<FFT64> {
|
impl BlindRotationKeyCGGI<FFT64> {
|
||||||
pub fn allocate(module: &Module<FFT64>, lwe_degree: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self {
|
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(lwe_degree);
|
let mut data: Vec<GGSWCiphertext<Vec<u8>, FFT64>> = Vec::with_capacity(n_lwe);
|
||||||
(0..lwe_degree).for_each(|_| data.push(GGSWCiphertext::alloc(module, basek, k, rows, 1, rank)));
|
(0..n_lwe).for_each(|_| data.push(GGSWCiphertext::alloc(module, basek, k, rows, 1, rank)));
|
||||||
Self {
|
Self {
|
||||||
data,
|
data,
|
||||||
dist: Distribution::NONE,
|
dist: Distribution::NONE,
|
||||||
@@ -61,4 +61,27 @@ impl BlindRotationKeyCGGI<FFT64> {
|
|||||||
ggsw.encrypt_sk(module, &pt, sk_glwe, source_xa, source_xe, sigma, scratch);
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
// pub mod cggi;
|
// pub mod cggi;
|
||||||
|
pub mod ccgi;
|
||||||
pub mod key;
|
pub mod key;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod test_fft64;
|
||||||
|
|||||||
85
core/src/blind_rotation/test_fft64/cggi.rs
Normal file
85
core/src/blind_rotation/test_fft64/cggi.rs
Normal 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);
|
||||||
|
}
|
||||||
1
core/src/blind_rotation/test_fft64/mod.rs
Normal file
1
core/src/blind_rotation/test_fft64/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod cggi;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use backend::{Backend, Module, ZnxInfos};
|
use backend::{Backend, Module, ZnxInfos};
|
||||||
|
|
||||||
use crate::{FourierGLWECiphertext, div_ceil};
|
use crate::FourierGLWECiphertext;
|
||||||
|
|
||||||
pub trait Infos {
|
pub trait Infos {
|
||||||
type Inner: ZnxInfos;
|
type Inner: ZnxInfos;
|
||||||
|
|||||||
@@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use backend::{Backend, Module, VecZnxDft, VecZnxDftAlloc};
|
use backend::{Backend, Module, VecZnxDft, VecZnxDftAlloc};
|
||||||
|
|
||||||
use crate::{Infos, div_ceil};
|
use crate::Infos;
|
||||||
|
|
||||||
pub struct FourierGLWECiphertext<C, B: Backend> {
|
pub struct FourierGLWECiphertext<C, B: Backend> {
|
||||||
pub data: VecZnxDft<C, B>,
|
pub data: VecZnxDft<C, B>,
|
||||||
@@ -11,14 +11,14 @@ pub struct FourierGLWECiphertext<C, B: Backend> {
|
|||||||
impl<B: Backend> FourierGLWECiphertext<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, div_ceil(k, basek)),
|
data: module.new_vec_znx_dft(rank + 1, k.div_ceil(basek)),
|
||||||
basek: basek,
|
basek: basek,
|
||||||
k: k,
|
k: k,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bytes_of(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize {
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ use backend::{
|
|||||||
VecZnxDftOps, ZnxZero,
|
VecZnxDftOps, ZnxZero,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, GLWEPlaintext, Infos, div_ceil};
|
use crate::{FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, GLWEPlaintext, Infos};
|
||||||
|
|
||||||
impl FourierGLWECiphertext<Vec<u8>, FFT64> {
|
impl FourierGLWECiphertext<Vec<u8>, FFT64> {
|
||||||
pub fn decrypt_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize {
|
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.vec_znx_big_normalize_tmp_bytes()
|
||||||
| module.bytes_of_vec_znx_dft(1, size)
|
| 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) + module.vec_znx_idft_tmp_bytes()))
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
use backend::{FFT64, Module, Scratch, VecZnxAlloc, VecZnxBigScratch, VecZnxDftOps};
|
use backend::{FFT64, Module, Scratch, VecZnxAlloc, VecZnxBigScratch, VecZnxDftOps};
|
||||||
use sampling::source::Source;
|
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> {
|
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, 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())
|
+ (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 {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use backend::{
|
|||||||
VecZnxDftAlloc, VecZnxDftOps,
|
VecZnxDftAlloc, VecZnxDftOps,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{FourierGLWECiphertext, GGSWCiphertext, Infos, div_ceil};
|
use crate::{FourierGLWECiphertext, GGSWCiphertext, Infos};
|
||||||
|
|
||||||
impl FourierGLWECiphertext<Vec<u8>, FFT64> {
|
impl FourierGLWECiphertext<Vec<u8>, FFT64> {
|
||||||
// WARNING TODO: UPDATE
|
// WARNING TODO: UPDATE
|
||||||
@@ -16,10 +16,10 @@ impl FourierGLWECiphertext<Vec<u8>, FFT64> {
|
|||||||
digits: usize,
|
digits: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> 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 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 in_size: usize = k_in.div_ceil(basek).div_ceil(digits);
|
||||||
let ggsw_size: usize = div_ceil(k_ggsw, basek);
|
let ggsw_size: usize = k_ggsw.div_ceil(basek);
|
||||||
let vmp: usize = module.bytes_of_vec_znx_dft(rank + 1, in_size)
|
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);
|
+ 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 res_small: usize = module.bytes_of_vec_znx(rank + 1, ggsw_size);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
FourierGLWECiphertext, FourierGLWESecret, GGSWCiphertext, GLWECiphertext, GLWEOps, GLWEPlaintext, GLWESecret, Infos,
|
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 backend::{FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwned, Stats, VecZnxOps, ZnxViewMut};
|
||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
@@ -10,7 +10,7 @@ fn apply() {
|
|||||||
let log_n: usize = 8;
|
let log_n: usize = 8;
|
||||||
let basek: usize = 12;
|
let basek: usize = 12;
|
||||||
let k_in: usize = 45;
|
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..4).for_each(|rank| {
|
||||||
(1..digits + 1).for_each(|di| {
|
(1..digits + 1).for_each(|di| {
|
||||||
let k_ggsw: usize = k_in + basek * di;
|
let k_ggsw: usize = k_in + basek * di;
|
||||||
@@ -26,7 +26,7 @@ fn apply_inplace() {
|
|||||||
let log_n: usize = 8;
|
let log_n: usize = 8;
|
||||||
let basek: usize = 12;
|
let basek: usize = 12;
|
||||||
let k_ct: usize = 60;
|
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..4).for_each(|rank| {
|
||||||
(1..digits + 1).for_each(|di| {
|
(1..digits + 1).for_each(|di| {
|
||||||
let k_ggsw: usize = k_ct + basek * 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) {
|
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 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_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);
|
||||||
@@ -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) {
|
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 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_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);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos, div_ceil,
|
FourierGLWECiphertext, FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos,
|
||||||
noise::log2_std_noise_gglwe_product,
|
noise::log2_std_noise_gglwe_product,
|
||||||
};
|
};
|
||||||
use backend::{FFT64, FillUniform, Module, ScratchOwned, Stats, VecZnxOps};
|
use backend::{FFT64, FillUniform, Module, ScratchOwned, Stats, VecZnxOps};
|
||||||
@@ -10,7 +10,7 @@ fn apply() {
|
|||||||
let log_n: usize = 8;
|
let log_n: usize = 8;
|
||||||
let basek: usize = 12;
|
let basek: usize = 12;
|
||||||
let k_in: usize = 45;
|
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_in| {
|
||||||
(1..4).for_each(|rank_out| {
|
(1..4).for_each(|rank_out| {
|
||||||
(1..digits + 1).for_each(|di| {
|
(1..digits + 1).for_each(|di| {
|
||||||
@@ -31,7 +31,7 @@ fn apply_inplace() {
|
|||||||
let log_n: usize = 8;
|
let log_n: usize = 8;
|
||||||
let basek: usize = 12;
|
let basek: usize = 12;
|
||||||
let k_ct: usize = 45;
|
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..4).for_each(|rank| {
|
||||||
(1..digits + 1).for_each(|di| {
|
(1..digits + 1).for_each(|di| {
|
||||||
let k_ksk: usize = k_ct + basek * 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 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> =
|
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);
|
||||||
@@ -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) {
|
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 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 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);
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -62,24 +62,33 @@ impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWEAutomorphismKey<DataSelf, FFT64> {
|
|||||||
self.rank_out(),
|
self.rank_out(),
|
||||||
rhs.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 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.rank_in()).for_each(|col_i| {
|
||||||
(0..self.rows()).for_each(|row_j| {
|
(0..self.rows()).for_each(|row_j| {
|
||||||
// Extracts relevant row
|
let (mut tmp_idft_data, scratct1) = scratch.tmp_vec_znx_big(module, cols_out, self.size());
|
||||||
lhs.get_row(module, row_j, col_i, &mut tmp_dft);
|
|
||||||
|
|
||||||
// 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
|
// Extracts relevant row
|
||||||
(0..cols_out).for_each(|i| {
|
lhs.get_row(module, row_j, col_i, &mut tmp_dft);
|
||||||
module.vec_znx_idft(&mut tmp_idft_data, i, &tmp_dft.data, i, scratch2);
|
|
||||||
});
|
// 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
|
// Consumes to small vec znx
|
||||||
let mut tmp_idft_small_data: VecZnx<&mut [u8]> = tmp_idft_data.to_vec_znx_small();
|
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)
|
// 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
|
let (mut tmp_dft, _) = scratct1.tmp_glwe_fourier(module, self.basek(), self.k(), self.rank());
|
||||||
(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
|
// Applies back the automorphism X^{k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) -> (-pi^{-1}_{k'+k}(s)a + s, a)
|
||||||
self.set_row(module, row_j, col_i, &tmp_dft);
|
// 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();
|
tmp_dft.data.zero();
|
||||||
|
|
||||||
(self.rows().min(lhs.rows())..self.rows()).for_each(|row_i| {
|
(self.rows().min(lhs.rows())..self.rows()).for_each(|row_i| {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use backend::{Backend, FFT64, MatZnxDft, MatZnxDftAlloc, MatZnxDftOps, Module};
|
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 struct GGLWECiphertext<C, B: Backend> {
|
||||||
pub(crate) data: MatZnxDft<C, B>,
|
pub(crate) data: MatZnxDft<C, B>,
|
||||||
@@ -19,7 +19,7 @@ impl<B: Backend> GGLWECiphertext<Vec<u8>, B> {
|
|||||||
rank_in: usize,
|
rank_in: usize,
|
||||||
rank_out: usize,
|
rank_out: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let size: usize = div_ceil(k, basek);
|
let size: usize = k.div_ceil(basek);
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
size > digits,
|
size > digits,
|
||||||
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
|
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
|
||||||
@@ -52,7 +52,7 @@ impl<B: Backend> GGLWECiphertext<Vec<u8>, B> {
|
|||||||
rank_in: usize,
|
rank_in: usize,
|
||||||
rank_out: usize,
|
rank_out: usize,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let size: usize = div_ceil(k, basek);
|
let size: usize = k.div_ceil(basek);
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
size > digits,
|
size > digits,
|
||||||
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
|
"invalid gglwe: ceil(k/basek): {} <= digits: {}",
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ use sampling::source::Source;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FourierGLWESecret, GGLWECiphertext, GLWEAutomorphismKey, GLWECiphertext, GLWESecret, GLWESwitchingKey, GLWETensorKey, Infos,
|
FourierGLWESecret, GGLWECiphertext, GLWEAutomorphismKey, GLWECiphertext, GLWESecret, GLWESwitchingKey, GLWETensorKey, Infos,
|
||||||
ScratchCore, SetRow, div_ceil,
|
ScratchCore, SetRow,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl GGLWECiphertext<Vec<u8>, FFT64> {
|
impl GGLWECiphertext<Vec<u8>, FFT64> {
|
||||||
pub fn generate_from_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
|
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)
|
GLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
|
||||||
+ module.bytes_of_vec_znx(rank + 1, size)
|
+ module.bytes_of_vec_znx(rank + 1, size)
|
||||||
+ module.bytes_of_vec_znx(1, size)
|
+ module.bytes_of_vec_znx(1, size)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use backend::{FFT64, Module, ScalarZnxOps, ScratchOwned, Stats, VecZnxOps};
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FourierGLWECiphertext, FourierGLWESecret, GLWEAutomorphismKey, GLWEPlaintext, GLWESecret, GetRow, Infos, div_ceil,
|
FourierGLWECiphertext, FourierGLWESecret, GLWEAutomorphismKey, GLWEPlaintext, GLWESecret, GetRow, Infos,
|
||||||
noise::log2_std_noise_gglwe_product,
|
noise::log2_std_noise_gglwe_product,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use sampling::source::Source;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FourierGLWECiphertext, FourierGLWESecret, GGSWCiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, GetRow, Infos,
|
FourierGLWECiphertext, FourierGLWESecret, GGSWCiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, GetRow, Infos,
|
||||||
div_ceil,
|
|
||||||
noise::{log2_std_noise_gglwe_product, noise_ggsw_product},
|
noise::{log2_std_noise_gglwe_product, noise_ggsw_product},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use sampling::source::Source;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FourierGLWECiphertext, FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWESwitchingKey, GLWETensorKey, GetRow,
|
FourierGLWECiphertext, FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWESwitchingKey, GLWETensorKey, GetRow,
|
||||||
Infos, ScratchCore, SetRow, div_ceil,
|
Infos, ScratchCore, SetRow,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct GGSWCiphertext<C, B: Backend> {
|
pub struct GGSWCiphertext<C, B: Backend> {
|
||||||
@@ -17,8 +17,8 @@ pub struct GGSWCiphertext<C, B: Backend> {
|
|||||||
pub(crate) digits: usize,
|
pub(crate) digits: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Backend> GGSWCiphertext<Vec<u8>, B> {
|
impl GGSWCiphertext<Vec<u8>, FFT64> {
|
||||||
pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
|
pub fn alloc(module: &Module<FFT64>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
|
||||||
let size: usize = k.div_ceil(basek);
|
let size: usize = k.div_ceil(basek);
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
size > digits,
|
size > digits,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use sampling::source::Source;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FourierGLWECiphertext, FourierGLWESecret, GGSWCiphertext, GLWEAutomorphismKey, GLWEPlaintext, GLWESecret, GLWESwitchingKey,
|
FourierGLWECiphertext, FourierGLWESecret, GGSWCiphertext, GLWEAutomorphismKey, GLWEPlaintext, GLWESecret, GLWESwitchingKey,
|
||||||
GLWETensorKey, GetRow, Infos, div_ceil,
|
GLWETensorKey, GetRow, Infos,
|
||||||
noise::{noise_ggsw_keyswitch, noise_ggsw_product},
|
noise::{noise_ggsw_keyswitch, noise_ggsw_product},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
use backend::{
|
use backend::{Backend, FFT64, Module, VecZnx, VecZnxAlloc, VecZnxDftOps, VecZnxToMut, VecZnxToRef};
|
||||||
Backend, FFT64, Module, VecZnx, VecZnxAlloc, VecZnxBigAlloc, VecZnxBigScratch, VecZnxDftAlloc, VecZnxDftOps, VecZnxToMut,
|
|
||||||
VecZnxToRef,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{FourierGLWECiphertext, GLWEOps, Infos, SetMetaData, div_ceil};
|
use crate::{FourierGLWECiphertext, GLWEOps, Infos, SetMetaData};
|
||||||
|
|
||||||
pub struct GLWECiphertext<C> {
|
pub struct GLWECiphertext<C> {
|
||||||
pub data: VecZnx<C>,
|
pub data: VecZnx<C>,
|
||||||
@@ -14,14 +11,14 @@ pub struct GLWECiphertext<C> {
|
|||||||
impl GLWECiphertext<Vec<u8>> {
|
impl GLWECiphertext<Vec<u8>> {
|
||||||
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self {
|
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> Self {
|
||||||
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,
|
basek,
|
||||||
k,
|
k,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bytes_of(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
|
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>> {
|
impl<DataSelf: AsRef<[u8]>> GLWECiphertext<DataSelf> {
|
||||||
pub fn decrypt_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize {
|
pub fn clone(&self) -> GLWECiphertext<Vec<u8>> {
|
||||||
let size: usize = div_ceil(k, basek);
|
GLWECiphertext {
|
||||||
(module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size)
|
data: self.data.clone(),
|
||||||
|
basek: self.basek(),
|
||||||
|
k: self.k(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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};
|
use crate::{FourierGLWESecret, GLWECiphertext, GLWEPlaintext, Infos};
|
||||||
|
|
||||||
impl<DataSelf: AsRef<[u8]>> GLWECiphertext<DataSelf> {
|
impl GLWECiphertext<Vec<u8>> {
|
||||||
pub fn clone(&self) -> GLWECiphertext<Vec<u8>> {
|
pub fn decrypt_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize {
|
||||||
GLWECiphertext {
|
let size: usize = k.div_ceil(basek);
|
||||||
data: self.data.clone(),
|
(module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size)
|
||||||
basek: self.basek(),
|
|
||||||
k: self.k(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<DataSelf: AsRef<[u8]>> GLWECiphertext<DataSelf> {
|
||||||
pub fn decrypt<DataPt: AsMut<[u8]> + AsRef<[u8]>, DataSk: AsRef<[u8]>>(
|
pub fn decrypt<DataPt: AsMut<[u8]> + AsRef<[u8]>, DataSk: AsRef<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ use backend::{
|
|||||||
};
|
};
|
||||||
use sampling::source::Source;
|
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>> {
|
impl GLWECiphertext<Vec<u8>> {
|
||||||
pub fn encrypt_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize) -> usize {
|
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)
|
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 {
|
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_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.bytes_of_scalar_znx_dft(1)
|
||||||
+ module.vec_znx_big_normalize_tmp_bytes()
|
+ module.vec_znx_big_normalize_tmp_bytes()
|
||||||
@@ -71,7 +71,7 @@ impl<DataSelf: AsRef<[u8]> + AsMut<[u8]>> GLWECiphertext<DataSelf> {
|
|||||||
sigma: f64,
|
sigma: f64,
|
||||||
scratch: &mut Scratch,
|
scratch: &mut Scratch,
|
||||||
) {
|
) {
|
||||||
self.encrypt_pk_private(
|
self.encrypt_pk_private::<DataPt, DataPk>(
|
||||||
module,
|
module,
|
||||||
Some((pt, 0)),
|
Some((pt, 0)),
|
||||||
pk,
|
pk,
|
||||||
@@ -91,7 +91,7 @@ impl<DataSelf: AsRef<[u8]> + AsMut<[u8]>> GLWECiphertext<DataSelf> {
|
|||||||
sigma: f64,
|
sigma: f64,
|
||||||
scratch: &mut Scratch,
|
scratch: &mut Scratch,
|
||||||
) {
|
) {
|
||||||
self.encrypt_pk_private(
|
self.encrypt_pk_private::<Vec<u8>, DataPk>(
|
||||||
module,
|
module,
|
||||||
None::<(&GLWEPlaintext<Vec<u8>>, usize)>,
|
None::<(&GLWEPlaintext<Vec<u8>>, usize)>,
|
||||||
pk,
|
pk,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use backend::{
|
|||||||
FFT64, MatZnxDftOps, MatZnxDftScratch, Module, Scratch, VecZnxBig, VecZnxBigOps, VecZnxDftAlloc, VecZnxDftOps, VecZnxScratch,
|
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>> {
|
impl GLWECiphertext<Vec<u8>> {
|
||||||
pub fn external_product_scratch_space(
|
pub fn external_product_scratch_space(
|
||||||
@@ -10,14 +10,14 @@ impl GLWECiphertext<Vec<u8>> {
|
|||||||
basek: usize,
|
basek: usize,
|
||||||
k_out: usize,
|
k_out: usize,
|
||||||
k_in: usize,
|
k_in: usize,
|
||||||
ggsw_k: usize,
|
k_ggsw: usize,
|
||||||
digits: usize,
|
digits: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let res_dft: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank);
|
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 in_size: usize = k_in.div_ceil(basek).div_ceil(digits);
|
||||||
let out_size: usize = div_ceil(k_out, basek);
|
let out_size: usize = k_out.div_ceil(basek);
|
||||||
let ggsw_size: usize = div_ceil(ggsw_k, basek);
|
let ggsw_size: usize = k_ggsw.div_ceil(basek);
|
||||||
let vmp: usize = module.bytes_of_vec_znx_dft(rank + 1, in_size)
|
let vmp: usize = module.bytes_of_vec_znx_dft(rank + 1, in_size)
|
||||||
+ module.vmp_apply_tmp_bytes(
|
+ module.vmp_apply_tmp_bytes(
|
||||||
out_size,
|
out_size,
|
||||||
@@ -35,11 +35,11 @@ impl GLWECiphertext<Vec<u8>> {
|
|||||||
module: &Module<FFT64>,
|
module: &Module<FFT64>,
|
||||||
basek: usize,
|
basek: usize,
|
||||||
k_out: usize,
|
k_out: usize,
|
||||||
ggsw_k: usize,
|
k_ggsw: usize,
|
||||||
digits: usize,
|
digits: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use backend::{
|
|||||||
VecZnxDftOps, ZnxZero,
|
VecZnxDftOps, ZnxZero,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{FourierGLWECiphertext, GLWECiphertext, GLWESwitchingKey, Infos, div_ceil};
|
use crate::{FourierGLWECiphertext, GLWECiphertext, GLWESwitchingKey, Infos};
|
||||||
|
|
||||||
impl GLWECiphertext<Vec<u8>> {
|
impl GLWECiphertext<Vec<u8>> {
|
||||||
pub fn keyswitch_scratch_space(
|
pub fn keyswitch_scratch_space(
|
||||||
@@ -17,9 +17,9 @@ impl GLWECiphertext<Vec<u8>> {
|
|||||||
rank_out: usize,
|
rank_out: usize,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let res_dft: usize = FourierGLWECiphertext::bytes_of(module, basek, k_out, rank_out + 1);
|
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 in_size: usize = k_in.div_ceil(basek).div_ceil(digits);
|
||||||
let out_size: usize = div_ceil(k_out, basek);
|
let out_size: usize = k_out.div_ceil(basek);
|
||||||
let ksk_size: usize = div_ceil(k_ksk, 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 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)
|
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);
|
+ module.bytes_of_vec_znx_dft(rank_in, in_size);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
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, div_ceil};
|
use crate::{GLWECiphertext, GLWECiphertextToMut, GLWECiphertextToRef, GLWEOps, Infos, SetMetaData};
|
||||||
|
|
||||||
pub struct GLWEPlaintext<C> {
|
pub struct GLWEPlaintext<C> {
|
||||||
pub data: VecZnx<C>,
|
pub data: VecZnx<C>,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use backend::{FFT64, FillUniform, Module, ScratchOwned, Stats, VecZnxOps};
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos, div_ceil,
|
FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos,
|
||||||
noise::log2_std_noise_gglwe_product,
|
noise::log2_std_noise_gglwe_product,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ fn apply_inplace() {
|
|||||||
let log_n: usize = 8;
|
let log_n: usize = 8;
|
||||||
let basek: usize = 12;
|
let basek: usize = 12;
|
||||||
let k_ct: usize = 60;
|
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..4).for_each(|rank| {
|
||||||
(1..digits + 1).for_each(|di| {
|
(1..digits + 1).for_each(|di| {
|
||||||
let k_ksk: usize = k_ct + basek * di;
|
let k_ksk: usize = k_ct + basek * di;
|
||||||
@@ -27,7 +27,7 @@ fn apply() {
|
|||||||
let log_n: usize = 8;
|
let log_n: usize = 8;
|
||||||
let basek: usize = 12;
|
let basek: usize = 12;
|
||||||
let k_in: usize = 60;
|
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..4).for_each(|rank| {
|
||||||
(1..digits + 1).for_each(|di| {
|
(1..digits + 1).for_each(|di| {
|
||||||
let k_ksk: usize = k_in + basek * 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 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 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);
|
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 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 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);
|
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_ct, rank);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use backend::{FFT64, FillUniform, Module, ScalarZnx, ScalarZnxAlloc, ScratchOwne
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
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]
|
#[test]
|
||||||
@@ -10,7 +10,7 @@ fn apply() {
|
|||||||
let log_n: usize = 8;
|
let log_n: usize = 8;
|
||||||
let basek: usize = 12;
|
let basek: usize = 12;
|
||||||
let k_in: usize = 45;
|
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..4).for_each(|rank| {
|
||||||
(1..digits + 1).for_each(|di| {
|
(1..digits + 1).for_each(|di| {
|
||||||
let k_ggsw: usize = k_in + basek * di;
|
let k_ggsw: usize = k_in + basek * di;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use backend::{FFT64, FillUniform, Module, ScratchOwned, Stats, VecZnxOps};
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos, div_ceil,
|
FourierGLWESecret, GLWECiphertext, GLWEPlaintext, GLWESecret, GLWESwitchingKey, Infos,
|
||||||
noise::log2_std_noise_gglwe_product,
|
noise::log2_std_noise_gglwe_product,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ fn apply() {
|
|||||||
let log_n: usize = 8;
|
let log_n: usize = 8;
|
||||||
let basek: usize = 12;
|
let basek: usize = 12;
|
||||||
let k_in: usize = 45;
|
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_in| {
|
||||||
(1..4).for_each(|rank_out| {
|
(1..4).for_each(|rank_out| {
|
||||||
(1..digits + 1).for_each(|di| {
|
(1..digits + 1).for_each(|di| {
|
||||||
@@ -32,7 +32,7 @@ fn apply_inplace() {
|
|||||||
let log_n: usize = 8;
|
let log_n: usize = 8;
|
||||||
let basek: usize = 12;
|
let basek: usize = 12;
|
||||||
let k_ct: usize = 45;
|
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..4).for_each(|rank| {
|
||||||
(1..digits + 1).for_each(|di| {
|
(1..digits + 1).for_each(|di| {
|
||||||
let k_ksk: usize = k_ct + basek * 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 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> =
|
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);
|
||||||
@@ -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) {
|
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 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_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);
|
let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&module, basek, k_ct, rank);
|
||||||
|
|||||||
@@ -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 std::collections::HashMap;
|
||||||
|
|
||||||
use backend::{Encoding, FFT64, Module, ScratchOwned, Stats};
|
use backend::{Encoding, FFT64, Module, ScratchOwned, Stats};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use backend::{FFT64, FillUniform, Module, ScratchOwned, Stats, VecZnxOps, ZnxVie
|
|||||||
use sampling::source::Source;
|
use sampling::source::Source;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos, div_ceil,
|
FourierGLWESecret, GLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos,
|
||||||
noise::var_noise_gglwe_product,
|
noise::var_noise_gglwe_product,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,18 +7,17 @@ pub mod ggsw;
|
|||||||
pub mod glwe;
|
pub mod glwe;
|
||||||
pub mod lwe;
|
pub mod lwe;
|
||||||
pub mod noise;
|
pub mod noise;
|
||||||
mod utils;
|
|
||||||
|
|
||||||
use backend::Backend;
|
use backend::Backend;
|
||||||
use backend::FFT64;
|
use backend::FFT64;
|
||||||
use backend::Module;
|
use backend::Module;
|
||||||
pub use elem::*;
|
pub use elem::{GetRow, Infos, SetMetaData, SetRow};
|
||||||
pub use fourier_glwe::{FourierGLWECiphertext, FourierGLWESecret};
|
pub use fourier_glwe::{FourierGLWECiphertext, FourierGLWESecret};
|
||||||
pub use gglwe::{GGLWECiphertext, GLWEAutomorphismKey, GLWESwitchingKey, GLWETensorKey};
|
pub use gglwe::{GGLWECiphertext, GLWEAutomorphismKey, GLWESwitchingKey, GLWETensorKey};
|
||||||
pub use ggsw::*;
|
pub use ggsw::GGSWCiphertext;
|
||||||
pub use glwe::{GLWECiphertext, GLWEOps, GLWEPacker, GLWEPlaintext, GLWEPublicKey, GLWESecret};
|
pub use glwe::{GLWECiphertext, GLWEOps, GLWEPacker, GLWEPlaintext, GLWEPublicKey, GLWESecret};
|
||||||
pub(crate) use glwe::{GLWECiphertextToMut, GLWECiphertextToRef};
|
pub(crate) use glwe::{GLWECiphertextToMut, GLWECiphertextToRef};
|
||||||
pub use lwe::*;
|
pub use lwe::{LWECiphertext, LWESecret};
|
||||||
|
|
||||||
pub use backend::Scratch;
|
pub use backend::Scratch;
|
||||||
pub use backend::ScratchOwned;
|
pub use backend::ScratchOwned;
|
||||||
@@ -174,7 +173,7 @@ impl ScratchCore<FFT64> for Scratch {
|
|||||||
k: usize,
|
k: usize,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
) -> (FourierGLWECiphertext<&mut [u8], FFT64>, &mut Self) {
|
) -> (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)
|
(FourierGLWECiphertext { data, basek, k }, scratch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
77
core/src/lwe/ciphertext.rs
Normal file
77
core/src/lwe/ciphertext.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
core/src/lwe/decryption.rs
Normal file
21
core/src/lwe/decryption.rs
Normal 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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
35
core/src/lwe/encryption.rs
Normal file
35
core/src/lwe/encryption.rs
Normal 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];
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
pub mod ciphertext;
|
||||||
pub mod secret;
|
pub mod secret;
|
||||||
|
pub mod encryption;
|
||||||
|
pub mod decryption;
|
||||||
|
pub mod plaintext;
|
||||||
|
|
||||||
|
pub use ciphertext::LWECiphertext;
|
||||||
pub use secret::LWESecret;
|
pub use secret::LWESecret;
|
||||||
|
pub use plaintext::LWEPlaintext;
|
||||||
|
|||||||
73
core/src/lwe/plaintext.rs
Normal file
73
core/src/lwe/plaintext.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user