mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 13:16:44 +01:00
Add cross-basek normalization (#90)
* added cross_basek_normalization * updated method signatures to take layouts * fixed cross-base normalization fix #91 fix #93
This commit is contained in:
committed by
GitHub
parent
4da790ea6a
commit
37e13b965c
@@ -4,34 +4,33 @@ use poulpy_hal::{
|
||||
ScratchAvailable, SvpApplyDftToDft, SvpPPolAllocBytes, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, TakeVecZnxDftSlice,
|
||||
TakeVecZnxSlice, VecZnxAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize,
|
||||
VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAdd, VecZnxDftAddInplace, VecZnxDftAllocBytes, VecZnxDftApply,
|
||||
VecZnxDftSubABInplace, VecZnxDftZero, VecZnxIdftApply, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpBytes,
|
||||
VecZnxDftSubInplace, VecZnxDftZero, VecZnxIdftApply, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpBytes,
|
||||
VecZnxMulXpMinusOneInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate,
|
||||
VecZnxSubABInplace, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes,
|
||||
VecZnxSubInplace, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes,
|
||||
},
|
||||
layouts::{Backend, DataMut, DataRef, Module, Scratch, SvpPPol, VecZnx, ZnxView, ZnxZero},
|
||||
};
|
||||
|
||||
use poulpy_core::{
|
||||
Distribution, GLWEOperations, TakeGLWECt,
|
||||
layouts::{GLWECiphertext, GLWECiphertextToMut, Infos, LWECiphertext, LWECiphertextToRef},
|
||||
layouts::{GGSWInfos, GLWECiphertext, GLWECiphertextToMut, GLWEInfos, LWECiphertext, LWECiphertextToRef, LWEInfos},
|
||||
};
|
||||
|
||||
use crate::tfhe::blind_rotation::{
|
||||
BlincRotationExecute, BlindRotationKeyPrepared, CGGI, LookUpTable, LookUpTableRotationDirection,
|
||||
BlincRotationExecute, BlindRotationKeyInfos, BlindRotationKeyPrepared, CGGI, LookUpTable, LookUpTableRotationDirection,
|
||||
};
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn cggi_blind_rotate_scratch_space<B: Backend>(
|
||||
pub fn cggi_blind_rotate_scratch_space<B: Backend, OUT, GGSW>(
|
||||
module: &Module<B>,
|
||||
block_size: usize,
|
||||
extension_factor: usize,
|
||||
basek: usize,
|
||||
k_res: usize,
|
||||
k_brk: usize,
|
||||
rows: usize,
|
||||
rank: usize,
|
||||
glwe_infos: &OUT,
|
||||
brk_infos: &GGSW,
|
||||
) -> usize
|
||||
where
|
||||
OUT: GLWEInfos,
|
||||
GGSW: GGSWInfos,
|
||||
Module<B>: VecZnxDftAllocBytes
|
||||
+ VmpApplyDftToDftTmpBytes
|
||||
+ VecZnxNormalizeTmpBytes
|
||||
@@ -39,10 +38,11 @@ where
|
||||
+ VecZnxIdftApplyTmpBytes
|
||||
+ VecZnxBigNormalizeTmpBytes,
|
||||
{
|
||||
let brk_size: usize = k_brk.div_ceil(basek);
|
||||
let brk_size: usize = brk_infos.size();
|
||||
|
||||
if block_size > 1 {
|
||||
let cols: usize = rank + 1;
|
||||
let cols: usize = (brk_infos.rank() + 1).into();
|
||||
let rows: usize = brk_infos.rows().into();
|
||||
let acc_dft: usize = module.vec_znx_dft_alloc_bytes(cols, rows) * extension_factor;
|
||||
let acc_big: usize = module.vec_znx_big_alloc_bytes(1, brk_size);
|
||||
let vmp_res: usize = module.vec_znx_dft_alloc_bytes(cols, brk_size) * extension_factor;
|
||||
@@ -50,7 +50,7 @@ where
|
||||
let acc_dft_add: usize = vmp_res;
|
||||
let vmp: usize = module.vmp_apply_dft_to_dft_tmp_bytes(brk_size, rows, rows, 2, 2, brk_size); // GGSW product: (1 x 2) x (2 x 2)
|
||||
let acc: usize = if extension_factor > 1 {
|
||||
VecZnx::alloc_bytes(module.n(), cols, k_res.div_ceil(basek)) * extension_factor
|
||||
VecZnx::alloc_bytes(module.n(), cols, glwe_infos.size()) * extension_factor
|
||||
} else {
|
||||
0
|
||||
};
|
||||
@@ -61,8 +61,8 @@ where
|
||||
+ vmp_xai
|
||||
+ (vmp | (acc_big + (module.vec_znx_big_normalize_tmp_bytes() | module.vec_znx_idft_apply_tmp_bytes())))
|
||||
} else {
|
||||
GLWECiphertext::bytes_of(module.n(), basek, k_res, rank)
|
||||
+ GLWECiphertext::external_product_scratch_space(module, basek, k_res, k_res, k_brk, 1, rank)
|
||||
GLWECiphertext::alloc_bytes(glwe_infos)
|
||||
+ GLWECiphertext::external_product_inplace_scratch_space(module, glwe_infos, brk_infos)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,11 +80,11 @@ where
|
||||
+ VecZnxDftApply<B>
|
||||
+ VecZnxDftZero<B>
|
||||
+ SvpApplyDftToDft<B>
|
||||
+ VecZnxDftSubABInplace<B>
|
||||
+ VecZnxDftSubInplace<B>
|
||||
+ VecZnxBigAddSmallInplace<B>
|
||||
+ VecZnxRotate
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxNormalize<B>
|
||||
+ VecZnxNormalizeInplace<B>
|
||||
+ VecZnxCopy
|
||||
@@ -142,11 +142,11 @@ fn execute_block_binary_extended<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
+ VecZnxDftApply<B>
|
||||
+ VecZnxDftZero<B>
|
||||
+ SvpApplyDftToDft<B>
|
||||
+ VecZnxDftSubABInplace<B>
|
||||
+ VecZnxDftSubInplace<B>
|
||||
+ VecZnxBigAddSmallInplace<B>
|
||||
+ VecZnxRotate
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxNormalize<B>
|
||||
+ VecZnxNormalizeInplace<B>
|
||||
+ VecZnxCopy
|
||||
@@ -155,11 +155,11 @@ fn execute_block_binary_extended<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
+ VmpApplyDftToDft<B>,
|
||||
Scratch<B>: TakeVecZnxDftSlice<B> + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnxSlice + ScratchAvailable + TakeVecZnx,
|
||||
{
|
||||
let n_glwe: usize = brk.n();
|
||||
let n_glwe: usize = brk.n_glwe().into();
|
||||
let extension_factor: usize = lut.extension_factor();
|
||||
let basek: usize = res.basek();
|
||||
let rows: usize = brk.rows();
|
||||
let cols: usize = res.rank() + 1;
|
||||
let base2k: usize = res.base2k().into();
|
||||
let rows: usize = brk.rows().into();
|
||||
let cols: usize = (res.rank() + 1).into();
|
||||
|
||||
let (mut acc, scratch_1) = scratch.take_vec_znx_slice(extension_factor, n_glwe, cols, res.size());
|
||||
let (mut acc_dft, scratch_2) = scratch_1.take_vec_znx_dft_slice(extension_factor, n_glwe, cols, rows);
|
||||
@@ -178,7 +178,7 @@ fn execute_block_binary_extended<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
panic!("invalid key: x_pow_a has not been initialized")
|
||||
}
|
||||
|
||||
let mut lwe_2n: Vec<i64> = vec![0i64; lwe.n() + 1]; // TODO: from scratch space
|
||||
let mut lwe_2n: Vec<i64> = vec![0i64; (lwe.n() + 1).as_usize()]; // TODO: from scratch space
|
||||
let lwe_ref: LWECiphertext<&[u8]> = lwe.to_ref();
|
||||
|
||||
let two_n: usize = 2 * n_glwe;
|
||||
@@ -233,7 +233,7 @@ fn execute_block_binary_extended<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
(0..cols).for_each(|i| {
|
||||
module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_hi], 0, &vmp_res[j], i);
|
||||
module.vec_znx_dft_add_inplace(&mut acc_add_dft[j], i, &vmp_xai, 0);
|
||||
module.vec_znx_dft_sub_ab_inplace(&mut acc_add_dft[j], i, &vmp_res[j], i);
|
||||
module.vec_znx_dft_sub_inplace(&mut acc_add_dft[j], i, &vmp_res[j], i);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -249,7 +249,7 @@ fn execute_block_binary_extended<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
(0..cols).for_each(|k| {
|
||||
module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_hi + 1], 0, &vmp_res[j], k);
|
||||
module.vec_znx_dft_add_inplace(&mut acc_add_dft[i], k, &vmp_xai, 0);
|
||||
module.vec_znx_dft_sub_ab_inplace(&mut acc_add_dft[i], k, &vmp_res[i], k);
|
||||
module.vec_znx_dft_sub_inplace(&mut acc_add_dft[i], k, &vmp_res[i], k);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -261,7 +261,7 @@ fn execute_block_binary_extended<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
(0..cols).for_each(|k| {
|
||||
module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_hi], 0, &vmp_res[j], k);
|
||||
module.vec_znx_dft_add_inplace(&mut acc_add_dft[i], k, &vmp_xai, 0);
|
||||
module.vec_znx_dft_sub_ab_inplace(&mut acc_add_dft[i], k, &vmp_res[i], k);
|
||||
module.vec_znx_dft_sub_inplace(&mut acc_add_dft[i], k, &vmp_res[i], k);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -275,14 +275,14 @@ fn execute_block_binary_extended<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
(0..cols).for_each(|i| {
|
||||
module.vec_znx_idft_apply(&mut acc_add_big, 0, &acc_add_dft[j], i, scratch7);
|
||||
module.vec_znx_big_add_small_inplace(&mut acc_add_big, 0, &acc[j], i);
|
||||
module.vec_znx_big_normalize(basek, &mut acc[j], i, &acc_add_big, 0, scratch7);
|
||||
module.vec_znx_big_normalize(base2k, &mut acc[j], i, base2k, &acc_add_big, 0, scratch7);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
(0..cols).for_each(|i| {
|
||||
module.vec_znx_copy(&mut res.data, i, &acc[0], i);
|
||||
module.vec_znx_copy(res.data_mut(), i, &acc[0], i);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -309,11 +309,11 @@ fn execute_block_binary<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
+ VecZnxDftApply<B>
|
||||
+ VecZnxDftZero<B>
|
||||
+ SvpApplyDftToDft<B>
|
||||
+ VecZnxDftSubABInplace<B>
|
||||
+ VecZnxDftSubInplace<B>
|
||||
+ VecZnxBigAddSmallInplace<B>
|
||||
+ VecZnxRotate
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxNormalize<B>
|
||||
+ VecZnxNormalizeInplace<B>
|
||||
+ VecZnxCopy
|
||||
@@ -322,15 +322,15 @@ fn execute_block_binary<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
+ VecZnxBigNormalize<B>,
|
||||
Scratch<B>: TakeVecZnxDftSlice<B> + TakeVecZnxDft<B> + TakeVecZnxBig<B> + TakeVecZnxSlice + ScratchAvailable + TakeVecZnx,
|
||||
{
|
||||
let n_glwe: usize = brk.n();
|
||||
let mut lwe_2n: Vec<i64> = vec![0i64; lwe.n() + 1]; // TODO: from scratch space
|
||||
let n_glwe: usize = brk.n_glwe().into();
|
||||
let mut lwe_2n: Vec<i64> = vec![0i64; (lwe.n() + 1).into()]; // TODO: from scratch space
|
||||
let mut out_mut: GLWECiphertext<&mut [u8]> = res.to_mut();
|
||||
let lwe_ref: LWECiphertext<&[u8]> = lwe.to_ref();
|
||||
let two_n: usize = n_glwe << 1;
|
||||
let basek: usize = brk.basek();
|
||||
let rows: usize = brk.rows();
|
||||
let base2k: usize = brk.base2k().into();
|
||||
let rows: usize = brk.rows().into();
|
||||
|
||||
let cols: usize = out_mut.rank() + 1;
|
||||
let cols: usize = (out_mut.rank() + 1).into();
|
||||
|
||||
mod_switch_2n(
|
||||
2 * lut.domain_size(),
|
||||
@@ -342,10 +342,10 @@ fn execute_block_binary<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
let a: &[i64] = &lwe_2n[1..];
|
||||
let b: i64 = lwe_2n[0];
|
||||
|
||||
out_mut.data.zero();
|
||||
out_mut.data_mut().zero();
|
||||
|
||||
// Initialize out to X^{b} * LUT(X)
|
||||
module.vec_znx_rotate(b, &mut out_mut.data, 0, &lut.data[0], 0);
|
||||
module.vec_znx_rotate(b, out_mut.data_mut(), 0, &lut.data[0], 0);
|
||||
|
||||
let block_size: usize = brk.block_size();
|
||||
|
||||
@@ -369,7 +369,7 @@ fn execute_block_binary<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
)
|
||||
.for_each(|(ai, ski)| {
|
||||
(0..cols).for_each(|j| {
|
||||
module.vec_znx_dft_apply(1, 0, &mut acc_dft, j, &out_mut.data, j);
|
||||
module.vec_znx_dft_apply(1, 0, &mut acc_dft, j, out_mut.data_mut(), j);
|
||||
});
|
||||
|
||||
module.vec_znx_dft_zero(&mut acc_add_dft);
|
||||
@@ -384,7 +384,7 @@ fn execute_block_binary<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
(0..cols).for_each(|i| {
|
||||
module.svp_apply_dft_to_dft(&mut vmp_xai, 0, &x_pow_a[ai_pos], 0, &vmp_res, i);
|
||||
module.vec_znx_dft_add_inplace(&mut acc_add_dft, i, &vmp_xai, 0);
|
||||
module.vec_znx_dft_sub_ab_inplace(&mut acc_add_dft, i, &vmp_res, i);
|
||||
module.vec_znx_dft_sub_inplace(&mut acc_add_dft, i, &vmp_res, i);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -393,8 +393,16 @@ fn execute_block_binary<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
|
||||
(0..cols).for_each(|i| {
|
||||
module.vec_znx_idft_apply(&mut acc_add_big, 0, &acc_add_dft, i, scratch_5);
|
||||
module.vec_znx_big_add_small_inplace(&mut acc_add_big, 0, &out_mut.data, i);
|
||||
module.vec_znx_big_normalize(basek, &mut out_mut.data, i, &acc_add_big, 0, scratch_5);
|
||||
module.vec_znx_big_add_small_inplace(&mut acc_add_big, 0, out_mut.data_mut(), i);
|
||||
module.vec_znx_big_normalize(
|
||||
base2k,
|
||||
out_mut.data_mut(),
|
||||
i,
|
||||
base2k,
|
||||
&acc_add_big,
|
||||
0,
|
||||
scratch_5,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -423,11 +431,11 @@ fn execute_standard<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
+ VecZnxDftApply<B>
|
||||
+ VecZnxDftZero<B>
|
||||
+ SvpApplyDftToDft<B>
|
||||
+ VecZnxDftSubABInplace<B>
|
||||
+ VecZnxDftSubInplace<B>
|
||||
+ VecZnxBigAddSmallInplace<B>
|
||||
+ VecZnxRotate
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxNormalize<B>
|
||||
+ VecZnxNormalizeInplace<B>
|
||||
+ VecZnxCopy
|
||||
@@ -450,10 +458,10 @@ fn execute_standard<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
);
|
||||
assert_eq!(
|
||||
lut.domain_size(),
|
||||
brk.n(),
|
||||
brk.n_glwe().as_usize(),
|
||||
"lut.n(): {} != brk.n(): {}",
|
||||
lut.domain_size(),
|
||||
brk.n()
|
||||
brk.n_glwe().as_usize()
|
||||
);
|
||||
assert_eq!(
|
||||
res.rank(),
|
||||
@@ -464,17 +472,16 @@ fn execute_standard<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
);
|
||||
assert_eq!(
|
||||
lwe.n(),
|
||||
brk.data.len(),
|
||||
brk.n_lwe(),
|
||||
"lwe.n(): {} != brk.data.len(): {}",
|
||||
lwe.n(),
|
||||
brk.data.len()
|
||||
brk.n_lwe()
|
||||
);
|
||||
}
|
||||
|
||||
let mut lwe_2n: Vec<i64> = vec![0i64; lwe.n() + 1]; // TODO: from scratch space
|
||||
let mut lwe_2n: Vec<i64> = vec![0i64; (lwe.n() + 1).into()]; // TODO: from scratch space
|
||||
let mut out_mut: GLWECiphertext<&mut [u8]> = res.to_mut();
|
||||
let lwe_ref: LWECiphertext<&[u8]> = lwe.to_ref();
|
||||
let basek: usize = brk.basek();
|
||||
|
||||
mod_switch_2n(
|
||||
2 * lut.domain_size(),
|
||||
@@ -486,13 +493,13 @@ fn execute_standard<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
let a: &[i64] = &lwe_2n[1..];
|
||||
let b: i64 = lwe_2n[0];
|
||||
|
||||
out_mut.data.zero();
|
||||
out_mut.data_mut().zero();
|
||||
|
||||
// Initialize out to X^{b} * LUT(X)
|
||||
module.vec_znx_rotate(b, &mut out_mut.data, 0, &lut.data[0], 0);
|
||||
module.vec_znx_rotate(b, out_mut.data_mut(), 0, &lut.data[0], 0);
|
||||
|
||||
// ACC + [sum DFT(X^ai -1) * (DFT(ACC) x BRKi)]
|
||||
let (mut acc_tmp, scratch_1) = scratch.take_glwe_ct(out_mut.n(), basek, out_mut.k(), out_mut.rank());
|
||||
let (mut acc_tmp, scratch_1) = scratch.take_glwe_ct(&out_mut);
|
||||
|
||||
// TODO: see if faster by skipping normalization in external product and keeping acc in big coeffs
|
||||
// TODO: first iteration can be optimized to be a gglwe product
|
||||
@@ -507,13 +514,13 @@ fn execute_standard<DataRes, DataIn, DataBrk, B: Backend>(
|
||||
out_mut.add_inplace(module, &acc_tmp);
|
||||
});
|
||||
|
||||
// We can normalize only at the end because we add normalized values in [-2^{basek-1}, 2^{basek-1}]
|
||||
// on top of each others, thus ~ 2^{63-basek} additions are supported before overflow.
|
||||
// We can normalize only at the end because we add normalized values in [-2^{base2k-1}, 2^{base2k-1}]
|
||||
// on top of each others, thus ~ 2^{63-base2k} additions are supported before overflow.
|
||||
out_mut.normalize_inplace(module, scratch_1);
|
||||
}
|
||||
|
||||
pub fn mod_switch_2n(n: usize, res: &mut [i64], lwe: &LWECiphertext<&[u8]>, rot_dir: LookUpTableRotationDirection) {
|
||||
let basek: usize = lwe.basek();
|
||||
let base2k: usize = lwe.base2k().into();
|
||||
|
||||
let log2n: usize = usize::BITS as usize - (n - 1).leading_zeros() as usize + 1;
|
||||
|
||||
@@ -526,23 +533,23 @@ pub fn mod_switch_2n(n: usize, res: &mut [i64], lwe: &LWECiphertext<&[u8]>, rot_
|
||||
LookUpTableRotationDirection::Right => {}
|
||||
}
|
||||
|
||||
if basek > log2n {
|
||||
let diff: usize = basek - (log2n - 1); // additional -1 because we map to [-N/2, N/2) instead of [0, N)
|
||||
if base2k > log2n {
|
||||
let diff: usize = base2k - (log2n - 1); // additional -1 because we map to [-N/2, N/2) instead of [0, N)
|
||||
res.iter_mut().for_each(|x| {
|
||||
*x = div_round_by_pow2(x, diff);
|
||||
})
|
||||
} else {
|
||||
let rem: usize = basek - (log2n % basek);
|
||||
let size: usize = log2n.div_ceil(basek);
|
||||
let rem: usize = base2k - (log2n % base2k);
|
||||
let size: usize = log2n.div_ceil(base2k);
|
||||
(1..size).for_each(|i| {
|
||||
if i == size - 1 && rem != basek {
|
||||
let k_rem: usize = basek - rem;
|
||||
if i == size - 1 && rem != base2k {
|
||||
let k_rem: usize = base2k - rem;
|
||||
izip!(lwe.data().at(0, i).iter(), res.iter_mut()).for_each(|(x, y)| {
|
||||
*y = (*y << k_rem) + (x >> rem);
|
||||
});
|
||||
} else {
|
||||
izip!(lwe.data().at(0, i).iter(), res.iter_mut()).for_each(|(x, y)| {
|
||||
*y = (*y << basek) + x;
|
||||
*y = (*y << base2k) + x;
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ use poulpy_hal::{
|
||||
api::{
|
||||
ScratchAvailable, SvpApplyDftToDftInplace, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal,
|
||||
VecZnxAddScalarInplace, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform,
|
||||
VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace,
|
||||
VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace,
|
||||
VmpPMatAlloc, VmpPrepare,
|
||||
},
|
||||
layouts::{Backend, DataMut, DataRef, Module, ScalarZnx, ScalarZnxToRef, Scratch, ZnxView, ZnxViewMut},
|
||||
@@ -14,21 +14,27 @@ use std::marker::PhantomData;
|
||||
use poulpy_core::{
|
||||
Distribution,
|
||||
layouts::{
|
||||
GGSWCiphertext, LWESecret,
|
||||
GGSWCiphertext, GGSWInfos, LWESecret,
|
||||
compressed::GGSWCiphertextCompressed,
|
||||
prepared::{GGSWCiphertextPrepared, GLWESecretPrepared},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::tfhe::blind_rotation::{
|
||||
BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyCompressed, BlindRotationKeyEncryptSk, BlindRotationKeyPrepared,
|
||||
BlindRotationKeyPreparedAlloc, CGGI,
|
||||
BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyCompressed, BlindRotationKeyEncryptSk, BlindRotationKeyInfos,
|
||||
BlindRotationKeyPrepared, BlindRotationKeyPreparedAlloc, CGGI,
|
||||
};
|
||||
|
||||
impl BlindRotationKeyAlloc for BlindRotationKey<Vec<u8>, CGGI> {
|
||||
fn alloc(n_gglwe: usize, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self {
|
||||
let mut data: Vec<GGSWCiphertext<Vec<u8>>> = Vec::with_capacity(n_lwe);
|
||||
(0..n_lwe).for_each(|_| data.push(GGSWCiphertext::alloc(n_gglwe, basek, k, rows, 1, rank)));
|
||||
fn alloc<A>(infos: &A) -> Self
|
||||
where
|
||||
A: BlindRotationKeyInfos,
|
||||
{
|
||||
let mut data: Vec<GGSWCiphertext<Vec<u8>>> = Vec::with_capacity(infos.n_lwe().into());
|
||||
for _ in 0..infos.n_lwe().as_usize() {
|
||||
data.push(GGSWCiphertext::alloc(infos));
|
||||
}
|
||||
|
||||
Self {
|
||||
keys: data,
|
||||
dist: Distribution::NONE,
|
||||
@@ -38,11 +44,12 @@ impl BlindRotationKeyAlloc for BlindRotationKey<Vec<u8>, CGGI> {
|
||||
}
|
||||
|
||||
impl BlindRotationKey<Vec<u8>, CGGI> {
|
||||
pub fn generate_from_sk_scratch_space<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize
|
||||
pub fn generate_from_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize
|
||||
where
|
||||
A: GGSWInfos,
|
||||
Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes,
|
||||
{
|
||||
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k, rank)
|
||||
GGSWCiphertext::encrypt_sk_scratch_space(module, infos)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +63,7 @@ where
|
||||
+ VecZnxIdftApplyConsume<B>
|
||||
+ VecZnxNormalizeTmpBytes
|
||||
+ VecZnxFillUniform
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxNormalizeInplace<B>
|
||||
+ VecZnxAddNormal
|
||||
@@ -78,9 +85,11 @@ where
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
assert_eq!(self.keys.len(), sk_lwe.n());
|
||||
assert!(sk_glwe.n() <= module.n());
|
||||
assert_eq!(sk_glwe.rank(), self.keys[0].rank());
|
||||
use poulpy_core::layouts::{GLWEInfos, LWEInfos};
|
||||
|
||||
assert_eq!(self.keys.len() as u32, sk_lwe.n());
|
||||
assert!(sk_glwe.n() <= module.n() as u32);
|
||||
assert_eq!(sk_glwe.rank(), self.rank());
|
||||
match sk_lwe.dist() {
|
||||
Distribution::BinaryBlock(_)
|
||||
| Distribution::BinaryFixed(_)
|
||||
@@ -94,7 +103,7 @@ where
|
||||
|
||||
self.dist = sk_lwe.dist();
|
||||
|
||||
let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n(), 1);
|
||||
let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n().into(), 1);
|
||||
let sk_ref: ScalarZnx<&[u8]> = sk_lwe.data().to_ref();
|
||||
|
||||
self.keys.iter_mut().enumerate().for_each(|(i, ggsw)| {
|
||||
@@ -108,13 +117,12 @@ impl<B: Backend> BlindRotationKeyPreparedAlloc<B> for BlindRotationKeyPrepared<V
|
||||
where
|
||||
Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>,
|
||||
{
|
||||
fn alloc(module: &Module<B>, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self {
|
||||
let mut data: Vec<GGSWCiphertextPrepared<Vec<u8>, B>> = Vec::with_capacity(n_lwe);
|
||||
(0..n_lwe).for_each(|_| {
|
||||
data.push(GGSWCiphertextPrepared::alloc(
|
||||
module, basek, k, rows, 1, rank,
|
||||
))
|
||||
});
|
||||
fn alloc<A>(module: &Module<B>, infos: &A) -> Self
|
||||
where
|
||||
A: BlindRotationKeyInfos,
|
||||
{
|
||||
let mut data: Vec<GGSWCiphertextPrepared<Vec<u8>, B>> = Vec::with_capacity(infos.n_lwe().into());
|
||||
(0..infos.n_lwe().as_usize()).for_each(|_| data.push(GGSWCiphertextPrepared::alloc(module, infos)));
|
||||
Self {
|
||||
data,
|
||||
dist: Distribution::NONE,
|
||||
@@ -125,13 +133,12 @@ where
|
||||
}
|
||||
|
||||
impl BlindRotationKeyCompressed<Vec<u8>, CGGI> {
|
||||
pub fn alloc(n_gglwe: usize, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self {
|
||||
let mut data: Vec<GGSWCiphertextCompressed<Vec<u8>>> = Vec::with_capacity(n_lwe);
|
||||
(0..n_lwe).for_each(|_| {
|
||||
data.push(GGSWCiphertextCompressed::alloc(
|
||||
n_gglwe, basek, k, rows, 1, rank,
|
||||
))
|
||||
});
|
||||
pub fn alloc<A>(infos: &A) -> Self
|
||||
where
|
||||
A: BlindRotationKeyInfos,
|
||||
{
|
||||
let mut data: Vec<GGSWCiphertextCompressed<Vec<u8>>> = Vec::with_capacity(infos.n_lwe().into());
|
||||
(0..infos.n_lwe().as_usize()).for_each(|_| data.push(GGSWCiphertextCompressed::alloc(infos)));
|
||||
Self {
|
||||
keys: data,
|
||||
dist: Distribution::NONE,
|
||||
@@ -139,11 +146,12 @@ impl BlindRotationKeyCompressed<Vec<u8>, CGGI> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_from_sk_scratch_space<B: Backend>(module: &Module<B>, basek: usize, k: usize, rank: usize) -> usize
|
||||
pub fn generate_from_sk_scratch_space<B: Backend, A>(module: &Module<B>, infos: &A) -> usize
|
||||
where
|
||||
A: GGSWInfos,
|
||||
Module<B>: VecZnxNormalizeTmpBytes + VecZnxDftAllocBytes,
|
||||
{
|
||||
GGSWCiphertextCompressed::encrypt_sk_scratch_space(module, basek, k, rank)
|
||||
GGSWCiphertextCompressed::encrypt_sk_scratch_space(module, infos)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +176,7 @@ impl<D: DataMut> BlindRotationKeyCompressed<D, CGGI> {
|
||||
+ VecZnxIdftApplyConsume<B>
|
||||
+ VecZnxNormalizeTmpBytes
|
||||
+ VecZnxFillUniform
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxNormalizeInplace<B>
|
||||
+ VecZnxAddNormal
|
||||
@@ -178,9 +186,11 @@ impl<D: DataMut> BlindRotationKeyCompressed<D, CGGI> {
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
assert_eq!(self.keys.len(), sk_lwe.n());
|
||||
assert!(sk_glwe.n() <= module.n());
|
||||
assert_eq!(sk_glwe.rank(), self.keys[0].rank());
|
||||
use poulpy_core::layouts::{GLWEInfos, LWEInfos};
|
||||
|
||||
assert_eq!(self.n_lwe(), sk_lwe.n());
|
||||
assert!(sk_glwe.n() <= module.n() as u32);
|
||||
assert_eq!(sk_glwe.rank(), self.rank());
|
||||
match sk_lwe.dist() {
|
||||
Distribution::BinaryBlock(_)
|
||||
| Distribution::BinaryFixed(_)
|
||||
@@ -194,7 +204,7 @@ impl<D: DataMut> BlindRotationKeyCompressed<D, CGGI> {
|
||||
|
||||
self.dist = sk_lwe.dist();
|
||||
|
||||
let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n(), 1);
|
||||
let mut pt: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(sk_glwe.n().into(), 1);
|
||||
let sk_ref: ScalarZnx<&[u8]> = sk_lwe.data().to_ref();
|
||||
|
||||
let mut source_xa: Source = Source::new(seed_xa);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use poulpy_hal::{
|
||||
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, Reset, Scratch, WriterTo},
|
||||
layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, Scratch, WriterTo},
|
||||
source::Source,
|
||||
};
|
||||
|
||||
@@ -7,15 +7,78 @@ use std::{fmt, marker::PhantomData};
|
||||
|
||||
use poulpy_core::{
|
||||
Distribution,
|
||||
layouts::{GGSWCiphertext, Infos, LWESecret, prepared::GLWESecretPrepared},
|
||||
layouts::{
|
||||
Base2K, Degree, Digits, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, LWESecret, Rank, Rows, TorusPrecision,
|
||||
prepared::GLWESecretPrepared,
|
||||
},
|
||||
};
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
|
||||
use crate::tfhe::blind_rotation::BlindRotationAlgo;
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
pub struct BlindRotationKeyLayout {
|
||||
pub n_glwe: Degree,
|
||||
pub n_lwe: Degree,
|
||||
pub base2k: Base2K,
|
||||
pub k: TorusPrecision,
|
||||
pub rows: Rows,
|
||||
pub rank: Rank,
|
||||
}
|
||||
|
||||
impl BlindRotationKeyInfos for BlindRotationKeyLayout {
|
||||
fn n_glwe(&self) -> Degree {
|
||||
self.n_glwe
|
||||
}
|
||||
|
||||
fn n_lwe(&self) -> Degree {
|
||||
self.n_lwe
|
||||
}
|
||||
}
|
||||
|
||||
impl GGSWInfos for BlindRotationKeyLayout {
|
||||
fn digits(&self) -> Digits {
|
||||
Digits(1)
|
||||
}
|
||||
|
||||
fn rows(&self) -> Rows {
|
||||
self.rows
|
||||
}
|
||||
}
|
||||
|
||||
impl GLWEInfos for BlindRotationKeyLayout {
|
||||
fn rank(&self) -> Rank {
|
||||
self.rank
|
||||
}
|
||||
}
|
||||
|
||||
impl LWEInfos for BlindRotationKeyLayout {
|
||||
fn base2k(&self) -> Base2K {
|
||||
self.base2k
|
||||
}
|
||||
|
||||
fn k(&self) -> TorusPrecision {
|
||||
self.k
|
||||
}
|
||||
|
||||
fn n(&self) -> Degree {
|
||||
self.n_glwe
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BlindRotationKeyInfos
|
||||
where
|
||||
Self: GGSWInfos,
|
||||
{
|
||||
fn n_glwe(&self) -> Degree;
|
||||
fn n_lwe(&self) -> Degree;
|
||||
}
|
||||
|
||||
pub trait BlindRotationKeyAlloc {
|
||||
fn alloc(n_gglwe: usize, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self;
|
||||
fn alloc<A>(infos: &A) -> Self
|
||||
where
|
||||
A: BlindRotationKeyInfos;
|
||||
}
|
||||
|
||||
pub trait BlindRotationKeyEncryptSk<B: Backend> {
|
||||
@@ -42,7 +105,7 @@ pub struct BlindRotationKey<D: Data, BRT: BlindRotationAlgo> {
|
||||
|
||||
impl<D: DataRef, BRT: BlindRotationAlgo> fmt::Debug for BlindRotationKey<D, BRT> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
write!(f, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,19 +129,12 @@ impl<D: Data, BRT: BlindRotationAlgo> Eq for BlindRotationKey<D, BRT> {}
|
||||
impl<D: DataRef, BRT: BlindRotationAlgo> fmt::Display for BlindRotationKey<D, BRT> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for (i, key) in self.keys.iter().enumerate() {
|
||||
write!(f, "key[{}]: {}", i, key)?;
|
||||
write!(f, "key[{i}]: {key}")?;
|
||||
}
|
||||
writeln!(f, "{:?}", self.dist)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataMut, BRT: BlindRotationAlgo> Reset for BlindRotationKey<D, BRT> {
|
||||
fn reset(&mut self) {
|
||||
self.keys.iter_mut().for_each(|key| key.reset());
|
||||
self.dist = Distribution::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataMut, BRT: BlindRotationAlgo> FillUniform for BlindRotationKey<D, BRT> {
|
||||
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
|
||||
self.keys
|
||||
@@ -121,41 +177,55 @@ impl<D: DataRef, BRT: BlindRotationAlgo> WriterTo for BlindRotationKey<D, BRT> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef, BRT: BlindRotationAlgo> BlindRotationKeyInfos for BlindRotationKey<D, BRT> {
|
||||
fn n_glwe(&self) -> Degree {
|
||||
self.n()
|
||||
}
|
||||
|
||||
fn n_lwe(&self) -> Degree {
|
||||
Degree(self.keys.len() as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef, BRT: BlindRotationAlgo> BlindRotationKey<D, BRT> {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn n(&self) -> usize {
|
||||
self.keys[0].n()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rows(&self) -> usize {
|
||||
self.keys[0].rows()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn k(&self) -> usize {
|
||||
self.keys[0].k()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
self.keys[0].size()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rank(&self) -> usize {
|
||||
self.keys[0].rank()
|
||||
}
|
||||
|
||||
pub(crate) fn basek(&self) -> usize {
|
||||
self.keys[0].basek()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn block_size(&self) -> usize {
|
||||
fn block_size(&self) -> usize {
|
||||
match self.dist {
|
||||
Distribution::BinaryBlock(value) => value,
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef, BRT: BlindRotationAlgo> LWEInfos for BlindRotationKey<D, BRT> {
|
||||
fn base2k(&self) -> Base2K {
|
||||
self.keys[0].base2k()
|
||||
}
|
||||
|
||||
fn k(&self) -> TorusPrecision {
|
||||
self.keys[0].k()
|
||||
}
|
||||
|
||||
fn n(&self) -> Degree {
|
||||
self.keys[0].n()
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
self.keys[0].size()
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef, BRT: BlindRotationAlgo> GLWEInfos for BlindRotationKey<D, BRT> {
|
||||
fn rank(&self) -> Rank {
|
||||
self.keys[0].rank()
|
||||
}
|
||||
}
|
||||
impl<D: DataRef, BRT: BlindRotationAlgo> GGSWInfos for BlindRotationKey<D, BRT> {
|
||||
fn digits(&self) -> poulpy_core::layouts::Digits {
|
||||
Digits(1)
|
||||
}
|
||||
|
||||
fn rows(&self) -> Rows {
|
||||
self.keys[0].rows()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use poulpy_hal::{
|
||||
layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, Reset, WriterTo},
|
||||
layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
|
||||
source::Source,
|
||||
};
|
||||
|
||||
@@ -8,10 +8,10 @@ use std::{fmt, marker::PhantomData};
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use poulpy_core::{
|
||||
Distribution,
|
||||
layouts::{Infos, compressed::GGSWCiphertextCompressed},
|
||||
layouts::{Base2K, Degree, Digits, GGSWInfos, GLWEInfos, LWEInfos, TorusPrecision, compressed::GGSWCiphertextCompressed},
|
||||
};
|
||||
|
||||
use crate::tfhe::blind_rotation::BlindRotationAlgo;
|
||||
use crate::tfhe::blind_rotation::{BlindRotationAlgo, BlindRotationKeyInfos};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BlindRotationKeyCompressed<D: Data, BRT: BlindRotationAlgo> {
|
||||
@@ -22,7 +22,7 @@ pub struct BlindRotationKeyCompressed<D: Data, BRT: BlindRotationAlgo> {
|
||||
|
||||
impl<D: DataRef, BRT: BlindRotationAlgo> fmt::Debug for BlindRotationKeyCompressed<D, BRT> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
write!(f, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,19 +45,12 @@ impl<D: Data, BRT: BlindRotationAlgo> Eq for BlindRotationKeyCompressed<D, BRT>
|
||||
impl<D: DataRef, BRT: BlindRotationAlgo> fmt::Display for BlindRotationKeyCompressed<D, BRT> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for (i, key) in self.keys.iter().enumerate() {
|
||||
write!(f, "key[{}]: {}", i, key)?;
|
||||
write!(f, "key[{i}]: {key}")?;
|
||||
}
|
||||
writeln!(f, "{:?}", self.dist)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataMut, BRT: BlindRotationAlgo> Reset for BlindRotationKeyCompressed<D, BRT> {
|
||||
fn reset(&mut self) {
|
||||
self.keys.iter_mut().for_each(|key| key.reset());
|
||||
self.dist = Distribution::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataMut, BRT: BlindRotationAlgo> FillUniform for BlindRotationKeyCompressed<D, BRT> {
|
||||
fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
|
||||
self.keys
|
||||
@@ -100,37 +93,51 @@ impl<D: DataRef, BRT: BlindRotationAlgo> WriterTo for BlindRotationKeyCompressed
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef, BRA: BlindRotationAlgo> BlindRotationKeyCompressed<D, BRA> {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn n(&self) -> usize {
|
||||
impl<D: DataRef, BRA: BlindRotationAlgo> BlindRotationKeyInfos for BlindRotationKeyCompressed<D, BRA> {
|
||||
fn n_glwe(&self) -> Degree {
|
||||
self.n()
|
||||
}
|
||||
|
||||
fn n_lwe(&self) -> Degree {
|
||||
Degree(self.keys.len() as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef, BRA: BlindRotationAlgo> LWEInfos for BlindRotationKeyCompressed<D, BRA> {
|
||||
fn n(&self) -> Degree {
|
||||
self.keys[0].n()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rows(&self) -> usize {
|
||||
self.keys[0].rows()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn k(&self) -> usize {
|
||||
self.keys[0].k()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
fn size(&self) -> usize {
|
||||
self.keys[0].size()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rank(&self) -> usize {
|
||||
fn k(&self) -> TorusPrecision {
|
||||
self.keys[0].k()
|
||||
}
|
||||
|
||||
fn base2k(&self) -> Base2K {
|
||||
self.keys[0].base2k()
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef, BRA: BlindRotationAlgo> GLWEInfos for BlindRotationKeyCompressed<D, BRA> {
|
||||
fn rank(&self) -> poulpy_core::layouts::Rank {
|
||||
self.keys[0].rank()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn basek(&self) -> usize {
|
||||
self.keys[0].basek()
|
||||
impl<D: DataRef, BRA: BlindRotationAlgo> GGSWInfos for BlindRotationKeyCompressed<D, BRA> {
|
||||
fn rows(&self) -> poulpy_core::layouts::Rows {
|
||||
self.keys[0].rows()
|
||||
}
|
||||
|
||||
fn digits(&self) -> poulpy_core::layouts::Digits {
|
||||
Digits(1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef, BRA: BlindRotationAlgo> BlindRotationKeyCompressed<D, BRA> {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn block_size(&self) -> usize {
|
||||
match self.dist {
|
||||
|
||||
@@ -8,15 +8,17 @@ use std::marker::PhantomData;
|
||||
use poulpy_core::{
|
||||
Distribution,
|
||||
layouts::{
|
||||
Infos,
|
||||
Base2K, Degree, Digits, GGSWInfos, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision,
|
||||
prepared::{GGSWCiphertextPrepared, Prepare, PrepareAlloc},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::tfhe::blind_rotation::{BlindRotationAlgo, BlindRotationKey, utils::set_xai_plus_y};
|
||||
use crate::tfhe::blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyInfos, utils::set_xai_plus_y};
|
||||
|
||||
pub trait BlindRotationKeyPreparedAlloc<B: Backend> {
|
||||
fn alloc(module: &Module<B>, n_lwe: usize, basek: usize, k: usize, rows: usize, rank: usize) -> Self;
|
||||
fn alloc<A>(module: &Module<B>, infos: &A) -> Self
|
||||
where
|
||||
A: BlindRotationKeyInfos;
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
@@ -27,37 +29,51 @@ pub struct BlindRotationKeyPrepared<D: Data, BRT: BlindRotationAlgo, B: Backend>
|
||||
pub(crate) _phantom: PhantomData<BRT>,
|
||||
}
|
||||
|
||||
impl<D: Data, BRT: BlindRotationAlgo, B: Backend> BlindRotationKeyPrepared<D, BRT, B> {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn n(&self) -> usize {
|
||||
self.data[0].n()
|
||||
impl<D: Data, BRT: BlindRotationAlgo, B: Backend> BlindRotationKeyInfos for BlindRotationKeyPrepared<D, BRT, B> {
|
||||
fn n_glwe(&self) -> Degree {
|
||||
self.n()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rows(&self) -> usize {
|
||||
self.data[0].rows()
|
||||
fn n_lwe(&self) -> Degree {
|
||||
Degree(self.data.len() as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Data, BRT: BlindRotationAlgo, B: Backend> LWEInfos for BlindRotationKeyPrepared<D, BRT, B> {
|
||||
fn base2k(&self) -> Base2K {
|
||||
self.data[0].base2k()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn k(&self) -> usize {
|
||||
fn k(&self) -> TorusPrecision {
|
||||
self.data[0].k()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
fn n(&self) -> Degree {
|
||||
self.data[0].n()
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
self.data[0].size()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn rank(&self) -> usize {
|
||||
impl<D: Data, BRT: BlindRotationAlgo, B: Backend> GLWEInfos for BlindRotationKeyPrepared<D, BRT, B> {
|
||||
fn rank(&self) -> Rank {
|
||||
self.data[0].rank()
|
||||
}
|
||||
|
||||
pub(crate) fn basek(&self) -> usize {
|
||||
self.data[0].basek()
|
||||
}
|
||||
impl<D: Data, BRT: BlindRotationAlgo, B: Backend> GGSWInfos for BlindRotationKeyPrepared<D, BRT, B> {
|
||||
fn digits(&self) -> poulpy_core::layouts::Digits {
|
||||
Digits(1)
|
||||
}
|
||||
|
||||
pub(crate) fn block_size(&self) -> usize {
|
||||
fn rows(&self) -> Rows {
|
||||
self.data[0].rows()
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Data, BRT: BlindRotationAlgo, B: Backend> BlindRotationKeyPrepared<D, BRT, B> {
|
||||
pub fn block_size(&self) -> usize {
|
||||
match self.dist {
|
||||
Distribution::BinaryBlock(value) => value,
|
||||
_ => 1,
|
||||
@@ -72,14 +88,7 @@ where
|
||||
BlindRotationKeyPrepared<Vec<u8>, BRA, B>: Prepare<B, BlindRotationKey<D, BRA>>,
|
||||
{
|
||||
fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> BlindRotationKeyPrepared<Vec<u8>, BRA, B> {
|
||||
let mut brk: BlindRotationKeyPrepared<Vec<u8>, BRA, B> = BlindRotationKeyPrepared::alloc(
|
||||
module,
|
||||
self.keys.len(),
|
||||
self.basek(),
|
||||
self.k(),
|
||||
self.rows(),
|
||||
self.rank(),
|
||||
);
|
||||
let mut brk: BlindRotationKeyPrepared<Vec<u8>, BRA, B> = BlindRotationKeyPrepared::alloc(module, self);
|
||||
brk.prepare(module, self, scratch);
|
||||
brk
|
||||
}
|
||||
@@ -96,7 +105,7 @@ where
|
||||
assert_eq!(self.data.len(), other.keys.len());
|
||||
}
|
||||
|
||||
let n: usize = other.n();
|
||||
let n: usize = other.n().as_usize();
|
||||
|
||||
self.data
|
||||
.iter_mut()
|
||||
|
||||
@@ -15,29 +15,28 @@ pub enum LookUpTableRotationDirection {
|
||||
pub struct LookUpTable {
|
||||
pub(crate) data: Vec<VecZnx<Vec<u8>>>,
|
||||
pub(crate) rot_dir: LookUpTableRotationDirection,
|
||||
pub(crate) basek: usize,
|
||||
pub(crate) base2k: usize,
|
||||
pub(crate) k: usize,
|
||||
pub(crate) drift: usize,
|
||||
}
|
||||
|
||||
impl LookUpTable {
|
||||
pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, extension_factor: usize) -> Self {
|
||||
pub fn alloc<B: Backend>(module: &Module<B>, base2k: usize, k: usize, extension_factor: usize) -> Self {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
assert!(
|
||||
extension_factor & (extension_factor - 1) == 0,
|
||||
"extension_factor must be a power of two but is: {}",
|
||||
extension_factor
|
||||
"extension_factor must be a power of two but is: {extension_factor}"
|
||||
);
|
||||
}
|
||||
let size: usize = k.div_ceil(basek);
|
||||
let size: usize = k.div_ceil(base2k);
|
||||
let mut data: Vec<VecZnx<Vec<u8>>> = Vec::with_capacity(extension_factor);
|
||||
(0..extension_factor).for_each(|_| {
|
||||
data.push(VecZnx::alloc(module.n(), 1, size));
|
||||
});
|
||||
Self {
|
||||
data,
|
||||
basek,
|
||||
base2k,
|
||||
k,
|
||||
drift: 0,
|
||||
rot_dir: LookUpTableRotationDirection::Left,
|
||||
@@ -80,27 +79,27 @@ impl LookUpTable {
|
||||
{
|
||||
assert!(f.len() <= module.n());
|
||||
|
||||
let basek: usize = self.basek;
|
||||
let base2k: usize = self.base2k;
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(module.vec_znx_normalize_tmp_bytes());
|
||||
|
||||
// Get the number minimum limb to store the message modulus
|
||||
let limbs: usize = k.div_ceil(basek);
|
||||
let limbs: usize = k.div_ceil(base2k);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
assert!(f.len() <= module.n());
|
||||
assert!(
|
||||
(max_bit_size(f) + (k % basek) as u32) < i64::BITS,
|
||||
"overflow: max(|f|) << (k%basek) > i64::BITS"
|
||||
(max_bit_size(f) + (k % base2k) as u32) < i64::BITS,
|
||||
"overflow: max(|f|) << (k%base2k) > i64::BITS"
|
||||
);
|
||||
assert!(limbs <= self.data[0].size());
|
||||
}
|
||||
|
||||
// Scaling factor
|
||||
let mut scale = 1;
|
||||
if !k.is_multiple_of(basek) {
|
||||
scale <<= basek - (k % basek);
|
||||
if !k.is_multiple_of(base2k) {
|
||||
scale <<= base2k - (k % base2k);
|
||||
}
|
||||
|
||||
// #elements in lookup table
|
||||
@@ -109,7 +108,7 @@ impl LookUpTable {
|
||||
// If LUT size > TakeScalarZnx
|
||||
let domain_size: usize = self.domain_size();
|
||||
|
||||
let size: usize = self.k.div_ceil(self.basek);
|
||||
let size: usize = self.k.div_ceil(self.base2k);
|
||||
|
||||
// Equivalent to AUTO([f(0), -f(n-1), -f(n-2), ..., -f(1)], -1)
|
||||
let mut lut_full: VecZnx<Vec<u8>> = VecZnx::alloc(domain_size, 1, size);
|
||||
@@ -140,7 +139,7 @@ impl LookUpTable {
|
||||
}
|
||||
|
||||
self.data.iter_mut().for_each(|a| {
|
||||
module.vec_znx_normalize_inplace(self.basek, a, 0, scratch.borrow());
|
||||
module.vec_znx_normalize_inplace(self.base2k, a, 0, scratch.borrow());
|
||||
});
|
||||
|
||||
self.rotate(module, -(drift as i64));
|
||||
|
||||
@@ -3,9 +3,9 @@ use poulpy_hal::{
|
||||
ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes,
|
||||
SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace,
|
||||
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAdd, VecZnxDftAddInplace,
|
||||
VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftSubABInplace, VecZnxDftZero, VecZnxFillUniform, VecZnxIdftApply,
|
||||
VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftSubInplace, VecZnxDftZero, VecZnxFillUniform, VecZnxIdftApply,
|
||||
VecZnxIdftApplyConsume, VecZnxIdftApplyTmpBytes, VecZnxMulXpMinusOneInplace, VecZnxNormalize, VecZnxNormalizeInplace,
|
||||
VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, VecZnxSub, VecZnxSubABInplace,
|
||||
VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, VecZnxSub, VecZnxSubInplace,
|
||||
VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, ZnAddNormal,
|
||||
ZnFillUniform, ZnNormalizeInplace,
|
||||
},
|
||||
@@ -18,12 +18,13 @@ use poulpy_hal::{
|
||||
};
|
||||
|
||||
use crate::tfhe::blind_rotation::{
|
||||
BlincRotationExecute, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, BlindRotationKeyPrepared, CGGI,
|
||||
LookUpTable, cggi_blind_rotate_scratch_space, mod_switch_2n,
|
||||
BlincRotationExecute, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, BlindRotationKeyLayout,
|
||||
BlindRotationKeyPrepared, CGGI, LookUpTable, cggi_blind_rotate_scratch_space, mod_switch_2n,
|
||||
};
|
||||
|
||||
use poulpy_core::layouts::{
|
||||
GLWECiphertext, GLWEPlaintext, GLWESecret, Infos, LWECiphertext, LWECiphertextToRef, LWEPlaintext, LWESecret,
|
||||
GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, LWECiphertext, LWECiphertextLayout, LWECiphertextToRef,
|
||||
LWEInfos, LWEPlaintext, LWESecret,
|
||||
prepared::{GLWESecretPrepared, PrepareAlloc},
|
||||
};
|
||||
|
||||
@@ -41,11 +42,11 @@ where
|
||||
+ VecZnxDftApply<B>
|
||||
+ VecZnxDftZero<B>
|
||||
+ SvpApplyDftToDft<B>
|
||||
+ VecZnxDftSubABInplace<B>
|
||||
+ VecZnxDftSubInplace<B>
|
||||
+ VecZnxBigAddSmallInplace<B>
|
||||
+ VecZnxRotate
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxNormalize<B>
|
||||
+ VecZnxNormalizeInplace<B>
|
||||
+ VecZnxCopy
|
||||
@@ -83,16 +84,16 @@ where
|
||||
+ TakeVecZnxImpl<B>
|
||||
+ TakeVecZnxSliceImpl<B>,
|
||||
{
|
||||
let n: usize = module.n();
|
||||
let basek: usize = 19;
|
||||
let n_glwe: usize = module.n();
|
||||
let base2k: usize = 19;
|
||||
let k_lwe: usize = 24;
|
||||
let k_brk: usize = 3 * basek;
|
||||
let k_brk: usize = 3 * base2k;
|
||||
let rows_brk: usize = 2; // Ensures first limb is noise-free.
|
||||
let k_lut: usize = basek;
|
||||
let k_res: usize = 2 * basek;
|
||||
let k_lut: usize = base2k;
|
||||
let k_res: usize = 2 * base2k;
|
||||
let rank: usize = 1;
|
||||
|
||||
let log_message_modulus = 4;
|
||||
let log_message_modulus: usize = 4;
|
||||
|
||||
let message_modulus: usize = 1 << log_message_modulus;
|
||||
|
||||
@@ -100,30 +101,48 @@ where
|
||||
let mut source_xe: Source = Source::new([2u8; 32]);
|
||||
let mut source_xa: Source = Source::new([1u8; 32]);
|
||||
|
||||
let brk_infos: BlindRotationKeyLayout = BlindRotationKeyLayout {
|
||||
n_glwe: n_glwe.into(),
|
||||
n_lwe: n_lwe.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k_brk.into(),
|
||||
rows: rows_brk.into(),
|
||||
rank: rank.into(),
|
||||
};
|
||||
|
||||
let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout {
|
||||
n: n_glwe.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k_res.into(),
|
||||
rank: rank.into(),
|
||||
};
|
||||
|
||||
let lwe_infos: LWECiphertextLayout = LWECiphertextLayout {
|
||||
n: n_lwe.into(),
|
||||
k: k_lwe.into(),
|
||||
base2k: base2k.into(),
|
||||
};
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::<B>::alloc(BlindRotationKey::generate_from_sk_scratch_space(
|
||||
module, basek, k_brk, rank,
|
||||
module, &brk_infos,
|
||||
));
|
||||
|
||||
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
|
||||
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos);
|
||||
sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
|
||||
let sk_glwe_dft: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow());
|
||||
|
||||
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
|
||||
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe.into());
|
||||
sk_lwe.fill_binary_block(block_size, &mut source_xs);
|
||||
|
||||
let mut scratch_br: ScratchOwned<B> = ScratchOwned::<B>::alloc(cggi_blind_rotate_scratch_space(
|
||||
module,
|
||||
block_size,
|
||||
extension_factor,
|
||||
basek,
|
||||
k_res,
|
||||
k_brk,
|
||||
rows_brk,
|
||||
rank,
|
||||
&glwe_infos,
|
||||
&brk_infos,
|
||||
));
|
||||
|
||||
let mut brk: BlindRotationKey<Vec<u8>, CGGI> =
|
||||
BlindRotationKey::<Vec<u8>, CGGI>::alloc(n, n_lwe, basek, k_brk, rows_brk, rank);
|
||||
let mut brk: BlindRotationKey<Vec<u8>, CGGI> = BlindRotationKey::<Vec<u8>, CGGI>::alloc(&brk_infos);
|
||||
|
||||
brk.encrypt_sk(
|
||||
module,
|
||||
@@ -134,13 +153,13 @@ where
|
||||
scratch.borrow(),
|
||||
);
|
||||
|
||||
let mut lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe);
|
||||
let mut lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos);
|
||||
|
||||
let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe);
|
||||
let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(&lwe_infos);
|
||||
|
||||
let x: i64 = 15 % (message_modulus as i64);
|
||||
|
||||
pt_lwe.encode_i64(x, log_message_modulus + 1);
|
||||
pt_lwe.encode_i64(x, (log_message_modulus + 1).into());
|
||||
|
||||
lwe.encrypt_sk(module, &pt_lwe, &sk_lwe, &mut source_xa, &mut source_xe);
|
||||
|
||||
@@ -152,20 +171,20 @@ where
|
||||
.enumerate()
|
||||
.for_each(|(i, x)| *x = f(i as i64));
|
||||
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(module, basek, k_lut, extension_factor);
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(module, base2k, k_lut, extension_factor);
|
||||
lut.set(module, &f_vec, log_message_modulus + 1);
|
||||
|
||||
let mut res: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_res, rank);
|
||||
let mut res: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos);
|
||||
|
||||
let brk_prepared: BlindRotationKeyPrepared<Vec<u8>, CGGI, B> = brk.prepare_alloc(module, scratch.borrow());
|
||||
|
||||
brk_prepared.execute(module, &mut res, &lwe, &lut, scratch_br.borrow());
|
||||
|
||||
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_res);
|
||||
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos);
|
||||
|
||||
res.decrypt(module, &mut pt_have, &sk_glwe_dft, scratch.borrow());
|
||||
|
||||
let mut lwe_2n: Vec<i64> = vec![0i64; lwe.n() + 1]; // TODO: from scratch space
|
||||
let mut lwe_2n: Vec<i64> = vec![0i64; (lwe.n() + 1).into()]; // TODO: from scratch space
|
||||
|
||||
mod_switch_2n(
|
||||
2 * lut.domain_size(),
|
||||
@@ -189,7 +208,7 @@ where
|
||||
assert_eq!(pt_have.data.at(0, 0), lut.data[0].at(0, 0));
|
||||
|
||||
// Verify that it effectively compute f(x)
|
||||
let mut have: i64 = pt_have.decode_coeff_i64(log_message_modulus + 1, 0);
|
||||
let mut have: i64 = pt_have.decode_coeff_i64((log_message_modulus + 1).into(), 0);
|
||||
|
||||
// Get positive representative and assert equality
|
||||
have = (have + message_modulus as i64) % (message_modulus as i64);
|
||||
|
||||
@@ -21,19 +21,19 @@ where
|
||||
+ VecZnxRotateInplaceTmpBytes,
|
||||
B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>,
|
||||
{
|
||||
let basek: usize = 20;
|
||||
let base2k: usize = 20;
|
||||
let k_lut: usize = 40;
|
||||
let message_modulus: usize = 16;
|
||||
let extension_factor: usize = 1;
|
||||
|
||||
let log_scale: usize = basek + 1;
|
||||
let log_scale: usize = base2k + 1;
|
||||
|
||||
let mut f: Vec<i64> = vec![0i64; message_modulus];
|
||||
f.iter_mut()
|
||||
.enumerate()
|
||||
.for_each(|(i, x)| *x = (i as i64) - 8);
|
||||
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(module, basek, k_lut, extension_factor);
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(module, base2k, k_lut, extension_factor);
|
||||
lut.set(module, &f, log_scale);
|
||||
|
||||
let half_step: i64 = lut.domain_size().div_round(message_modulus << 1) as i64;
|
||||
@@ -42,7 +42,7 @@ where
|
||||
let step: usize = lut.domain_size().div_round(message_modulus);
|
||||
|
||||
let mut lut_dec: Vec<i64> = vec![0i64; module.n()];
|
||||
lut.data[0].decode_vec_i64(basek, 0, log_scale, &mut lut_dec);
|
||||
lut.data[0].decode_vec_i64(base2k, 0, log_scale, &mut lut_dec);
|
||||
|
||||
(0..lut.domain_size()).step_by(step).for_each(|i| {
|
||||
(0..step).for_each(|_| {
|
||||
@@ -61,19 +61,19 @@ where
|
||||
+ VecZnxRotateInplaceTmpBytes,
|
||||
B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>,
|
||||
{
|
||||
let basek: usize = 20;
|
||||
let base2k: usize = 20;
|
||||
let k_lut: usize = 40;
|
||||
let message_modulus: usize = 16;
|
||||
let extension_factor: usize = 4;
|
||||
|
||||
let log_scale: usize = basek + 1;
|
||||
let log_scale: usize = base2k + 1;
|
||||
|
||||
let mut f: Vec<i64> = vec![0i64; message_modulus];
|
||||
f.iter_mut()
|
||||
.enumerate()
|
||||
.for_each(|(i, x)| *x = (i as i64) - 8);
|
||||
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(module, basek, k_lut, extension_factor);
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(module, base2k, k_lut, extension_factor);
|
||||
lut.set(module, &f, log_scale);
|
||||
|
||||
let half_step: i64 = lut.domain_size().div_round(message_modulus << 1) as i64;
|
||||
@@ -84,7 +84,7 @@ where
|
||||
let mut lut_dec: Vec<i64> = vec![0i64; module.n()];
|
||||
|
||||
(0..extension_factor).for_each(|ext| {
|
||||
lut.data[ext].decode_vec_i64(basek, 0, log_scale, &mut lut_dec);
|
||||
lut.data[ext].decode_vec_i64(base2k, 0, log_scale, &mut lut_dec);
|
||||
(0..module.n()).step_by(step).for_each(|i| {
|
||||
(0..step).for_each(|_| {
|
||||
assert_eq!(f[i / step] % message_modulus as i64, lut_dec[i]);
|
||||
|
||||
@@ -1,15 +1,35 @@
|
||||
use poulpy_hal::test_suite::serialization::test_reader_writer_interface;
|
||||
|
||||
use crate::tfhe::blind_rotation::{BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyCompressed, CGGI};
|
||||
use crate::tfhe::blind_rotation::{
|
||||
BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyCompressed, BlindRotationKeyLayout, CGGI,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_cggi_blind_rotation_key_serialization() {
|
||||
let original: BlindRotationKey<Vec<u8>, CGGI> = BlindRotationKey::alloc(256, 64, 12, 54, 2, 2);
|
||||
let layout: BlindRotationKeyLayout = BlindRotationKeyLayout {
|
||||
n_glwe: 256_u32.into(),
|
||||
n_lwe: 64_usize.into(),
|
||||
base2k: 12_usize.into(),
|
||||
k: 54_usize.into(),
|
||||
rows: 2_usize.into(),
|
||||
rank: 2_usize.into(),
|
||||
};
|
||||
|
||||
let original: BlindRotationKey<Vec<u8>, CGGI> = BlindRotationKey::alloc(&layout);
|
||||
test_reader_writer_interface(original);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cggi_blind_rotation_key_compressed_serialization() {
|
||||
let original: BlindRotationKeyCompressed<Vec<u8>, CGGI> = BlindRotationKeyCompressed::alloc(256, 64, 12, 54, 2, 2);
|
||||
let layout: BlindRotationKeyLayout = BlindRotationKeyLayout {
|
||||
n_glwe: 256_u32.into(),
|
||||
n_lwe: 64_usize.into(),
|
||||
base2k: 12_usize.into(),
|
||||
k: 54_usize.into(),
|
||||
rows: 2_usize.into(),
|
||||
rank: 2_usize.into(),
|
||||
};
|
||||
|
||||
let original: BlindRotationKeyCompressed<Vec<u8>, CGGI> = BlindRotationKeyCompressed::alloc(&layout);
|
||||
test_reader_writer_interface(original);
|
||||
}
|
||||
|
||||
@@ -4,17 +4,20 @@ use poulpy_hal::{
|
||||
api::{
|
||||
ScratchAvailable, TakeMatZnx, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, TakeVecZnxDftSlice, TakeVecZnxSlice,
|
||||
VecZnxAddInplace, VecZnxAutomorphismInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace,
|
||||
VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallBInplace, VecZnxCopy, VecZnxDftAddInplace,
|
||||
VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAddInplace,
|
||||
VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNegateInplace,
|
||||
VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes,
|
||||
VecZnxRshInplace, VecZnxSub, VecZnxSubABInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
|
||||
VmpApplyDftToDftTmpBytes,
|
||||
VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace,
|
||||
VecZnxRotateInplaceTmpBytes, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft,
|
||||
VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes,
|
||||
},
|
||||
layouts::{Backend, DataMut, DataRef, Module, Scratch, ToOwnedDeep},
|
||||
oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl},
|
||||
};
|
||||
|
||||
use poulpy_core::{GLWEOperations, TakeGGLWE, TakeGLWECt, layouts::Infos};
|
||||
use poulpy_core::{
|
||||
GLWEOperations, TakeGGLWE, TakeGLWECt,
|
||||
layouts::{Digits, GGLWECiphertextLayout, GGSWInfos, GLWEInfos, LWEInfos},
|
||||
};
|
||||
|
||||
use poulpy_core::layouts::{GGSWCiphertext, GLWECiphertext, LWECiphertext, prepared::GGLWEAutomorphismKeyPrepared};
|
||||
|
||||
@@ -39,7 +42,7 @@ where
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxNegateInplace
|
||||
+ VecZnxCopy
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxDftAllocBytes
|
||||
+ VmpApplyDftToDftTmpBytes
|
||||
+ VecZnxBigNormalizeTmpBytes
|
||||
@@ -50,11 +53,12 @@ where
|
||||
+ VecZnxBigAddSmallInplace<B>
|
||||
+ VecZnxBigNormalize<B>
|
||||
+ VecZnxAutomorphismInplace<B>
|
||||
+ VecZnxBigSubSmallBInplace<B>
|
||||
+ VecZnxBigSubSmallNegateInplace<B>
|
||||
+ VecZnxRotateInplaceTmpBytes
|
||||
+ VecZnxBigAllocBytes
|
||||
+ VecZnxDftAddInplace<B>
|
||||
+ VecZnxRotate,
|
||||
+ VecZnxRotate
|
||||
+ VecZnxNormalize<B>,
|
||||
B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>,
|
||||
Scratch<B>: TakeVecZnx
|
||||
+ TakeVecZnxDftSlice<B>
|
||||
@@ -138,7 +142,7 @@ pub fn circuit_bootstrap_core<DRes, DLwe, DBrk, BRA: BlindRotationAlgo, B>(
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxNegateInplace
|
||||
+ VecZnxCopy
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxDftAllocBytes
|
||||
+ VmpApplyDftToDftTmpBytes
|
||||
+ VecZnxBigNormalizeTmpBytes
|
||||
@@ -149,11 +153,12 @@ pub fn circuit_bootstrap_core<DRes, DLwe, DBrk, BRA: BlindRotationAlgo, B>(
|
||||
+ VecZnxBigAddSmallInplace<B>
|
||||
+ VecZnxBigNormalize<B>
|
||||
+ VecZnxAutomorphismInplace<B>
|
||||
+ VecZnxBigSubSmallBInplace<B>
|
||||
+ VecZnxBigSubSmallNegateInplace<B>
|
||||
+ VecZnxBigAllocBytes
|
||||
+ VecZnxDftAddInplace<B>
|
||||
+ VecZnxRotateInplaceTmpBytes
|
||||
+ VecZnxRotate,
|
||||
+ VecZnxRotate
|
||||
+ VecZnxNormalize<B>,
|
||||
B: Backend + ScratchOwnedAllocImpl<B> + ScratchOwnedBorrowImpl<B>,
|
||||
Scratch<B>: TakeVecZnxDftSlice<B>
|
||||
+ TakeVecZnxBig<B>
|
||||
@@ -166,16 +171,18 @@ pub fn circuit_bootstrap_core<DRes, DLwe, DBrk, BRA: BlindRotationAlgo, B>(
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
use poulpy_core::layouts::LWEInfos;
|
||||
|
||||
assert_eq!(res.n(), key.brk.n());
|
||||
assert_eq!(lwe.basek(), key.brk.basek());
|
||||
assert_eq!(res.basek(), key.brk.basek());
|
||||
assert_eq!(lwe.base2k(), key.brk.base2k());
|
||||
assert_eq!(res.base2k(), key.brk.base2k());
|
||||
}
|
||||
|
||||
let n: usize = res.n();
|
||||
let basek: usize = res.basek();
|
||||
let rows: usize = res.rows();
|
||||
let rank: usize = res.rank();
|
||||
let k: usize = res.k();
|
||||
let n: usize = res.n().into();
|
||||
let base2k: usize = res.base2k().into();
|
||||
let rows: usize = res.rows().into();
|
||||
let rank: usize = res.rank().into();
|
||||
let k: usize = res.k().into();
|
||||
|
||||
let alpha: usize = rows.next_power_of_two();
|
||||
|
||||
@@ -183,27 +190,38 @@ pub fn circuit_bootstrap_core<DRes, DLwe, DBrk, BRA: BlindRotationAlgo, B>(
|
||||
|
||||
if to_exponent {
|
||||
(0..rows).for_each(|i| {
|
||||
f[i] = 1 << (basek * (rows - 1 - i));
|
||||
f[i] = 1 << (base2k * (rows - 1 - i));
|
||||
});
|
||||
} else {
|
||||
(0..1 << log_domain).for_each(|j| {
|
||||
(0..rows).for_each(|i| {
|
||||
f[j * alpha + i] = j as i64 * (1 << (basek * (rows - 1 - i)));
|
||||
f[j * alpha + i] = j as i64 * (1 << (base2k * (rows - 1 - i)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Lut precision, basically must be able to hold the decomposition power basis of the GGSW
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(module, basek, basek * rows, extension_factor);
|
||||
lut.set(module, &f, basek * rows);
|
||||
let mut lut: LookUpTable = LookUpTable::alloc(module, base2k, base2k * rows, extension_factor);
|
||||
lut.set(module, &f, base2k * rows);
|
||||
|
||||
if to_exponent {
|
||||
lut.set_rotation_direction(LookUpTableRotationDirection::Right);
|
||||
}
|
||||
|
||||
// TODO: separate GGSW k from output of blind rotation k
|
||||
let (mut res_glwe, scratch_1) = scratch.take_glwe_ct(n, basek, k, rank);
|
||||
let (mut tmp_gglwe, scratch_2) = scratch_1.take_gglwe(n, basek, k, rows, 1, rank.max(1), rank);
|
||||
let (mut res_glwe, scratch_1) = scratch.take_glwe_ct(res);
|
||||
|
||||
let gglwe_infos: GGLWECiphertextLayout = GGLWECiphertextLayout {
|
||||
n: n.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k.into(),
|
||||
rows: rows.into(),
|
||||
digits: Digits(1),
|
||||
rank_in: rank.max(1).into(),
|
||||
rank_out: rank.into(),
|
||||
};
|
||||
|
||||
let (mut tmp_gglwe, scratch_2) = scratch_1.take_gglwe(&gglwe_infos);
|
||||
|
||||
key.brk.execute(module, &mut res_glwe, lwe, &lut, scratch_2);
|
||||
|
||||
@@ -264,7 +282,7 @@ fn post_process<DataRes, DataA, B: Backend>(
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxNegateInplace
|
||||
+ VecZnxCopy
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxDftAllocBytes
|
||||
+ VmpApplyDftToDftTmpBytes
|
||||
+ VecZnxBigNormalizeTmpBytes
|
||||
@@ -275,8 +293,9 @@ fn post_process<DataRes, DataA, B: Backend>(
|
||||
+ VecZnxBigAddSmallInplace<B>
|
||||
+ VecZnxBigNormalize<B>
|
||||
+ VecZnxAutomorphismInplace<B>
|
||||
+ VecZnxBigSubSmallBInplace<B>
|
||||
+ VecZnxRotate,
|
||||
+ VecZnxBigSubSmallNegateInplace<B>
|
||||
+ VecZnxRotate
|
||||
+ VecZnxNormalize<B>,
|
||||
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx,
|
||||
{
|
||||
let log_n: usize = module.log_n();
|
||||
@@ -336,7 +355,7 @@ pub fn pack<D: DataMut, B: Backend>(
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxNegateInplace
|
||||
+ VecZnxCopy
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxDftAllocBytes
|
||||
+ VmpApplyDftToDftTmpBytes
|
||||
+ VecZnxBigNormalizeTmpBytes
|
||||
@@ -347,16 +366,13 @@ pub fn pack<D: DataMut, B: Backend>(
|
||||
+ VecZnxBigAddSmallInplace<B>
|
||||
+ VecZnxBigNormalize<B>
|
||||
+ VecZnxAutomorphismInplace<B>
|
||||
+ VecZnxBigSubSmallBInplace<B>
|
||||
+ VecZnxRotate,
|
||||
+ VecZnxBigSubSmallNegateInplace<B>
|
||||
+ VecZnxRotate
|
||||
+ VecZnxNormalize<B>,
|
||||
Scratch<B>: TakeVecZnx + TakeVecZnxDft<B> + ScratchAvailable,
|
||||
{
|
||||
let log_n: usize = module.log_n();
|
||||
|
||||
let basek: usize = cts.get(&0).unwrap().basek();
|
||||
let k: usize = cts.get(&0).unwrap().k();
|
||||
let rank: usize = cts.get(&0).unwrap().rank();
|
||||
|
||||
(0..log_n - log_gap_out).for_each(|i| {
|
||||
let t: usize = 16.min(1 << (log_n - 1 - i));
|
||||
|
||||
@@ -370,17 +386,7 @@ pub fn pack<D: DataMut, B: Backend>(
|
||||
let mut a: Option<GLWECiphertext<D>> = cts.remove(&j);
|
||||
let mut b: Option<GLWECiphertext<D>> = cts.remove(&(j + t));
|
||||
|
||||
combine(
|
||||
module,
|
||||
basek,
|
||||
k,
|
||||
rank,
|
||||
a.as_mut(),
|
||||
b.as_mut(),
|
||||
i,
|
||||
auto_key,
|
||||
scratch,
|
||||
);
|
||||
combine(module, a.as_mut(), b.as_mut(), i, auto_key, scratch);
|
||||
|
||||
if let Some(a) = a {
|
||||
cts.insert(j, a);
|
||||
@@ -394,9 +400,6 @@ pub fn pack<D: DataMut, B: Backend>(
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn combine<A: DataMut, D: DataMut, DataAK: DataRef, B: Backend>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
k: usize,
|
||||
rank: usize,
|
||||
a: Option<&mut GLWECiphertext<A>>,
|
||||
b: Option<&mut GLWECiphertext<D>>,
|
||||
i: usize,
|
||||
@@ -415,7 +418,7 @@ fn combine<A: DataMut, D: DataMut, DataAK: DataRef, B: Backend>(
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxNegateInplace
|
||||
+ VecZnxCopy
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxDftAllocBytes
|
||||
+ VmpApplyDftToDftTmpBytes
|
||||
+ VecZnxBigNormalizeTmpBytes
|
||||
@@ -426,8 +429,9 @@ fn combine<A: DataMut, D: DataMut, DataAK: DataRef, B: Backend>(
|
||||
+ VecZnxBigAddSmallInplace<B>
|
||||
+ VecZnxBigNormalize<B>
|
||||
+ VecZnxAutomorphismInplace<B>
|
||||
+ VecZnxBigSubSmallBInplace<B>
|
||||
+ VecZnxRotate,
|
||||
+ VecZnxBigSubSmallNegateInplace<B>
|
||||
+ VecZnxRotate
|
||||
+ VecZnxNormalize<B>,
|
||||
Scratch<B>: TakeVecZnx + TakeVecZnxDft<B> + ScratchAvailable,
|
||||
{
|
||||
// Goal is to evaluate: a = a + b*X^t + phi(a - b*X^t))
|
||||
@@ -441,12 +445,10 @@ fn combine<A: DataMut, D: DataMut, DataAK: DataRef, B: Backend>(
|
||||
// either mapped to garbage or twice their value which vanishes I(X)
|
||||
// since 2*(I(X) * Q/2) = I(X) * Q = 0 mod Q.
|
||||
if let Some(a) = a {
|
||||
let n: usize = a.n();
|
||||
let log_n: usize = (u64::BITS - (n - 1).leading_zeros()) as _;
|
||||
let t: i64 = 1 << (log_n - i - 1);
|
||||
let t: i64 = 1 << (a.n().log2() - i - 1);
|
||||
|
||||
if let Some(b) = b {
|
||||
let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(n, basek, k, rank);
|
||||
let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(a);
|
||||
|
||||
// a = a * X^-t
|
||||
a.rotate_inplace(module, -t, scratch_1);
|
||||
@@ -478,15 +480,13 @@ fn combine<A: DataMut, D: DataMut, DataAK: DataRef, B: Backend>(
|
||||
a.automorphism_add_inplace(module, auto_key, scratch);
|
||||
}
|
||||
} else if let Some(b) = b {
|
||||
let n: usize = b.n();
|
||||
let log_n: usize = (u64::BITS - (n - 1).leading_zeros()) as _;
|
||||
let t: i64 = 1 << (log_n - i - 1);
|
||||
let t: i64 = 1 << (b.n().log2() - i - 1);
|
||||
|
||||
let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(n, basek, k, rank);
|
||||
let (mut tmp_b, scratch_1) = scratch.take_glwe_ct(b);
|
||||
tmp_b.rotate(module, t, b);
|
||||
tmp_b.rsh(module, 1, scratch_1);
|
||||
|
||||
// a = (b* X^t - phi(b* X^t))
|
||||
b.automorphism_sub_ba(module, &tmp_b, auto_key, scratch_1);
|
||||
b.automorphism_sub_negate(module, &tmp_b, auto_key, scratch_1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use poulpy_core::layouts::{
|
||||
GGLWEAutomorphismKey, GGLWETensorKey, GLWECiphertext, GLWESecret, LWESecret,
|
||||
GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWELayoutInfos, GGLWETensorKey, GGLWETensorKeyLayout, GGSWInfos,
|
||||
GLWECiphertext, GLWEInfos, GLWESecret, LWEInfos, LWESecret,
|
||||
prepared::{GGLWEAutomorphismKeyPrepared, GGLWETensorKeyPrepared, GLWESecretPrepared, PrepareAlloc},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
@@ -9,7 +10,7 @@ use poulpy_hal::{
|
||||
ScratchAvailable, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx,
|
||||
TakeSvpPPol, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace,
|
||||
VecZnxAutomorphism, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume,
|
||||
VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace,
|
||||
VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace,
|
||||
VecZnxSwitchRing, VmpPMatAlloc, VmpPrepare,
|
||||
},
|
||||
layouts::{Backend, Data, DataRef, Module, Scratch},
|
||||
@@ -17,27 +18,49 @@ use poulpy_hal::{
|
||||
};
|
||||
|
||||
use crate::tfhe::blind_rotation::{
|
||||
BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, BlindRotationKeyPrepared,
|
||||
BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, BlindRotationKeyInfos,
|
||||
BlindRotationKeyLayout, BlindRotationKeyPrepared,
|
||||
};
|
||||
|
||||
pub trait CircuitBootstrappingKeyInfos {
|
||||
fn layout_brk(&self) -> BlindRotationKeyLayout;
|
||||
fn layout_atk(&self) -> GGLWEAutomorphismKeyLayout;
|
||||
fn layout_tsk(&self) -> GGLWETensorKeyLayout;
|
||||
}
|
||||
|
||||
pub struct CircuitBootstrappingKeyLayout {
|
||||
pub layout_brk: BlindRotationKeyLayout,
|
||||
pub layout_atk: GGLWEAutomorphismKeyLayout,
|
||||
pub layout_tsk: GGLWETensorKeyLayout,
|
||||
}
|
||||
|
||||
impl CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyLayout {
|
||||
fn layout_atk(&self) -> GGLWEAutomorphismKeyLayout {
|
||||
self.layout_atk
|
||||
}
|
||||
|
||||
fn layout_brk(&self) -> BlindRotationKeyLayout {
|
||||
self.layout_brk
|
||||
}
|
||||
|
||||
fn layout_tsk(&self) -> GGLWETensorKeyLayout {
|
||||
self.layout_tsk
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CircuitBootstrappingKeyEncryptSk<B: Backend> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn encrypt_sk<DLwe, DGlwe>(
|
||||
fn encrypt_sk<DLwe, DGlwe, INFOS>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
sk_lwe: &LWESecret<DLwe>,
|
||||
sk_glwe: &GLWESecret<DGlwe>,
|
||||
k_brk: usize,
|
||||
rows_brk: usize,
|
||||
k_trace: usize,
|
||||
rows_trace: usize,
|
||||
k_tsk: usize,
|
||||
rows_tsk: usize,
|
||||
cbt_infos: &INFOS,
|
||||
source_xa: &mut Source,
|
||||
source_xe: &mut Source,
|
||||
scratch: &mut Scratch<B>,
|
||||
) -> Self
|
||||
where
|
||||
INFOS: CircuitBootstrappingKeyInfos,
|
||||
DLwe: DataRef,
|
||||
DGlwe: DataRef;
|
||||
}
|
||||
@@ -61,7 +84,7 @@ where
|
||||
+ VecZnxIdftApplyConsume<B>
|
||||
+ VecZnxNormalizeTmpBytes
|
||||
+ VecZnxFillUniform
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxNormalizeInplace<B>
|
||||
+ VecZnxAddNormal
|
||||
@@ -74,46 +97,41 @@ where
|
||||
+ VecZnxAutomorphism,
|
||||
Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeSvpPPol<B> + TakeVecZnxBig<B>,
|
||||
{
|
||||
fn encrypt_sk<DLwe, DGlwe>(
|
||||
fn encrypt_sk<DLwe, DGlwe, INFOS>(
|
||||
module: &Module<B>,
|
||||
basek: usize,
|
||||
sk_lwe: &LWESecret<DLwe>,
|
||||
sk_glwe: &GLWESecret<DGlwe>,
|
||||
k_brk: usize,
|
||||
rows_brk: usize,
|
||||
k_trace: usize,
|
||||
rows_trace: usize,
|
||||
k_tsk: usize,
|
||||
rows_tsk: usize,
|
||||
cbt_infos: &INFOS,
|
||||
source_xa: &mut Source,
|
||||
source_xe: &mut Source,
|
||||
scratch: &mut Scratch<B>,
|
||||
) -> Self
|
||||
where
|
||||
INFOS: CircuitBootstrappingKeyInfos,
|
||||
DLwe: DataRef,
|
||||
DGlwe: DataRef,
|
||||
Module<B>:,
|
||||
{
|
||||
assert_eq!(sk_lwe.n(), cbt_infos.layout_brk().n_lwe());
|
||||
assert_eq!(sk_glwe.n(), cbt_infos.layout_brk().n_glwe());
|
||||
assert_eq!(sk_glwe.n(), cbt_infos.layout_atk().n());
|
||||
assert_eq!(sk_glwe.n(), cbt_infos.layout_tsk().n());
|
||||
|
||||
let atk_infos: GGLWEAutomorphismKeyLayout = cbt_infos.layout_atk();
|
||||
let brk_infos: BlindRotationKeyLayout = cbt_infos.layout_brk();
|
||||
let trk_infos: GGLWETensorKeyLayout = cbt_infos.layout_tsk();
|
||||
|
||||
let mut auto_keys: HashMap<i64, GGLWEAutomorphismKey<Vec<u8>>> = HashMap::new();
|
||||
let gal_els: Vec<i64> = GLWECiphertext::trace_galois_elements(module);
|
||||
gal_els.iter().for_each(|gal_el| {
|
||||
let mut key: GGLWEAutomorphismKey<Vec<u8>> =
|
||||
GGLWEAutomorphismKey::alloc(sk_glwe.n(), basek, k_trace, rows_trace, 1, sk_glwe.rank());
|
||||
let mut key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&atk_infos);
|
||||
key.encrypt_sk(module, *gal_el, sk_glwe, source_xa, source_xe, scratch);
|
||||
auto_keys.insert(*gal_el, key);
|
||||
});
|
||||
|
||||
let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch);
|
||||
|
||||
let mut brk: BlindRotationKey<Vec<u8>, BRA> = BlindRotationKey::<Vec<u8>, BRA>::alloc(
|
||||
sk_glwe.n(),
|
||||
sk_lwe.n(),
|
||||
basek,
|
||||
k_brk,
|
||||
rows_brk,
|
||||
sk_glwe.rank(),
|
||||
);
|
||||
|
||||
let mut brk: BlindRotationKey<Vec<u8>, BRA> = BlindRotationKey::<Vec<u8>, BRA>::alloc(&brk_infos);
|
||||
brk.encrypt_sk(
|
||||
module,
|
||||
&sk_glwe_prepared,
|
||||
@@ -123,7 +141,7 @@ where
|
||||
scratch,
|
||||
);
|
||||
|
||||
let mut tsk: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(sk_glwe.n(), basek, k_tsk, rows_tsk, 1, sk_glwe.rank());
|
||||
let mut tsk: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&trk_infos);
|
||||
tsk.encrypt_sk(module, sk_glwe, source_xa, source_xe, scratch);
|
||||
|
||||
Self {
|
||||
@@ -140,6 +158,42 @@ pub struct CircuitBootstrappingKeyPrepared<D: Data, BRA: BlindRotationAlgo, B: B
|
||||
pub(crate) atk: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>>,
|
||||
}
|
||||
|
||||
impl<D: DataRef, BRA: BlindRotationAlgo, B: Backend> CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyPrepared<D, BRA, B> {
|
||||
fn layout_atk(&self) -> GGLWEAutomorphismKeyLayout {
|
||||
let (_, atk) = self.atk.iter().next().expect("atk is empty");
|
||||
GGLWEAutomorphismKeyLayout {
|
||||
n: atk.n(),
|
||||
base2k: atk.base2k(),
|
||||
k: atk.k(),
|
||||
rows: atk.rows(),
|
||||
digits: atk.digits(),
|
||||
rank: atk.rank(),
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_brk(&self) -> BlindRotationKeyLayout {
|
||||
BlindRotationKeyLayout {
|
||||
n_glwe: self.brk.n_glwe(),
|
||||
n_lwe: self.brk.n_lwe(),
|
||||
base2k: self.brk.base2k(),
|
||||
k: self.brk.k(),
|
||||
rows: self.brk.rows(),
|
||||
rank: self.brk.rank(),
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_tsk(&self) -> GGLWETensorKeyLayout {
|
||||
GGLWETensorKeyLayout {
|
||||
n: self.tsk.n(),
|
||||
base2k: self.tsk.base2k(),
|
||||
k: self.tsk.k(),
|
||||
rows: self.tsk.rows(),
|
||||
digits: self.tsk.digits(),
|
||||
rank: self.tsk.rank(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: DataRef, BRA: BlindRotationAlgo, B: Backend> PrepareAlloc<B, CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, B>>
|
||||
for CircuitBootstrappingKey<D, BRA>
|
||||
where
|
||||
|
||||
@@ -5,10 +5,10 @@ use poulpy_hal::{
|
||||
ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes,
|
||||
SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace,
|
||||
VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace,
|
||||
VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallBInplace, VecZnxCopy, VecZnxDftAddInplace,
|
||||
VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAddInplace,
|
||||
VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxFillUniform, VecZnxIdftApplyConsume,
|
||||
VecZnxIdftApplyTmpA, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotate,
|
||||
VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, VecZnxRshInplace, VecZnxSub, VecZnxSubABInplace, VecZnxSwitchRing,
|
||||
VecZnxRotateInplace, VecZnxRotateInplaceTmpBytes, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing,
|
||||
VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, ZnAddNormal, ZnFillUniform,
|
||||
ZnNormalizeInplace,
|
||||
},
|
||||
@@ -23,14 +23,17 @@ use poulpy_hal::{
|
||||
use crate::tfhe::{
|
||||
blind_rotation::{
|
||||
BlincRotationExecute, BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk,
|
||||
BlindRotationKeyPrepared,
|
||||
BlindRotationKeyLayout, BlindRotationKeyPrepared,
|
||||
},
|
||||
circuit_bootstrapping::{
|
||||
CircuitBootstrappingKey, CircuitBootstrappingKeyEncryptSk, CircuitBootstrappingKeyPrepared, CirtuitBootstrappingExecute,
|
||||
CircuitBootstrappingKey, CircuitBootstrappingKeyEncryptSk, CircuitBootstrappingKeyLayout,
|
||||
CircuitBootstrappingKeyPrepared, CirtuitBootstrappingExecute,
|
||||
},
|
||||
};
|
||||
|
||||
use poulpy_core::layouts::prepared::PrepareAlloc;
|
||||
use poulpy_core::layouts::{
|
||||
Digits, GGLWEAutomorphismKeyLayout, GGLWETensorKeyLayout, GGSWCiphertextLayout, LWECiphertextLayout, prepared::PrepareAlloc,
|
||||
};
|
||||
|
||||
use poulpy_core::layouts::{
|
||||
GGSWCiphertext, GLWECiphertext, GLWEPlaintext, GLWESecret, LWECiphertext, LWEPlaintext, LWESecret,
|
||||
@@ -48,7 +51,7 @@ where
|
||||
+ SvpApplyDftToDftInplace<B>
|
||||
+ VecZnxIdftApplyConsume<B>
|
||||
+ VecZnxNormalizeTmpBytes
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxNormalize<B>
|
||||
+ VecZnxSub
|
||||
@@ -78,7 +81,7 @@ where
|
||||
+ VecZnxNegateInplace
|
||||
+ VecZnxCopy
|
||||
+ VecZnxAutomorphismInplace<B>
|
||||
+ VecZnxBigSubSmallBInplace<B>
|
||||
+ VecZnxBigSubSmallNegateInplace<B>
|
||||
+ VecZnxRotateInplaceTmpBytes
|
||||
+ VecZnxBigAllocBytes
|
||||
+ VecZnxDftAddInplace<B>
|
||||
@@ -102,8 +105,8 @@ where
|
||||
BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlincRotationExecute<B>,
|
||||
BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>,
|
||||
{
|
||||
let n: usize = module.n();
|
||||
let basek: usize = 17;
|
||||
let n_glwe: usize = module.n();
|
||||
let base2k: usize = 17;
|
||||
let extension_factor: usize = 1;
|
||||
let rank: usize = 1;
|
||||
|
||||
@@ -112,61 +115,97 @@ where
|
||||
let k_lwe_ct: usize = 22;
|
||||
let block_size: usize = 7;
|
||||
|
||||
let k_brk: usize = 5 * basek;
|
||||
let k_brk: usize = 5 * base2k;
|
||||
let rows_brk: usize = 4;
|
||||
|
||||
let k_trace: usize = 5 * basek;
|
||||
let rows_trace: usize = 4;
|
||||
let k_atk: usize = 5 * base2k;
|
||||
let rows_atk: usize = 4;
|
||||
|
||||
let k_tsk: usize = 5 * basek;
|
||||
let k_tsk: usize = 5 * base2k;
|
||||
let rows_tsk: usize = 4;
|
||||
|
||||
let k_ggsw_res: usize = 4 * base2k;
|
||||
let rows_ggsw_res: usize = 2;
|
||||
|
||||
let lwe_infos: LWECiphertextLayout = LWECiphertextLayout {
|
||||
n: n_lwe.into(),
|
||||
k: k_lwe_ct.into(),
|
||||
base2k: base2k.into(),
|
||||
};
|
||||
|
||||
let cbt_infos: CircuitBootstrappingKeyLayout = CircuitBootstrappingKeyLayout {
|
||||
layout_brk: BlindRotationKeyLayout {
|
||||
n_glwe: n_glwe.into(),
|
||||
n_lwe: n_lwe.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k_brk.into(),
|
||||
rows: rows_brk.into(),
|
||||
rank: rank.into(),
|
||||
},
|
||||
layout_atk: GGLWEAutomorphismKeyLayout {
|
||||
n: n_glwe.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k_atk.into(),
|
||||
rows: rows_atk.into(),
|
||||
rank: rank.into(),
|
||||
digits: Digits(1),
|
||||
},
|
||||
layout_tsk: GGLWETensorKeyLayout {
|
||||
n: n_glwe.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k_tsk.into(),
|
||||
rows: rows_tsk.into(),
|
||||
digits: Digits(1),
|
||||
rank: rank.into(),
|
||||
},
|
||||
};
|
||||
|
||||
let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
|
||||
n: n_glwe.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k_ggsw_res.into(),
|
||||
rows: rows_ggsw_res.into(),
|
||||
digits: Digits(1),
|
||||
rank: rank.into(),
|
||||
};
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(1 << 23);
|
||||
|
||||
let mut source_xs: Source = Source::new([1u8; 32]);
|
||||
let mut source_xa: Source = Source::new([1u8; 32]);
|
||||
let mut source_xe: Source = Source::new([1u8; 32]);
|
||||
|
||||
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
|
||||
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe.into());
|
||||
sk_lwe.fill_binary_block(block_size, &mut source_xs);
|
||||
|
||||
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
|
||||
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n_glwe.into(), rank.into());
|
||||
sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
|
||||
|
||||
let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow());
|
||||
|
||||
let data: i64 = 1;
|
||||
|
||||
let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe_pt);
|
||||
pt_lwe.encode_i64(data, k_lwe_pt + 1);
|
||||
let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_with(base2k.into(), k_lwe_pt.into());
|
||||
pt_lwe.encode_i64(data, (k_lwe_pt + 1).into());
|
||||
|
||||
println!("pt_lwe: {}", pt_lwe);
|
||||
println!("pt_lwe: {pt_lwe}");
|
||||
|
||||
let mut ct_lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe_ct);
|
||||
let mut ct_lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos);
|
||||
ct_lwe.encrypt_sk(module, &pt_lwe, &sk_lwe, &mut source_xa, &mut source_xe);
|
||||
|
||||
let now: Instant = Instant::now();
|
||||
let cbt_key: CircuitBootstrappingKey<Vec<u8>, BRA> = CircuitBootstrappingKey::encrypt_sk(
|
||||
module,
|
||||
basek,
|
||||
&sk_lwe,
|
||||
&sk_glwe,
|
||||
k_brk,
|
||||
rows_brk,
|
||||
k_trace,
|
||||
rows_trace,
|
||||
k_tsk,
|
||||
rows_tsk,
|
||||
&cbt_infos,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
scratch.borrow(),
|
||||
);
|
||||
println!("CBT-KGEN: {} ms", now.elapsed().as_millis());
|
||||
|
||||
let k_ggsw_res: usize = 4 * basek;
|
||||
let rows_ggsw_res: usize = 2;
|
||||
|
||||
let mut res: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw_res, rows_ggsw_res, 1, rank);
|
||||
let mut res: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos);
|
||||
|
||||
let log_gap_out = 1;
|
||||
|
||||
@@ -185,7 +224,7 @@ where
|
||||
println!("CBT: {} ms", now.elapsed().as_millis());
|
||||
|
||||
// X^{data * 2^log_gap_out}
|
||||
let mut pt_ggsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
|
||||
let mut pt_ggsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n_glwe, 1);
|
||||
pt_ggsw.at_mut(0, 0)[0] = 1;
|
||||
module.vec_znx_rotate_inplace(
|
||||
data * (1 << log_gap_out),
|
||||
@@ -196,11 +235,9 @@ where
|
||||
|
||||
res.print_noise(module, &sk_glwe_prepared, &pt_ggsw);
|
||||
|
||||
let k_glwe: usize = k_ggsw_res;
|
||||
|
||||
let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_glwe, rank);
|
||||
let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, basek);
|
||||
pt_glwe.data.at_mut(0, 0)[0] = 1 << (basek - 2);
|
||||
let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&ggsw_infos);
|
||||
let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ggsw_infos);
|
||||
pt_glwe.data.at_mut(0, 0)[0] = 1 << (base2k - 2);
|
||||
|
||||
ct_glwe.encrypt_sk(
|
||||
module,
|
||||
@@ -215,7 +252,7 @@ where
|
||||
|
||||
ct_glwe.external_product_inplace(module, &res_prepared, scratch.borrow());
|
||||
|
||||
let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_glwe);
|
||||
let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ggsw_infos);
|
||||
ct_glwe.decrypt(module, &mut pt_res, &sk_glwe_prepared, scratch.borrow());
|
||||
|
||||
// Parameters are set such that the first limb should be noiseless.
|
||||
@@ -235,7 +272,7 @@ where
|
||||
+ SvpApplyDftToDftInplace<B>
|
||||
+ VecZnxIdftApplyConsume<B>
|
||||
+ VecZnxNormalizeTmpBytes
|
||||
+ VecZnxSubABInplace
|
||||
+ VecZnxSubInplace
|
||||
+ VecZnxAddInplace
|
||||
+ VecZnxNormalize<B>
|
||||
+ VecZnxSub
|
||||
@@ -266,7 +303,7 @@ where
|
||||
+ VecZnxNegateInplace
|
||||
+ VecZnxCopy
|
||||
+ VecZnxAutomorphismInplace<B>
|
||||
+ VecZnxBigSubSmallBInplace<B>
|
||||
+ VecZnxBigSubSmallNegateInplace<B>
|
||||
+ VecZnxBigAllocBytes
|
||||
+ VecZnxDftAddInplace<B>
|
||||
+ VecZnxRotate
|
||||
@@ -289,8 +326,8 @@ where
|
||||
BlindRotationKeyPrepared<Vec<u8>, BRA, B>: BlincRotationExecute<B>,
|
||||
BlindRotationKey<Vec<u8>, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk<B>,
|
||||
{
|
||||
let n: usize = module.n();
|
||||
let basek: usize = 14;
|
||||
let n_glwe: usize = module.n();
|
||||
let base2k: usize = 14;
|
||||
let extension_factor: usize = 1;
|
||||
let rank: usize = 2;
|
||||
|
||||
@@ -299,61 +336,97 @@ where
|
||||
let k_lwe_ct: usize = 13;
|
||||
let block_size: usize = 7;
|
||||
|
||||
let k_brk: usize = 5 * basek;
|
||||
let k_brk: usize = 5 * base2k;
|
||||
let rows_brk: usize = 3;
|
||||
|
||||
let k_trace: usize = 5 * basek;
|
||||
let rows_trace: usize = 4;
|
||||
let k_atk: usize = 5 * base2k;
|
||||
let rows_atk: usize = 4;
|
||||
|
||||
let k_tsk: usize = 5 * basek;
|
||||
let k_tsk: usize = 5 * base2k;
|
||||
let rows_tsk: usize = 4;
|
||||
|
||||
let k_ggsw_res: usize = 4 * base2k;
|
||||
let rows_ggsw_res: usize = 3;
|
||||
|
||||
let lwe_infos: LWECiphertextLayout = LWECiphertextLayout {
|
||||
n: n_lwe.into(),
|
||||
k: k_lwe_ct.into(),
|
||||
base2k: base2k.into(),
|
||||
};
|
||||
|
||||
let cbt_infos: CircuitBootstrappingKeyLayout = CircuitBootstrappingKeyLayout {
|
||||
layout_brk: BlindRotationKeyLayout {
|
||||
n_glwe: n_glwe.into(),
|
||||
n_lwe: n_lwe.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k_brk.into(),
|
||||
rows: rows_brk.into(),
|
||||
rank: rank.into(),
|
||||
},
|
||||
layout_atk: GGLWEAutomorphismKeyLayout {
|
||||
n: n_glwe.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k_atk.into(),
|
||||
rows: rows_atk.into(),
|
||||
rank: rank.into(),
|
||||
digits: Digits(1),
|
||||
},
|
||||
layout_tsk: GGLWETensorKeyLayout {
|
||||
n: n_glwe.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k_tsk.into(),
|
||||
rows: rows_tsk.into(),
|
||||
digits: Digits(1),
|
||||
rank: rank.into(),
|
||||
},
|
||||
};
|
||||
|
||||
let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
|
||||
n: n_glwe.into(),
|
||||
base2k: base2k.into(),
|
||||
k: k_ggsw_res.into(),
|
||||
rows: rows_ggsw_res.into(),
|
||||
digits: Digits(1),
|
||||
rank: rank.into(),
|
||||
};
|
||||
|
||||
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(1 << 23);
|
||||
|
||||
let mut source_xs: Source = Source::new([1u8; 32]);
|
||||
let mut source_xa: Source = Source::new([1u8; 32]);
|
||||
let mut source_xe: Source = Source::new([1u8; 32]);
|
||||
|
||||
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
|
||||
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe.into());
|
||||
sk_lwe.fill_binary_block(block_size, &mut source_xs);
|
||||
|
||||
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
|
||||
let mut sk_glwe: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n_glwe.into(), rank.into());
|
||||
sk_glwe.fill_ternary_prob(0.5, &mut source_xs);
|
||||
|
||||
let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow());
|
||||
|
||||
let data: i64 = 1;
|
||||
|
||||
let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe_pt);
|
||||
pt_lwe.encode_i64(data, k_lwe_pt + 1);
|
||||
let mut pt_lwe: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_with(base2k.into(), k_lwe_pt.into());
|
||||
pt_lwe.encode_i64(data, (k_lwe_pt + 1).into());
|
||||
|
||||
println!("pt_lwe: {}", pt_lwe);
|
||||
println!("pt_lwe: {pt_lwe}");
|
||||
|
||||
let mut ct_lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe_ct);
|
||||
let mut ct_lwe: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos);
|
||||
ct_lwe.encrypt_sk(module, &pt_lwe, &sk_lwe, &mut source_xa, &mut source_xe);
|
||||
|
||||
let now: Instant = Instant::now();
|
||||
let cbt_key: CircuitBootstrappingKey<Vec<u8>, BRA> = CircuitBootstrappingKey::encrypt_sk(
|
||||
module,
|
||||
basek,
|
||||
&sk_lwe,
|
||||
&sk_glwe,
|
||||
k_brk,
|
||||
rows_brk,
|
||||
k_trace,
|
||||
rows_trace,
|
||||
k_tsk,
|
||||
rows_tsk,
|
||||
&cbt_infos,
|
||||
&mut source_xa,
|
||||
&mut source_xe,
|
||||
scratch.borrow(),
|
||||
);
|
||||
println!("CBT-KGEN: {} ms", now.elapsed().as_millis());
|
||||
|
||||
let k_ggsw_res: usize = 4 * basek;
|
||||
let rows_ggsw_res: usize = 3;
|
||||
|
||||
let mut res: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw_res, rows_ggsw_res, 1, rank);
|
||||
let mut res: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos);
|
||||
|
||||
let cbt_prepared: CircuitBootstrappingKeyPrepared<Vec<u8>, BRA, B> = cbt_key.prepare_alloc(module, scratch.borrow());
|
||||
|
||||
@@ -369,16 +442,14 @@ where
|
||||
println!("CBT: {} ms", now.elapsed().as_millis());
|
||||
|
||||
// X^{data * 2^log_gap_out}
|
||||
let mut pt_ggsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
|
||||
let mut pt_ggsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n_glwe, 1);
|
||||
pt_ggsw.at_mut(0, 0)[0] = data;
|
||||
|
||||
res.print_noise(module, &sk_glwe_prepared, &pt_ggsw);
|
||||
|
||||
let k_glwe: usize = k_ggsw_res;
|
||||
|
||||
let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_glwe, rank);
|
||||
let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, basek);
|
||||
pt_glwe.data.at_mut(0, 0)[0] = 1 << (basek - k_lwe_pt - 1);
|
||||
let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&ggsw_infos);
|
||||
let mut pt_glwe: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ggsw_infos);
|
||||
pt_glwe.data.at_mut(0, 0)[0] = 1 << (base2k - k_lwe_pt - 1);
|
||||
|
||||
ct_glwe.encrypt_sk(
|
||||
module,
|
||||
@@ -393,7 +464,7 @@ where
|
||||
|
||||
ct_glwe.external_product_inplace(module, &res_prepared, scratch.borrow());
|
||||
|
||||
let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_glwe);
|
||||
let mut pt_res: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ggsw_infos);
|
||||
ct_glwe.decrypt(module, &mut pt_res, &sk_glwe_prepared, scratch.borrow());
|
||||
|
||||
// Parameters are set such that the first limb should be noiseless.
|
||||
|
||||
Reference in New Issue
Block a user