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:
Jean-Philippe Bossuat
2025-09-30 14:40:10 +02:00
committed by GitHub
parent 4da790ea6a
commit 37e13b965c
216 changed files with 12481 additions and 7745 deletions

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace,
VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes,
VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize,
VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace, VecZnxSubScalarInplace, VecZnxSwitchRing,
VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSubScalarInplace, VecZnxSwitchRing,
VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScratchOwned},
@@ -18,7 +18,7 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWEAutomorphismKey, GLWEPlaintext, GLWESecret, Infos,
GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWELayoutInfos, GLWEPlaintext, GLWESecret,
prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, Prepare, PrepareAlloc},
},
noise::log2_std_noise_gglwe_product,
@@ -47,7 +47,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxAddScalarInplace
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -67,40 +67,70 @@ where
+ TakeSvpPPolImpl<B>
+ TakeVecZnxBigImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_in: usize = 60;
let k_out: usize = 40;
let digits: usize = k_in.div_ceil(basek);
let p0 = -1;
let p1 = -5;
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_apply: usize = (digits + di) * basek;
let digits: usize = k_in.div_ceil(base2k);
let p0: i64 = -1;
let p1: i64 = -5;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_apply: usize = (digits + di) * base2k;
let n: usize = module.n();
let digits_in: usize = 1;
let rows_in: usize = k_in / (basek * di);
let rows_out: usize = k_out / (basek * di);
let rows_apply: usize = k_in.div_ceil(basek * di);
let rows_in: usize = k_in / (base2k * di);
let rows_out: usize = k_out / (base2k * di);
let rows_apply: usize = k_in.div_ceil(base2k * di);
let mut auto_key_in: GGLWEAutomorphismKey<Vec<u8>> =
GGLWEAutomorphismKey::alloc(n, basek, k_in, rows_in, digits_in, rank);
let mut auto_key_out: GGLWEAutomorphismKey<Vec<u8>> =
GGLWEAutomorphismKey::alloc(n, basek, k_out, rows_out, digits_in, rank);
let mut auto_key_apply: GGLWEAutomorphismKey<Vec<u8>> =
GGLWEAutomorphismKey::alloc(n, basek, k_apply, rows_apply, di, rank);
let auto_key_in_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
rows: rows_in.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let auto_key_out_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows_out.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let auto_key_apply_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_apply.into(),
rows: rows_apply.into(),
digits: di.into(),
rank: rank.into(),
};
let mut auto_key_in: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_in_infos);
let mut auto_key_out: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_out_infos);
let mut auto_key_apply: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_apply_infos);
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 scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, basek, k_apply, rank)
| GGLWEAutomorphismKey::automorphism_scratch_space(module, basek, k_out, k_in, k_apply, di, rank),
GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key_in_infos)
| GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key_apply_infos)
| GGLWEAutomorphismKey::automorphism_scratch_space(
module,
&auto_key_out_infos,
&auto_key_in_infos,
&auto_key_apply_infos,
),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&auto_key_in);
sk.fill_ternary_prob(0.5, &mut source_xs);
// gglwe_{s1}(s0) = s0 -> s1
@@ -124,7 +154,7 @@ where
);
let mut auto_key_apply_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> =
GGLWEAutomorphismKeyPrepared::alloc(module, basek, k_apply, rows_apply, di, rank);
GGLWEAutomorphismKeyPrepared::alloc(module, &auto_key_apply_infos);
auto_key_apply_prepared.prepare(module, &auto_key_apply, scratch.borrow());
@@ -136,11 +166,11 @@ where
scratch.borrow(),
);
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_out);
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&auto_key_out_infos);
let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(&auto_key_out_infos);
sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
(0..rank).for_each(|i| {
for i in 0..rank {
module.vec_znx_automorphism(
module.galois_element_inv(p0 * p1),
&mut sk_auto.data.as_vec_znx_mut(),
@@ -148,12 +178,12 @@ where
&sk.data.as_vec_znx(),
i,
);
});
}
let sk_auto_dft: GLWESecretPrepared<Vec<u8>, B> = sk_auto.prepare_alloc(module, scratch.borrow());
(0..auto_key_out.rank_in()).for_each(|col_i| {
(0..auto_key_out.rows()).for_each(|row_i| {
(0..auto_key_out.rank_in().into()).for_each(|col_i| {
(0..auto_key_out.rows().into()).for_each(|row_i| {
auto_key_out
.at(row_i, col_i)
.decrypt(module, &mut pt, &sk_auto_dft, scratch.borrow());
@@ -166,10 +196,10 @@ where
col_i,
);
let noise_have: f64 = pt.data.std(basek, 0).log2();
let noise_have: f64 = pt.data.std(base2k, 0).log2();
let noise_want: f64 = log2_std_noise_gglwe_product(
n as f64,
basek * di,
base2k * di,
0.5,
0.5,
0f64,
@@ -182,14 +212,13 @@ where
assert!(
noise_have < noise_want + 0.5,
"{} {}",
noise_have,
noise_want
"{noise_have} {}",
noise_want + 0.5
);
});
});
});
});
}
}
}
#[allow(clippy::too_many_arguments)]
@@ -202,7 +231,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -249,36 +278,53 @@ where
+ TakeSvpPPolImpl<B>
+ TakeVecZnxBigImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_in: usize = 60;
let digits: usize = k_in.div_ceil(basek);
let digits: usize = k_in.div_ceil(base2k);
let p0: i64 = -1;
let p1: i64 = -5;
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_apply: usize = (digits + di) * basek;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_apply: usize = (digits + di) * base2k;
let n: usize = module.n();
let digits_in: usize = 1;
let rows_in: usize = k_in / (basek * di);
let rows_apply: usize = k_in.div_ceil(basek * di);
let rows_in: usize = k_in / (base2k * di);
let rows_apply: usize = k_in.div_ceil(base2k * di);
let mut auto_key: GGLWEAutomorphismKey<Vec<u8>> =
GGLWEAutomorphismKey::alloc(n, basek, k_in, rows_in, digits_in, rank);
let mut auto_key_apply: GGLWEAutomorphismKey<Vec<u8>> =
GGLWEAutomorphismKey::alloc(n, basek, k_apply, rows_apply, di, rank);
let auto_key_layout: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
rows: rows_in.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let auto_key_apply_layout: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_apply.into(),
rows: rows_apply.into(),
digits: di.into(),
rank: rank.into(),
};
let mut auto_key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_layout);
let mut auto_key_apply: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_apply_layout);
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 scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, basek, k_apply, rank)
| GGLWEAutomorphismKey::automorphism_inplace_scratch_space(module, basek, k_in, k_apply, di, rank),
GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key)
| GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key_apply)
| GGLWEAutomorphismKey::automorphism_inplace_scratch_space(module, &auto_key, &auto_key_apply),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&auto_key);
sk.fill_ternary_prob(0.5, &mut source_xs);
// gglwe_{s1}(s0) = s0 -> s1
@@ -302,19 +348,19 @@ where
);
let mut auto_key_apply_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> =
GGLWEAutomorphismKeyPrepared::alloc(module, basek, k_apply, rows_apply, di, rank);
GGLWEAutomorphismKeyPrepared::alloc(module, &auto_key_apply_layout);
auto_key_apply_prepared.prepare(module, &auto_key_apply, scratch.borrow());
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
auto_key.automorphism_inplace(module, &auto_key_apply_prepared, scratch.borrow());
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_in);
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&auto_key);
let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc(&auto_key);
sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
(0..rank).for_each(|i| {
for i in 0..rank {
module.vec_znx_automorphism(
module.galois_element_inv(p0 * p1),
&mut sk_auto.data.as_vec_znx_mut(),
@@ -322,12 +368,12 @@ where
&sk.data.as_vec_znx(),
i,
);
});
}
let sk_auto_dft: GLWESecretPrepared<Vec<u8>, B> = sk_auto.prepare_alloc(module, scratch.borrow());
(0..auto_key.rank_in()).for_each(|col_i| {
(0..auto_key.rows()).for_each(|row_i| {
(0..auto_key.rank_in().into()).for_each(|col_i| {
(0..auto_key.rows().into()).for_each(|row_i| {
auto_key
.at(row_i, col_i)
.decrypt(module, &mut pt, &sk_auto_dft, scratch.borrow());
@@ -339,10 +385,10 @@ where
col_i,
);
let noise_have: f64 = pt.data.std(basek, 0).log2();
let noise_have: f64 = pt.data.std(base2k, 0).log2();
let noise_want: f64 = log2_std_noise_gglwe_product(
n as f64,
basek * di,
base2k * di,
0.5,
0.5,
0f64,
@@ -355,12 +401,11 @@ where
assert!(
noise_have < noise_want + 0.5,
"{} {}",
noise_have,
noise_want
"{noise_have} {}",
noise_want + 0.5
);
});
});
});
});
}
}
}

View File

@@ -5,7 +5,7 @@ use poulpy_hal::{
VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigNormalize,
VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAddInplace, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply,
VecZnxDftCopy, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScalarZnx, ScratchOwned},
@@ -19,13 +19,12 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWEAutomorphismKey, GGLWETensorKey, GGSWCiphertext, GLWESecret,
GGLWEAutomorphismKey, GGLWETensorKey, GGLWETensorKeyLayout, GGSWCiphertext, GGSWCiphertextLayout, GLWESecret,
prepared::{GGLWEAutomorphismKeyPrepared, GGLWETensorKeyPrepared, GLWESecretPrepared, Prepare, PrepareAlloc},
},
noise::noise_ggsw_keyswitch,
};
#[allow(clippy::too_many_arguments)]
pub fn test_ggsw_automorphism<B>(module: &Module<B>)
where
Module<B>: VecZnxDftAllocBytes
@@ -46,7 +45,7 @@ where
+ SvpPPolAlloc<B>
+ VecZnxAddScalarInplace
+ VecZnxCopy
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VmpPMatAlloc<B>
+ VmpPrepare<B>
+ VmpApplyDftToDftTmpBytes
@@ -76,26 +75,63 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_in: usize = 54;
let digits: usize = k_in.div_ceil(basek);
let digits: usize = k_in.div_ceil(base2k);
let p: i64 = -5;
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_in + basek * di;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_ksk: usize = k_in + base2k * di;
let k_tsk: usize = k_ksk;
let k_out: usize = k_ksk; // Better capture noise.
let n: usize = module.n();
let rows: usize = k_in.div_ceil(basek * di);
let rows_in: usize = k_in.div_euclid(basek * di);
let rows: usize = k_in.div_ceil(base2k * di);
let rows_in: usize = k_in.div_euclid(base2k * di);
let digits_in: usize = 1;
let mut ct_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_in, rows_in, digits_in, rank);
let mut ct_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_out, rows_in, digits_in, rank);
let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(n, basek, k_tsk, rows, di, rank);
let mut auto_key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_ksk, rows, di, rank);
let ggsw_in_layout: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
rows: rows_in.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let ggsw_out_layout: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows_in.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let tensor_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_tsk.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let auto_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let mut ct_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_in_layout);
let mut ct_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_layout);
let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tensor_key_layout);
let mut auto_key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_layout);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
@@ -103,15 +139,15 @@ where
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_in, rank)
| GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank)
| GGLWETensorKey::encrypt_sk_scratch_space(module, basek, k_tsk, rank)
| GGSWCiphertext::automorphism_scratch_space(module, basek, k_out, k_in, k_ksk, di, k_tsk, di, rank),
GGSWCiphertext::encrypt_sk_scratch_space(module, &ct_in)
| GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key)
| GGLWETensorKey::encrypt_sk_scratch_space(module, &tensor_key)
| GGSWCiphertext::automorphism_scratch_space(module, &ct_out, &ct_in, &auto_key, &tensor_key),
);
let var_xs: f64 = 0.5;
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ct_out);
sk.fill_ternary_prob(var_xs, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
@@ -143,11 +179,10 @@ where
);
let mut auto_key_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> =
GGLWEAutomorphismKeyPrepared::alloc(module, basek, k_ksk, rows, di, rank);
GGLWEAutomorphismKeyPrepared::alloc(module, &auto_key_layout);
auto_key_prepared.prepare(module, &auto_key, scratch.borrow());
let mut tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> =
GGLWETensorKeyPrepared::alloc(module, basek, k_tsk, rows, di, rank);
let mut tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = GGLWETensorKeyPrepared::alloc(module, &tensor_key_layout);
tsk_prepared.prepare(module, &tensor_key, scratch.borrow());
ct_out.automorphism(
@@ -163,7 +198,7 @@ where
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
n as f64,
basek * di,
base2k * di,
col_j,
var_xs,
0f64,
@@ -177,8 +212,8 @@ where
};
ct_out.assert_noise(module, &sk_prepared, &pt_scalar, max_noise);
});
});
}
}
}
#[allow(clippy::too_many_arguments)]
@@ -202,7 +237,7 @@ where
+ SvpPPolAlloc<B>
+ VecZnxAddScalarInplace
+ VecZnxCopy
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VmpPMatAlloc<B>
+ VmpPrepare<B>
+ VmpApplyDftToDftTmpBytes
@@ -233,23 +268,50 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 12;
let k_ct: usize = 54;
let digits: usize = k_ct.div_ceil(basek);
let p = -1;
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_ct + basek * di;
let base2k: usize = 12;
let k_out: usize = 54;
let digits: usize = k_out.div_ceil(base2k);
let p: i64 = -1;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_ksk: usize = k_out + base2k * di;
let k_tsk: usize = k_ksk;
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(di * basek);
let rows_in: usize = k_ct.div_euclid(basek * di);
let rows: usize = k_out.div_ceil(di * base2k);
let rows_in: usize = k_out.div_euclid(base2k * di);
let digits_in: usize = 1;
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ct, rows_in, digits_in, rank);
let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(n, basek, k_tsk, rows, di, rank);
let mut auto_key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_ksk, rows, di, rank);
let ggsw_out_layout: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows_in.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let tensor_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_tsk.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let auto_key_layout: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_layout);
let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tensor_key_layout);
let mut auto_key: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&auto_key_layout);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
@@ -257,15 +319,15 @@ where
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_ct, rank)
| GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank)
| GGLWETensorKey::encrypt_sk_scratch_space(module, basek, k_tsk, rank)
| GGSWCiphertext::automorphism_inplace_scratch_space(module, basek, k_ct, k_ksk, di, k_tsk, di, rank),
GGSWCiphertext::encrypt_sk_scratch_space(module, &ct)
| GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &auto_key)
| GGLWETensorKey::encrypt_sk_scratch_space(module, &tensor_key)
| GGSWCiphertext::automorphism_inplace_scratch_space(module, &ct, &auto_key, &tensor_key),
);
let var_xs: f64 = 0.5;
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ct);
sk.fill_ternary_prob(var_xs, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
@@ -297,11 +359,10 @@ where
);
let mut auto_key_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> =
GGLWEAutomorphismKeyPrepared::alloc(module, basek, k_ksk, rows, di, rank);
GGLWEAutomorphismKeyPrepared::alloc(module, &auto_key_layout);
auto_key_prepared.prepare(module, &auto_key, scratch.borrow());
let mut tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> =
GGLWETensorKeyPrepared::alloc(module, basek, k_tsk, rows, di, rank);
let mut tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = GGLWETensorKeyPrepared::alloc(module, &tensor_key_layout);
tsk_prepared.prepare(module, &tensor_key, scratch.borrow());
ct.automorphism_inplace(module, &auto_key_prepared, &tsk_prepared, scratch.borrow());
@@ -311,20 +372,20 @@ where
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
n as f64,
basek * di,
base2k * di,
col_j,
var_xs,
0f64,
SIGMA * SIGMA,
0f64,
rank as f64,
k_ct,
k_out,
k_ksk,
k_tsk,
) + 0.5
};
ct.assert_noise(module, &sk_prepared, &pt_scalar, max_noise);
});
});
}
}
}

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace,
VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes,
VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScratchOwned},
@@ -18,13 +18,12 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos,
GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret,
prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, Prepare, PrepareAlloc},
},
noise::log2_std_noise_gglwe_product,
};
#[allow(clippy::too_many_arguments)]
pub fn test_glwe_automorphism<B>(module: &Module<B>)
where
Module<B>: VecZnxDftAllocBytes
@@ -34,7 +33,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -66,45 +65,60 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_in: usize = 60;
let digits: usize = k_in.div_ceil(basek);
let digits: usize = k_in.div_ceil(base2k);
let p: i64 = -5;
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_in + basek * di;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_ksk: usize = k_in + base2k * di;
let k_out: usize = k_ksk; // Better capture noise.
let n: usize = module.n();
let rows: usize = k_in.div_ceil(basek * digits);
let rows: usize = k_in.div_ceil(base2k * digits);
let mut autokey: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_ksk, rows, digits, rank);
let mut ct_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_in, rank);
let mut ct_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_out, rank);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_in);
let ct_in_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
rank: rank.into(),
};
let ct_out_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rank: rank.into(),
};
let autokey_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rank: rank.into(),
rows: rows.into(),
digits: di.into(),
};
let mut autokey: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&autokey_infos);
let mut ct_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&ct_in_infos);
let mut ct_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&ct_out_infos);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ct_out_infos);
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]);
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, basek, autokey.k(), rank)
| GLWECiphertext::decrypt_scratch_space(module, basek, ct_out.k())
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct_in.k())
| GLWECiphertext::automorphism_scratch_space(
module,
basek,
ct_out.k(),
ct_in.k(),
autokey.k(),
digits,
rank,
),
GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &autokey)
| GLWECiphertext::decrypt_scratch_space(module, &ct_out)
| GLWECiphertext::encrypt_sk_scratch_space(module, &ct_in)
| GLWECiphertext::automorphism_scratch_space(module, &ct_out, &ct_in, &autokey),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ct_out);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
@@ -127,14 +141,14 @@ where
);
let mut autokey_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> =
GGLWEAutomorphismKeyPrepared::alloc(module, basek, k_ksk, rows, digits, rank);
GGLWEAutomorphismKeyPrepared::alloc(module, &autokey_infos);
autokey_prepared.prepare(module, &autokey, scratch.borrow());
ct_out.automorphism(module, &ct_in, &autokey_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product(
module.n() as f64,
basek * digits,
base2k * digits,
0.5,
0.5,
0f64,
@@ -148,8 +162,8 @@ where
module.vec_znx_automorphism_inplace(p, &mut pt_want.data, 0, scratch.borrow());
ct_out.assert_noise(module, &sk_prepared, &pt_want, max_noise + 1.0);
})
});
}
}
}
#[allow(clippy::too_many_arguments)]
@@ -162,7 +176,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -194,35 +208,51 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 12;
let k_ct: usize = 60;
let digits: usize = k_ct.div_ceil(basek);
let base2k: usize = 12;
let k_out: usize = 60;
let digits: usize = k_out.div_ceil(base2k);
let p = -5;
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_ct + basek * di;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_ksk: usize = k_out + base2k * di;
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(basek * digits);
let rows: usize = k_out.div_ceil(base2k * digits);
let mut autokey: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_ksk, rows, digits, rank);
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
let ct_out_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rank: rank.into(),
};
let autokey_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rank: rank.into(),
rows: rows.into(),
digits: di.into(),
};
let mut autokey: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&autokey_infos);
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&ct_out_infos);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&ct_out_infos);
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]);
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, basek, autokey.k(), rank)
| GLWECiphertext::decrypt_scratch_space(module, basek, ct.k())
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct.k())
| GLWECiphertext::automorphism_inplace_scratch_space(module, basek, ct.k(), autokey.k(), digits, rank),
GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &autokey)
| GLWECiphertext::decrypt_scratch_space(module, &ct)
| GLWECiphertext::encrypt_sk_scratch_space(module, &ct)
| GLWECiphertext::automorphism_inplace_scratch_space(module, &ct, &autokey),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ct);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
@@ -245,27 +275,27 @@ where
);
let mut autokey_prepared: GGLWEAutomorphismKeyPrepared<Vec<u8>, B> =
GGLWEAutomorphismKeyPrepared::alloc(module, basek, k_ksk, rows, digits, rank);
GGLWEAutomorphismKeyPrepared::alloc(module, &autokey);
autokey_prepared.prepare(module, &autokey, scratch.borrow());
ct.automorphism_inplace(module, &autokey_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product(
module.n() as f64,
basek * digits,
base2k * digits,
0.5,
0.5,
0f64,
SIGMA * SIGMA,
0f64,
rank as f64,
k_ct,
k_out,
k_ksk,
);
module.vec_znx_automorphism_inplace(p, &mut pt_want.data, 0, scratch.borrow());
ct.assert_noise(module, &sk_prepared, &pt_want, max_noise + 1.0);
});
});
}
}
}

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphismInplace, VecZnxBigAddInplace,
VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAllocBytes,
VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, ZnAddNormal, ZnFillUniform, ZnNormalizeInplace,
},
layouts::{Backend, Module, ScratchOwned, ZnxView},
@@ -16,8 +16,9 @@ use poulpy_hal::{
};
use crate::layouts::{
GLWECiphertext, GLWEPlaintext, GLWESecret, GLWEToLWESwitchingKey, Infos, LWECiphertext, LWEPlaintext, LWESecret,
LWEToGLWESwitchingKey,
Base2K, Degree, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret, GLWEToLWESwitchingKey,
GLWEToLWESwitchingKeyLayout, LWECiphertext, LWECiphertextLayout, LWEPlaintext, LWESecret, LWEToGLWESwitchingKey,
LWEToGLWESwitchingKeyLayout, Rank, Rows, TorusPrecision,
prepared::{GLWESecretPrepared, GLWEToLWESwitchingKeyPrepared, LWEToGLWESwitchingKeyPrepared, PrepareAlloc},
};
@@ -29,7 +30,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -64,30 +65,44 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let n: usize = module.n();
let basek: usize = 17;
let n_glwe: Degree = Degree(module.n() as u32);
let n_lwe: Degree = Degree(22);
let rank: usize = 2;
let n_lwe: usize = 22;
let k_lwe_ct: usize = 2 * basek;
let k_lwe_pt: usize = 8;
let k_glwe_ct: usize = 3 * basek;
let k_ksk: usize = k_lwe_ct + basek;
let rank: Rank = Rank(2);
let k_lwe_pt: TorusPrecision = TorusPrecision(8);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let lwe_to_glwe_infos: LWEToGLWESwitchingKeyLayout = LWEToGLWESwitchingKeyLayout {
n: n_glwe,
base2k: Base2K(17),
k: TorusPrecision(51),
rows: Rows(2),
rank_out: rank,
};
let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n_glwe,
base2k: Base2K(17),
k: TorusPrecision(34),
rank,
};
let lwe_infos: LWECiphertextLayout = LWECiphertextLayout {
n: n_lwe,
base2k: Base2K(17),
k: TorusPrecision(34),
};
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
LWEToGLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank)
| GLWECiphertext::from_lwe_scratch_space(module, basek, k_lwe_ct, k_glwe_ct, k_ksk, rank)
| GLWECiphertext::decrypt_scratch_space(module, basek, k_glwe_ct),
LWEToGLWESwitchingKey::encrypt_sk_scratch_space(module, &lwe_to_glwe_infos)
| GLWECiphertext::from_lwe_scratch_space(module, &glwe_infos, &lwe_infos, &lwe_to_glwe_infos)
| GLWECiphertext::decrypt_scratch_space(module, &glwe_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_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow());
@@ -97,13 +112,13 @@ where
let data: i64 = 17;
let mut lwe_pt: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe_pt);
let mut lwe_pt: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(&lwe_infos);
lwe_pt.encode_i64(data, k_lwe_pt);
let mut lwe_ct: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe_ct);
let mut lwe_ct: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos);
lwe_ct.encrypt_sk(module, &lwe_pt, &sk_lwe, &mut source_xa, &mut source_xe);
let mut ksk: LWEToGLWESwitchingKey<Vec<u8>> = LWEToGLWESwitchingKey::alloc(n, basek, k_ksk, lwe_ct.size(), rank);
let mut ksk: LWEToGLWESwitchingKey<Vec<u8>> = LWEToGLWESwitchingKey::alloc(&lwe_to_glwe_infos);
ksk.encrypt_sk(
module,
@@ -114,13 +129,13 @@ where
scratch.borrow(),
);
let mut glwe_ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_glwe_ct, rank);
let mut glwe_ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos);
let ksk_prepared: LWEToGLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow());
glwe_ct.from_lwe(module, &lwe_ct, &ksk_prepared, scratch.borrow());
let mut glwe_pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_glwe_ct);
let mut glwe_pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos);
glwe_ct.decrypt(module, &mut glwe_pt, &sk_glwe_prepared, scratch.borrow());
assert_eq!(glwe_pt.data.at(0, 0)[0], lwe_pt.data.at(0, 0)[0]);
@@ -134,7 +149,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -167,42 +182,56 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let n: usize = module.n();
let basek: usize = 17;
let n_glwe: Degree = Degree(module.n() as u32);
let n_lwe: Degree = Degree(22);
let rank: usize = 2;
let rank: Rank = Rank(2);
let k_lwe_pt: TorusPrecision = TorusPrecision(8);
let n_lwe: usize = 22;
let k_lwe_ct: usize = 2 * basek;
let k_lwe_pt: usize = 8;
let glwe_to_lwe_infos: GLWEToLWESwitchingKeyLayout = GLWEToLWESwitchingKeyLayout {
n: n_glwe,
base2k: Base2K(17),
k: TorusPrecision(51),
rows: Rows(2),
rank_in: rank,
};
let k_glwe_ct: usize = 3 * basek;
let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n_glwe,
base2k: Base2K(17),
k: TorusPrecision(34),
rank,
};
let k_ksk: usize = k_lwe_ct + basek;
let lwe_infos: LWECiphertextLayout = LWECiphertextLayout {
n: n_lwe,
base2k: Base2K(17),
k: TorusPrecision(34),
};
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
LWEToGLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank)
| LWECiphertext::from_glwe_scratch_space(module, basek, k_lwe_ct, k_glwe_ct, k_ksk, rank)
| GLWECiphertext::decrypt_scratch_space(module, basek, k_glwe_ct),
GLWEToLWESwitchingKey::encrypt_sk_scratch_space(module, &glwe_to_lwe_infos)
| LWECiphertext::from_glwe_scratch_space(module, &lwe_infos, &glwe_infos, &glwe_to_lwe_infos)
| GLWECiphertext::decrypt_scratch_space(module, &glwe_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_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_glwe.prepare_alloc(module, scratch.borrow());
let mut sk_lwe = LWESecret::alloc(n_lwe);
let mut sk_lwe: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe);
sk_lwe.fill_ternary_prob(0.5, &mut source_xs);
let data: i64 = 17;
let mut glwe_pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_glwe_ct);
let mut glwe_pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos);
glwe_pt.encode_coeff_i64(data, k_lwe_pt, 0);
let mut glwe_ct = GLWECiphertext::alloc(n, basek, k_glwe_ct, rank);
let mut glwe_ct = GLWECiphertext::alloc(&glwe_infos);
glwe_ct.encrypt_sk(
module,
&glwe_pt,
@@ -212,7 +241,7 @@ where
scratch.borrow(),
);
let mut ksk: GLWEToLWESwitchingKey<Vec<u8>> = GLWEToLWESwitchingKey::alloc(n, basek, k_ksk, glwe_ct.size(), rank);
let mut ksk: GLWEToLWESwitchingKey<Vec<u8>> = GLWEToLWESwitchingKey::alloc(&glwe_to_lwe_infos);
ksk.encrypt_sk(
module,
@@ -223,13 +252,13 @@ where
scratch.borrow(),
);
let mut lwe_ct: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe, basek, k_lwe_ct);
let mut lwe_ct: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_infos);
let ksk_prepared: GLWEToLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow());
lwe_ct.from_glwe(module, &glwe_ct, &ksk_prepared, scratch.borrow());
let mut lwe_pt: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe_ct);
let mut lwe_pt: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(&lwe_infos);
lwe_ct.decrypt(module, &mut lwe_pt, &sk_lwe);
assert_eq!(glwe_pt.data.at(0, 0)[0], lwe_pt.data.at(0, 0)[0]);

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace,
VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes,
VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize,
VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace, VecZnxSubScalarInplace, VecZnxSwitchRing,
VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSubScalarInplace, VecZnxSwitchRing,
VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScratchOwned},
@@ -18,7 +18,7 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWEAutomorphismKey, GLWESecret,
GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GLWEInfos, GLWESecret,
compressed::{Decompress, GGLWEAutomorphismKeyCompressed},
prepared::{GLWESecretPrepared, PrepareAlloc},
},
@@ -33,7 +33,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -67,25 +67,34 @@ where
+ TakeSvpPPolImpl<B>
+ TakeVecZnxBigImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_ksk: usize = 60;
let digits: usize = k_ksk.div_ceil(basek) - 1;
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let digits: usize = k_ksk.div_ceil(base2k) - 1;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let n: usize = module.n();
let rows: usize = (k_ksk - di * basek) / (di * basek);
let rows: usize = (k_ksk - di * base2k) / (di * base2k);
let mut atk: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_ksk, rows, di, rank);
let atk_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let mut atk: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&atk_infos);
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 scratch: ScratchOwned<B> = ScratchOwned::alloc(GGLWEAutomorphismKey::encrypt_sk_scratch_space(
module, basek, k_ksk, rank,
module, &atk_infos,
));
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&atk_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let p = -5;
@@ -100,7 +109,7 @@ where
);
let mut sk_out: GLWESecret<Vec<u8>> = sk.clone();
(0..atk.rank()).for_each(|i| {
(0..atk.rank().into()).for_each(|i| {
module.vec_znx_automorphism(
module.galois_element_inv(p),
&mut sk_out.data.as_vec_znx_mut(),
@@ -114,8 +123,8 @@ where
atk.key
.key
.assert_noise(module, &sk_out_prepared, &sk.data, SIGMA);
});
});
}
}
}
pub fn test_gglwe_automorphisk_key_compressed_encrypt_sk<B>(module: &Module<B>)
@@ -127,7 +136,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -161,25 +170,33 @@ where
+ TakeSvpPPolImpl<B>
+ TakeVecZnxBigImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_ksk: usize = 60;
let digits: usize = k_ksk.div_ceil(basek) - 1;
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let digits: usize = k_ksk.div_ceil(base2k) - 1;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let n: usize = module.n();
let rows: usize = (k_ksk - di * basek) / (di * basek);
let rows: usize = (k_ksk - di * base2k) / (di * base2k);
let mut atk_compressed: GGLWEAutomorphismKeyCompressed<Vec<u8>> =
GGLWEAutomorphismKeyCompressed::alloc(n, basek, k_ksk, rows, di, rank);
let atk_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let mut atk_compressed: GGLWEAutomorphismKeyCompressed<Vec<u8>> = GGLWEAutomorphismKeyCompressed::alloc(&atk_infos);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGLWEAutomorphismKey::encrypt_sk_scratch_space(
module, basek, k_ksk, rank,
module, &atk_infos,
));
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&atk_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let p = -5;
@@ -189,7 +206,7 @@ where
atk_compressed.encrypt_sk(module, p, &sk, seed_xa, &mut source_xe, scratch.borrow());
let mut sk_out: GLWESecret<Vec<u8>> = sk.clone();
(0..atk_compressed.rank()).for_each(|i| {
(0..atk_compressed.rank().into()).for_each(|i| {
module.vec_znx_automorphism(
module.galois_element_inv(p),
&mut sk_out.data.as_vec_znx_mut(),
@@ -200,12 +217,12 @@ where
});
let sk_out_prepared = sk_out.prepare_alloc(module, scratch.borrow());
let mut atk: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_ksk, rows, di, rank);
let mut atk: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&atk_infos);
atk.decompress(module, &atk_compressed);
atk.key
.key
.assert_noise(module, &sk_out_prepared, &sk.data, SIGMA);
});
});
}
}
}

View File

@@ -3,7 +3,7 @@ use poulpy_hal::{
ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare,
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace,
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform,
VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace,
VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace,
VecZnxSubScalarInplace, VecZnxSwitchRing, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScratchOwned},
@@ -17,7 +17,7 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWESwitchingKey, GLWESecret,
GGLWECiphertextLayout, GGLWESwitchingKey, GLWESecret,
compressed::{Decompress, GGLWESwitchingKeyCompressed},
prepared::{GLWESecretPrepared, PrepareAlloc},
},
@@ -32,7 +32,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -62,29 +62,40 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_ksk: usize = 54;
let digits: usize = k_ksk / basek;
(1..3).for_each(|rank_in| {
(1..3).for_each(|rank_out| {
(1..digits + 1).for_each(|di| {
let digits: usize = k_ksk / base2k;
for rank_in in 1_usize..3 {
for rank_out in 1_usize..3 {
for di in 1_usize..digits + 1 {
let n: usize = module.n();
let rows: usize = (k_ksk - di * basek) / (di * basek);
let rows: usize = (k_ksk - di * base2k) / (di * base2k);
let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(n, basek, k_ksk, rows, di, rank_in, rank_out);
let gglwe_infos: GGLWECiphertextLayout = GGLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank_in: rank_in.into(),
rank_out: rank_out.into(),
};
let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_infos);
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 scratch: ScratchOwned<B> = ScratchOwned::alloc(GGLWESwitchingKey::encrypt_sk_scratch_space(
module, basek, k_ksk, rank_in, rank_out,
module,
&gglwe_infos,
));
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_in);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into());
sk_in.fill_ternary_prob(0.5, &mut source_xs);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_out);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into());
sk_out.fill_ternary_prob(0.5, &mut source_xs);
let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow());
@@ -99,9 +110,9 @@ where
ksk.key
.assert_noise(module, &sk_out_prepared, &sk_in.data, SIGMA);
});
});
});
}
}
}
}
pub fn test_gglwe_switching_key_compressed_encrypt_sk<B>(module: &Module<B>)
@@ -113,7 +124,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -143,29 +154,39 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_ksk: usize = 54;
let digits: usize = k_ksk / basek;
(1..3).for_each(|rank_in| {
(1..3).for_each(|rank_out| {
(1..digits + 1).for_each(|di| {
let digits: usize = k_ksk / base2k;
for rank_in in 1_usize..3 {
for rank_out in 1_usize..3 {
for di in 1_usize..digits + 1 {
let n: usize = module.n();
let rows: usize = (k_ksk - di * basek) / (di * basek);
let rows: usize = (k_ksk - di * base2k) / (di * base2k);
let mut ksk_compressed: GGLWESwitchingKeyCompressed<Vec<u8>> =
GGLWESwitchingKeyCompressed::alloc(n, basek, k_ksk, rows, di, rank_in, rank_out);
let gglwe_infos: GGLWECiphertextLayout = GGLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank_in: rank_in.into(),
rank_out: rank_out.into(),
};
let mut ksk_compressed: GGLWESwitchingKeyCompressed<Vec<u8>> = GGLWESwitchingKeyCompressed::alloc(&gglwe_infos);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGLWESwitchingKeyCompressed::encrypt_sk_scratch_space(
module, basek, k_ksk, rank_in, rank_out,
module,
&gglwe_infos,
));
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_in);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into());
sk_in.fill_ternary_prob(0.5, &mut source_xs);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_out);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into());
sk_out.fill_ternary_prob(0.5, &mut source_xs);
let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow());
@@ -180,12 +201,12 @@ where
scratch.borrow(),
);
let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(n, basek, k_ksk, rows, di, rank_in, rank_out);
let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_infos);
ksk.decompress(module, &ksk_compressed);
ksk.key
.assert_noise(module, &sk_out_prepared, &sk_in.data, SIGMA);
});
});
});
}
}
}
}

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc,
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAlloc, VecZnxDftAllocBytes,
VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace, VmpPMatAlloc, VmpPrepare,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScalarZnx, ScratchOwned},
oep::{
@@ -17,7 +17,7 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGSWCiphertext, GLWESecret,
GGSWCiphertext, GGSWCiphertextLayout, GLWESecret,
compressed::{Decompress, GGSWCiphertextCompressed},
prepared::{GLWESecretPrepared, PrepareAlloc},
},
@@ -32,7 +32,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -65,15 +65,24 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k: usize = 54;
let digits: usize = k / basek;
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let digits: usize = k / base2k;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let n: usize = module.n();
let rows: usize = (k - di * basek) / (di * basek);
let rows: usize = (k - di * base2k) / (di * base2k);
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k, rows, di, rank);
let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
@@ -84,10 +93,11 @@ where
pt_scalar.fill_ternary_hw(0, n, &mut source_xs);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGSWCiphertext::encrypt_sk_scratch_space(
module, basek, k, rank,
module,
&ggsw_infos,
));
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ggsw_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
@@ -103,8 +113,8 @@ where
let noise_f = |_col_i: usize| -(k as f64) + SIGMA.log2() + 0.5;
ct.assert_noise(module, &sk_prepared, &pt_scalar, noise_f);
});
});
}
}
}
pub fn test_ggsw_compressed_encrypt_sk<B>(module: &Module<B>)
@@ -116,7 +126,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -148,16 +158,24 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k: usize = 54;
let digits: usize = k / basek;
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let digits: usize = k / base2k;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let n: usize = module.n();
let rows: usize = (k - di * basek) / (di * basek);
let rows: usize = (k - di * base2k) / (di * base2k);
let mut ct_compressed: GGSWCiphertextCompressed<Vec<u8>> =
GGSWCiphertextCompressed::alloc(n, basek, k, rows, di, rank);
let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let mut ct_compressed: GGSWCiphertextCompressed<Vec<u8>> = GGSWCiphertextCompressed::alloc(&ggsw_infos);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
@@ -167,10 +185,11 @@ where
pt_scalar.fill_ternary_hw(0, n, &mut source_xs);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGSWCiphertextCompressed::encrypt_sk_scratch_space(
module, basek, k, rank,
module,
&ggsw_infos,
));
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&ggsw_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
@@ -187,10 +206,10 @@ where
let noise_f = |_col_i: usize| -(k as f64) + SIGMA.log2() + 0.5;
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k, rows, di, rank);
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos);
ct.decompress(module, &ct_compressed);
ct.assert_noise(module, &sk_prepared, &pt_scalar, noise_f);
});
});
}
}
}

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxBigAddInplace, VecZnxBigAddNormal, VecZnxBigAddSmallInplace,
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxCopy, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply,
VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub,
VecZnxSubABInplace,
VecZnxSubInplace,
},
layouts::{Backend, Module, ScratchOwned},
oep::{
@@ -17,7 +17,7 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GLWECiphertext, GLWEPlaintext, GLWEPublicKey, GLWESecret, Infos,
GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWEPlaintextLayout, GLWEPublicKey, GLWESecret, LWEInfos,
compressed::{Decompress, GLWECiphertextCompressed},
prepared::{GLWEPublicKeyPrepared, GLWESecretPrepared, PrepareAlloc},
},
@@ -38,24 +38,10 @@ where
+ SvpPrepare<B>
+ SvpPPolAllocBytes
+ SvpPPolAlloc<B>
+ VecZnxDftAllocBytes
+ VecZnxBigAllocBytes
+ SvpPPolAllocBytes
+ SvpPrepare<B>
+ SvpApplyDftToDft<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxBigAddNormal<B>
+ VecZnxBigAddSmallInplace<B>
+ VecZnxBigNormalize<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxDftAllocBytes
+ VecZnxBigNormalize<B>
+ VecZnxDftApply<B>
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -71,30 +57,44 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 8;
let base2k: usize = 8;
let k_ct: usize = 54;
let k_pt: usize = 30;
for rank in 1..3 {
let n = module.n();
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
for rank in 1_usize..3 {
let n: usize = module.n();
let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ct.into(),
rank: rank.into(),
};
let pt_infos: GLWEPlaintextLayout = GLWEPlaintextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_pt.into(),
};
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&pt_infos);
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&pt_infos);
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 scratch: ScratchOwned<B> = ScratchOwned::alloc(
GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct.k())
| GLWECiphertext::decrypt_scratch_space(module, basek, ct.k()),
GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_infos)
| GLWECiphertext::decrypt_scratch_space(module, &glwe_infos),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
ct.encrypt_sk(
module,
@@ -109,7 +109,7 @@ where
pt_want.sub_inplace_ab(module, &pt_have);
let noise_have: f64 = pt_want.data.std(basek, 0) * (ct.k() as f64).exp2();
let noise_have: f64 = pt_want.data.std(base2k, 0) * (ct.k().as_u32() as f64).exp2();
let noise_want: f64 = SIGMA;
assert!(noise_have <= noise_want + 0.2);
@@ -130,24 +130,10 @@ where
+ SvpPrepare<B>
+ SvpPPolAllocBytes
+ SvpPPolAlloc<B>
+ VecZnxDftAllocBytes
+ VecZnxBigAllocBytes
+ SvpPPolAllocBytes
+ SvpPrepare<B>
+ SvpApplyDftToDft<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxBigAddNormal<B>
+ VecZnxBigAddSmallInplace<B>
+ VecZnxBigNormalize<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxDftAllocBytes
+ VecZnxBigNormalize<B>
+ VecZnxDftApply<B>
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -164,31 +150,45 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 8;
let base2k: usize = 8;
let k_ct: usize = 54;
let k_pt: usize = 30;
for rank in 1..3 {
let n = module.n();
let mut ct_compressed: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(n, basek, k_ct, rank);
for rank in 1_usize..3 {
let n: usize = module.n();
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_pt);
let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ct.into(),
rank: rank.into(),
};
let pt_infos: GLWEPlaintextLayout = GLWEPlaintextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_pt.into(),
};
let mut ct_compressed: GLWECiphertextCompressed<Vec<u8>> = GLWECiphertextCompressed::alloc(&glwe_infos);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&pt_infos);
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&pt_infos);
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 scratch: ScratchOwned<B> = ScratchOwned::alloc(
GLWECiphertextCompressed::encrypt_sk_scratch_space(module, basek, k_ct)
| GLWECiphertext::decrypt_scratch_space(module, basek, k_ct),
GLWECiphertextCompressed::encrypt_sk_scratch_space(module, &glwe_infos)
| GLWECiphertext::decrypt_scratch_space(module, &glwe_infos),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
let seed_xa: [u8; 32] = [1u8; 32];
@@ -201,20 +201,19 @@ where
scratch.borrow(),
);
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos);
ct.decompress(module, &ct_compressed);
ct.decrypt(module, &mut pt_have, &sk_prepared, scratch.borrow());
pt_want.sub_inplace_ab(module, &pt_have);
let noise_have: f64 = pt_want.data.std(basek, 0) * (ct.k() as f64).exp2();
let noise_have: f64 = pt_want.data.std(base2k, 0) * (ct.k().as_u32() as f64).exp2();
let noise_want: f64 = SIGMA;
assert!(
noise_have <= noise_want + 0.2,
"{} <= {}",
noise_have,
"{noise_have} <= {}",
noise_want + 0.2
);
}
@@ -234,24 +233,10 @@ where
+ SvpPrepare<B>
+ SvpPPolAllocBytes
+ SvpPPolAlloc<B>
+ VecZnxDftAllocBytes
+ VecZnxBigAllocBytes
+ SvpPPolAllocBytes
+ SvpPrepare<B>
+ SvpApplyDftToDft<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxBigAddNormal<B>
+ VecZnxBigAddSmallInplace<B>
+ VecZnxBigNormalize<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxDftAllocBytes
+ VecZnxBigNormalize<B>
+ VecZnxDftApply<B>
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -267,27 +252,35 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 8;
let base2k: usize = 8;
let k_ct: usize = 54;
for rank in 1..3 {
let n = module.n();
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
for rank in 1_usize..3 {
let n: usize = module.n();
let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ct.into(),
rank: rank.into(),
};
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([1u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GLWECiphertext::decrypt_scratch_space(module, basek, k_ct)
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, k_ct),
GLWECiphertext::decrypt_scratch_space(module, &glwe_infos)
| GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_infos),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos);
ct.encrypt_zero_sk(
module,
@@ -298,7 +291,7 @@ where
);
ct.decrypt(module, &mut pt, &sk_prepared, scratch.borrow());
assert!((SIGMA - pt.data.std(basek, 0) * (k_ct as f64).exp2()) <= 0.2);
assert!((SIGMA - pt.data.std(base2k, 0) * (k_ct as f64).exp2()) <= 0.2);
}
}
@@ -311,7 +304,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -337,15 +330,22 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 8;
let base2k: usize = 8;
let k_ct: usize = 54;
let k_pk: usize = 54;
for rank in 1..3 {
for rank in 1_usize..3 {
let n: usize = module.n();
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
let glwe_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ct.into(),
rank: rank.into(),
};
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_infos);
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_infos);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
@@ -353,19 +353,19 @@ where
let mut source_xu: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct.k())
| GLWECiphertext::decrypt_scratch_space(module, basek, ct.k())
| GLWECiphertext::encrypt_pk_scratch_space(module, basek, k_pk),
GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_infos)
| GLWECiphertext::decrypt_scratch_space(module, &glwe_infos)
| GLWECiphertext::encrypt_pk_scratch_space(module, &glwe_infos),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
let mut pk: GLWEPublicKey<Vec<u8>> = GLWEPublicKey::alloc(n, basek, k_pk, rank);
let mut pk: GLWEPublicKey<Vec<u8>> = GLWEPublicKey::alloc(&glwe_infos);
pk.generate_from_sk(module, &sk_prepared, &mut source_xa, &mut source_xe);
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
let pk_prepared: GLWEPublicKeyPrepared<Vec<u8>, B> = pk.prepare_alloc(module, scratch.borrow());
@@ -382,14 +382,13 @@ where
pt_want.sub_inplace_ab(module, &pt_have);
let noise_have: f64 = pt_want.data.std(basek, 0).log2();
let noise_have: f64 = pt_want.data.std(base2k, 0).log2();
let noise_want: f64 = ((((rank as f64) + 1.0) * n as f64 * 0.5 * SIGMA * SIGMA).sqrt()).log2() - (k_ct as f64);
assert!(
noise_have <= noise_want + 0.2,
"{} {}",
noise_have,
noise_want
"{noise_have} <= {}",
noise_want + 0.2
);
}
}

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace,
VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxCopy, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply,
VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace, VecZnxSubScalarInplace, VecZnxSwitchRing,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSubScalarInplace, VecZnxSwitchRing,
},
layouts::{Backend, Module, ScratchOwned, VecZnxDft},
oep::{
@@ -17,7 +17,7 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWETensorKey, GLWEPlaintext, GLWESecret, Infos,
Digits, GGLWETensorKey, GGLWETensorKeyLayout, GLWEPlaintext, GLWESecret,
compressed::{Decompress, GGLWETensorKeyCompressed},
prepared::{GLWESecretPrepared, PrepareAlloc},
},
@@ -32,7 +32,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -64,14 +64,23 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 8;
let base2k: usize = 8;
let k: usize = 54;
(1..3).for_each(|rank| {
for rank in 1_usize..3 {
let n: usize = module.n();
let rows: usize = k / basek;
let rows: usize = k / base2k;
let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(n, basek, k, rows, 1, rank);
let tensor_key_infos = GGLWETensorKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k.into(),
rows: rows.into(),
digits: Digits(1),
rank: rank.into(),
};
let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tensor_key_infos);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
@@ -79,12 +88,10 @@ where
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGLWETensorKey::encrypt_sk_scratch_space(
module,
basek,
tensor_key.k(),
rank,
&tensor_key_infos,
));
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&tensor_key_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
@@ -96,45 +103,44 @@ where
scratch.borrow(),
);
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k);
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&tensor_key_infos);
let mut sk_ij_dft = module.vec_znx_dft_alloc(1, 1);
let mut sk_ij_big = module.vec_znx_big_alloc(1, 1);
let mut sk_ij: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, 1);
let mut sk_ij: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), 1_u32.into());
let mut sk_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(rank, 1);
(0..rank).for_each(|i| {
for i in 0..rank {
module.vec_znx_dft_apply(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i);
});
}
(0..rank).for_each(|i| {
(0..rank).for_each(|j| {
for i in 0..rank {
for j in 0..rank {
module.svp_apply_dft_to_dft(&mut sk_ij_dft, 0, &sk_prepared.data, j, &sk_dft, i);
module.vec_znx_idft_apply_tmpa(&mut sk_ij_big, 0, &mut sk_ij_dft, 0);
module.vec_znx_big_normalize(
basek,
base2k,
&mut sk_ij.data.as_vec_znx_mut(),
0,
base2k,
&sk_ij_big,
0,
scratch.borrow(),
);
(0..tensor_key.rank_in()).for_each(|col_i| {
(0..tensor_key.rows()).for_each(|row_i| {
tensor_key
.at(i, j)
.at(row_i, col_i)
.decrypt(module, &mut pt, &sk_prepared, scratch.borrow());
for row_i in 0..rows {
tensor_key
.at(i, j)
.at(row_i, 0)
.decrypt(module, &mut pt, &sk_prepared, scratch.borrow());
module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, row_i, &sk_ij.data, col_i);
module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, row_i, &sk_ij.data, 0);
let std_pt: f64 = pt.data.std(basek, 0) * (k as f64).exp2();
assert!((SIGMA - std_pt).abs() <= 0.5, "{} {}", SIGMA, std_pt);
});
});
});
});
});
let std_pt: f64 = pt.data.std(base2k, 0) * (k as f64).exp2();
assert!((SIGMA - std_pt).abs() <= 0.5, "{SIGMA} {std_pt}");
}
}
}
}
}
pub fn test_gglwe_tensor_key_compressed_encrypt_sk<B>(module: &Module<B>)
@@ -146,7 +152,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -178,26 +184,32 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek = 8;
let base2k = 8;
let k = 54;
(1..3).for_each(|rank| {
for rank in 1_usize..3 {
let n: usize = module.n();
let rows: usize = k / basek;
let rows: usize = k / base2k;
let mut tensor_key_compressed: GGLWETensorKeyCompressed<Vec<u8>> =
GGLWETensorKeyCompressed::alloc(n, basek, k, rows, 1, rank);
let tensor_key_infos: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k.into(),
rows: rows.into(),
digits: Digits(1),
rank: rank.into(),
};
let mut tensor_key_compressed: GGLWETensorKeyCompressed<Vec<u8>> = GGLWETensorKeyCompressed::alloc(&tensor_key_infos);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(GGLWETensorKeyCompressed::encrypt_sk_scratch_space(
module,
basek,
tensor_key_compressed.k(),
rank,
&tensor_key_infos,
));
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&tensor_key_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
@@ -205,46 +217,45 @@ where
tensor_key_compressed.encrypt_sk(module, &sk, seed_xa, &mut source_xe, scratch.borrow());
let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(n, basek, k, rows, 1, rank);
let mut tensor_key: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tensor_key_infos);
tensor_key.decompress(module, &tensor_key_compressed);
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k);
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&tensor_key_infos);
let mut sk_ij_dft = module.vec_znx_dft_alloc(1, 1);
let mut sk_ij_big = module.vec_znx_big_alloc(1, 1);
let mut sk_ij: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, 1);
let mut sk_ij: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), 1_u32.into());
let mut sk_dft: VecZnxDft<Vec<u8>, B> = module.vec_znx_dft_alloc(rank, 1);
(0..rank).for_each(|i| {
for i in 0..rank {
module.vec_znx_dft_apply(1, 0, &mut sk_dft, i, &sk.data.as_vec_znx(), i);
});
}
(0..rank).for_each(|i| {
(0..rank).for_each(|j| {
for i in 0..rank {
for j in 0..rank {
module.svp_apply_dft_to_dft(&mut sk_ij_dft, 0, &sk_prepared.data, j, &sk_dft, i);
module.vec_znx_idft_apply_tmpa(&mut sk_ij_big, 0, &mut sk_ij_dft, 0);
module.vec_znx_big_normalize(
basek,
base2k,
&mut sk_ij.data.as_vec_znx_mut(),
0,
base2k,
&sk_ij_big,
0,
scratch.borrow(),
);
(0..tensor_key.rank_in()).for_each(|col_i| {
(0..tensor_key.rows()).for_each(|row_i| {
tensor_key
.at(i, j)
.at(row_i, col_i)
.decrypt(module, &mut pt, &sk_prepared, scratch.borrow());
for row_i in 0..rows {
tensor_key
.at(i, j)
.at(row_i, 0)
.decrypt(module, &mut pt, &sk_prepared, scratch.borrow());
module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, row_i, &sk_ij.data, col_i);
module.vec_znx_sub_scalar_inplace(&mut pt.data, 0, row_i, &sk_ij.data, 0);
let std_pt: f64 = pt.data.std(basek, 0) * (k as f64).exp2();
assert!((SIGMA - std_pt).abs() <= 0.5, "{} {}", SIGMA, std_pt);
});
});
});
});
});
let std_pt: f64 = pt.data.std(base2k, 0) * (k as f64).exp2();
assert!((SIGMA - std_pt).abs() <= 0.5, "{SIGMA} {std_pt}");
}
}
}
}
}

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace,
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform,
VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxSub,
VecZnxSubABInplace, VecZnxSubScalarInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VecZnxSubInplace, VecZnxSubScalarInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, ScratchOwned, ZnxViewMut},
@@ -18,7 +18,7 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWESwitchingKey, GGSWCiphertext, GLWESecret,
GGLWESwitchingKey, GGLWESwitchingKeyLayout, GGSWCiphertext, GGSWCiphertextLayout, GLWESecret,
prepared::{GGSWCiphertextPrepared, GLWESecretPrepared, PrepareAlloc},
},
noise::noise_ggsw_product,
@@ -34,7 +34,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -68,24 +68,51 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_in: usize = 60;
let digits: usize = k_in.div_ceil(basek);
(1..3).for_each(|rank_in| {
(1..3).for_each(|rank_out| {
(1..digits + 1).for_each(|di| {
let k_ggsw: usize = k_in + basek * di;
let digits: usize = k_in.div_ceil(base2k);
for rank_in in 1_usize..3 {
for rank_out in 1_usize..3 {
for di in 1_usize..digits + 1 {
let k_ggsw: usize = k_in + base2k * di;
let k_out: usize = k_in; // Better capture noise.
let n: usize = module.n();
let rows: usize = k_in.div_ceil(basek * di);
let rows: usize = k_in.div_ceil(base2k * di);
let digits_in: usize = 1;
let mut ct_gglwe_in: GGLWESwitchingKey<Vec<u8>> =
GGLWESwitchingKey::alloc(n, basek, k_in, rows, digits_in, rank_in, rank_out);
let mut ct_gglwe_out: GGLWESwitchingKey<Vec<u8>> =
GGLWESwitchingKey::alloc(n, basek, k_out, rows, digits_in, rank_in, rank_out);
let mut ct_rgsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw, rows, di, rank_out);
let gglwe_in_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
rows: rows.into(),
digits: digits_in.into(),
rank_in: rank_in.into(),
rank_out: rank_out.into(),
};
let gglwe_out_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows.into(),
digits: digits_in.into(),
rank_in: rank_in.into(),
rank_out: rank_out.into(),
};
let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ggsw.into(),
rows: rows.into(),
digits: di.into(),
rank: rank_out.into(),
};
let mut ct_gglwe_in: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_in_infos);
let mut ct_gglwe_out: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_out_infos);
let mut ct_rgsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos);
let mut pt_rgsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
@@ -94,9 +121,14 @@ where
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k_in, rank_in, rank_out)
| GGLWESwitchingKey::external_product_scratch_space(module, basek, k_out, k_in, k_ggsw, di, rank_out)
| GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_ggsw, rank_out),
GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_in_infos)
| GGLWESwitchingKey::external_product_scratch_space(
module,
&gglwe_out_infos,
&gglwe_in_infos,
&ggsw_infos,
)
| GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_infos),
);
let r: usize = 1;
@@ -105,10 +137,10 @@ where
let var_xs: f64 = 0.5;
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_in);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into());
sk_in.fill_ternary_prob(var_xs, &mut source_xs);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_out);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into());
sk_out.fill_ternary_prob(var_xs, &mut source_xs);
let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow());
@@ -154,7 +186,7 @@ where
let max_noise: f64 = noise_ggsw_product(
n as f64,
basek * di,
base2k * di,
var_xs,
var_msg,
var_a0_err,
@@ -169,9 +201,9 @@ where
ct_gglwe_out
.key
.assert_noise(module, &sk_out_prepared, &sk_in.data, max_noise + 0.5);
});
});
});
}
}
}
}
#[allow(clippy::too_many_arguments)]
@@ -184,7 +216,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -218,22 +250,40 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 12;
let k_ct: usize = 60;
let digits: usize = k_ct.div_ceil(basek);
(1..3).for_each(|rank_in| {
(1..3).for_each(|rank_out| {
(1..digits).for_each(|di| {
let k_ggsw: usize = k_ct + basek * di;
let base2k: usize = 12;
let k_out: usize = 60;
let digits: usize = k_out.div_ceil(base2k);
for rank_in in 1_usize..3 {
for rank_out in 1_usize..3 {
for di in 1_usize..digits + 1 {
let k_ggsw: usize = k_out + base2k * di;
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(basek * di);
let rows: usize = k_out.div_ceil(base2k * di);
let digits_in: usize = 1;
let mut ct_gglwe: GGLWESwitchingKey<Vec<u8>> =
GGLWESwitchingKey::alloc(n, basek, k_ct, rows, digits_in, rank_in, rank_out);
let mut ct_rgsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw, rows, di, rank_out);
let gglwe_out_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows.into(),
digits: digits_in.into(),
rank_in: rank_in.into(),
rank_out: rank_out.into(),
};
let ggsw_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ggsw.into(),
rows: rows.into(),
digits: di.into(),
rank: rank_out.into(),
};
let mut ct_gglwe: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_out_infos);
let mut ct_rgsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_infos);
let mut pt_rgsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
@@ -242,9 +292,9 @@ where
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k_ct, rank_in, rank_out)
| GGLWESwitchingKey::external_product_inplace_scratch_space(module, basek, k_ct, k_ggsw, di, rank_out)
| GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_ggsw, rank_out),
GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_out_infos)
| GGLWESwitchingKey::external_product_inplace_scratch_space(module, &gglwe_out_infos, &ggsw_infos)
| GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_infos),
);
let r: usize = 1;
@@ -253,10 +303,10 @@ where
let var_xs: f64 = 0.5;
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_in);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into());
sk_in.fill_ternary_prob(var_xs, &mut source_xs);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_out);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into());
sk_out.fill_ternary_prob(var_xs, &mut source_xs);
let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow());
@@ -302,7 +352,7 @@ where
let max_noise: f64 = noise_ggsw_product(
n as f64,
basek * di,
base2k * di,
var_xs,
var_msg,
var_a0_err,
@@ -310,14 +360,14 @@ where
var_gct_err_lhs,
var_gct_err_rhs,
rank_out as f64,
k_ct,
k_out,
k_ggsw,
);
ct_gglwe
.key
.assert_noise(module, &sk_out_prepared, &sk_in.data, max_noise + 0.5);
});
});
});
}
}
}
}

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc,
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftAlloc, VecZnxDftAllocBytes,
VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace,
VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxSub, VecZnxSubABInplace, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxSub, VecZnxSubInplace, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScalarZnx, ScalarZnxToMut, ScratchOwned, ZnxViewMut},
@@ -18,7 +18,7 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGSWCiphertext, GLWESecret,
GGSWCiphertext, GGSWCiphertextLayout, GLWESecret,
prepared::{GGSWCiphertextPrepared, GLWESecretPrepared, PrepareAlloc},
},
noise::noise_ggsw_product,
@@ -34,7 +34,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -70,73 +70,96 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_in: usize = 60;
let digits: usize = k_in.div_ceil(basek);
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ggsw: usize = k_in + basek * di;
let digits: usize = k_in.div_ceil(base2k);
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_apply: usize = k_in + base2k * di;
let k_out: usize = k_in; // Better capture noise.
let n: usize = module.n();
let rows: usize = k_in.div_ceil(basek * di);
let rows_in: usize = k_in.div_euclid(basek * di);
let rows: usize = k_in.div_ceil(base2k * di);
let rows_in: usize = k_in.div_euclid(base2k * di);
let digits_in: usize = 1;
let mut ct_ggsw_lhs_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_in, rows_in, digits_in, rank);
let mut ct_ggsw_lhs_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_out, rows_in, digits_in, rank);
let mut ct_ggsw_rhs: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw, rows, di, rank);
let mut pt_ggsw_lhs: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut pt_ggsw_rhs: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let ggsw_in_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
rows: rows_in.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows_in.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_apply.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let mut ggsw_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_in_infos);
let mut ggsw_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_infos);
let mut ggsw_apply: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_apply_infos);
let mut pt_in: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut pt_apply: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
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]);
pt_ggsw_lhs.fill_ternary_prob(0, 0.5, &mut source_xs);
pt_in.fill_ternary_prob(0, 0.5, &mut source_xs);
let k: usize = 1;
pt_ggsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k}
pt_apply.to_mut().raw_mut()[k] = 1; //X^{k}
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_ggsw, rank)
| GGSWCiphertext::external_product_scratch_space(module, basek, k_out, k_in, k_ggsw, di, rank),
GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_apply_infos)
| GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_in_infos)
| GGSWCiphertext::external_product_scratch_space(module, &ggsw_out_infos, &ggsw_in_infos, &ggsw_apply_infos),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into());
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
ct_ggsw_rhs.encrypt_sk(
ggsw_apply.encrypt_sk(
module,
&pt_ggsw_rhs,
&pt_apply,
&sk_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
ct_ggsw_lhs_in.encrypt_sk(
ggsw_in.encrypt_sk(
module,
&pt_ggsw_lhs,
&pt_in,
&sk_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let ct_rhs_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ct_ggsw_rhs.prepare_alloc(module, scratch.borrow());
let ct_rhs_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ggsw_apply.prepare_alloc(module, scratch.borrow());
ct_ggsw_lhs_out.external_product(module, &ct_ggsw_lhs_in, &ct_rhs_prepared, scratch.borrow());
ggsw_out.external_product(module, &ggsw_in, &ct_rhs_prepared, scratch.borrow());
module.vec_znx_rotate_inplace(
k as i64,
&mut pt_ggsw_lhs.as_vec_znx_mut(),
0,
scratch.borrow(),
);
module.vec_znx_rotate_inplace(k as i64, &mut pt_in.as_vec_znx_mut(), 0, scratch.borrow());
let var_gct_err_lhs: f64 = SIGMA * SIGMA;
let var_gct_err_rhs: f64 = 0f64;
@@ -148,7 +171,7 @@ where
let max_noise = |_col_j: usize| -> f64 {
noise_ggsw_product(
n as f64,
basek * di,
base2k * di,
0.5,
var_msg,
var_a0_err,
@@ -157,13 +180,13 @@ where
var_gct_err_rhs,
rank as f64,
k_in,
k_ggsw,
k_apply,
) + 0.5
};
ct_ggsw_lhs_out.assert_noise(module, &sk_prepared, &pt_ggsw_lhs, max_noise);
});
});
ggsw_out.assert_noise(module, &sk_prepared, &pt_in, max_noise);
}
}
}
#[allow(clippy::too_many_arguments)]
@@ -176,7 +199,7 @@ where
+ VecZnxIdftApplyConsume<B>
+ VecZnxNormalizeTmpBytes
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -212,71 +235,85 @@ where
+ VecZnxBigAllocBytesImpl<B>
+ TakeSvpPPolImpl<B>,
{
let basek: usize = 12;
let k_ct: usize = 60;
let digits: usize = k_ct.div_ceil(basek);
(1..3).for_each(|rank| {
(1..digits).for_each(|di| {
let k_ggsw: usize = k_ct + basek * di;
let base2k: usize = 12;
let k_out: usize = 60;
let digits: usize = k_out.div_ceil(base2k);
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_apply: usize = k_out + base2k * di;
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(di * basek);
let rows_in: usize = k_ct.div_euclid(basek * di);
let rows: usize = k_out.div_ceil(di * base2k);
let rows_in: usize = k_out.div_euclid(base2k * di);
let digits_in: usize = 1;
let mut ct_ggsw_lhs: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ct, rows_in, digits_in, rank);
let mut ct_ggsw_rhs: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw, rows, di, rank);
let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows_in.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let mut pt_ggsw_lhs: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut pt_ggsw_rhs: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_apply.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let mut ggsw_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_infos);
let mut ggsw_apply: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_apply_infos);
let mut pt_in: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut pt_apply: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
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]);
pt_ggsw_lhs.fill_ternary_prob(0, 0.5, &mut source_xs);
pt_in.fill_ternary_prob(0, 0.5, &mut source_xs);
let k: usize = 1;
pt_ggsw_rhs.to_mut().raw_mut()[k] = 1; //X^{k}
pt_apply.to_mut().raw_mut()[k] = 1; //X^{k}
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_ggsw, rank)
| GGSWCiphertext::external_product_inplace_scratch_space(module, basek, k_ct, k_ggsw, di, rank),
GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_apply_infos)
| GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_out_infos)
| GGSWCiphertext::external_product_inplace_scratch_space(module, &ggsw_out_infos, &ggsw_apply_infos),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into());
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
ct_ggsw_rhs.encrypt_sk(
ggsw_apply.encrypt_sk(
module,
&pt_ggsw_rhs,
&pt_apply,
&sk_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
ct_ggsw_lhs.encrypt_sk(
ggsw_out.encrypt_sk(
module,
&pt_ggsw_lhs,
&pt_in,
&sk_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let ct_rhs_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ct_ggsw_rhs.prepare_alloc(module, scratch.borrow());
let ct_rhs_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ggsw_apply.prepare_alloc(module, scratch.borrow());
ct_ggsw_lhs.external_product_inplace(module, &ct_rhs_prepared, scratch.borrow());
ggsw_out.external_product_inplace(module, &ct_rhs_prepared, scratch.borrow());
module.vec_znx_rotate_inplace(
k as i64,
&mut pt_ggsw_lhs.as_vec_znx_mut(),
0,
scratch.borrow(),
);
module.vec_znx_rotate_inplace(k as i64, &mut pt_in.as_vec_znx_mut(), 0, scratch.borrow());
let var_gct_err_lhs: f64 = SIGMA * SIGMA;
let var_gct_err_rhs: f64 = 0f64;
@@ -288,7 +325,7 @@ where
let max_noise = |_col_j: usize| -> f64 {
noise_ggsw_product(
n as f64,
basek * di,
base2k * di,
0.5,
var_msg,
var_a0_err,
@@ -296,12 +333,12 @@ where
var_gct_err_lhs,
var_gct_err_rhs,
rank as f64,
k_ct,
k_ggsw,
k_out,
k_apply,
) + 0.5
};
ct_ggsw_lhs.assert_noise(module, &sk_prepared, &pt_ggsw_lhs, max_noise);
});
});
ggsw_out.assert_noise(module, &sk_prepared, &pt_in, max_noise);
}
}
}

View File

@@ -3,7 +3,7 @@ use poulpy_hal::{
ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare,
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace,
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume,
VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxSub, VecZnxSubABInplace,
VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxRotateInplace, VecZnxSub, VecZnxSubInplace,
VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScalarZnx, ScratchOwned, ZnxViewMut},
@@ -17,7 +17,7 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGSWCiphertext, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos,
GGSWCiphertext, GGSWCiphertextLayout, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret,
prepared::{GGSWCiphertextPrepared, GLWESecretPrepared, PrepareAlloc},
},
noise::noise_ggsw_product,
@@ -32,7 +32,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -62,64 +62,79 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_in: usize = 45;
let digits: usize = k_in.div_ceil(basek);
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ggsw: usize = k_in + basek * di;
let digits: usize = k_in.div_ceil(base2k);
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_ggsw: usize = k_in + base2k * di;
let k_out: usize = k_ggsw; // Better capture noise
let n: usize = module.n();
let rows: usize = k_in.div_ceil(basek * digits);
let rows: usize = k_in.div_ceil(base2k * digits);
let mut ct_ggsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw, rows, digits, rank);
let mut ct_glwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_in, rank);
let mut ct_glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_out, rank);
let mut pt_rgsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_in);
let glwe_in_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
rank: rank.into(),
};
let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rank: rank.into(),
};
let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ggsw.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let mut ggsw_apply: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_apply_infos);
let mut glwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_in_infos);
let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos);
let mut pt_ggsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_in_infos);
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]);
// Random input plaintext
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
pt_want.data.at_mut(0, 0)[1] = 1;
let k: usize = 1;
pt_rgsw.raw_mut()[k] = 1; // X^{k}
pt_ggsw.raw_mut()[k] = 1; // X^{k}
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, ct_ggsw.k(), rank)
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct_glwe_in.k())
| GLWECiphertext::external_product_scratch_space(
module,
basek,
ct_glwe_out.k(),
ct_glwe_in.k(),
ct_ggsw.k(),
digits,
rank,
),
GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_apply_infos)
| GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_in_infos)
| GLWECiphertext::external_product_scratch_space(module, &glwe_out_infos, &glwe_in_infos, &ggsw_apply_infos),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into());
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
ct_ggsw.encrypt_sk(
ggsw_apply.encrypt_sk(
module,
&pt_rgsw,
&pt_ggsw,
&sk_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
ct_glwe_in.encrypt_sk(
glwe_in.encrypt_sk(
module,
&pt_want,
&sk_prepared,
@@ -128,9 +143,9 @@ where
scratch.borrow(),
);
let ct_ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ct_ggsw.prepare_alloc(module, scratch.borrow());
let ct_ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ggsw_apply.prepare_alloc(module, scratch.borrow());
ct_glwe_out.external_product(module, &ct_glwe_in, &ct_ggsw_prepared, scratch.borrow());
glwe_out.external_product(module, &glwe_in, &ct_ggsw_prepared, scratch.borrow());
module.vec_znx_rotate_inplace(k as i64, &mut pt_want.data, 0, scratch.borrow());
@@ -143,7 +158,7 @@ where
let max_noise: f64 = noise_ggsw_product(
n as f64,
basek * digits,
base2k * digits,
0.5,
var_msg,
var_a0_err,
@@ -155,9 +170,9 @@ where
k_ggsw,
);
ct_glwe_out.assert_noise(module, &sk_prepared, &pt_want, max_noise + 0.5);
});
});
glwe_out.assert_noise(module, &sk_prepared, &pt_want, max_noise + 0.5);
}
}
}
#[allow(clippy::too_many_arguments)]
@@ -169,7 +184,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -199,61 +214,70 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 12;
let k_ct: usize = 60;
let digits: usize = k_ct.div_ceil(basek);
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ggsw: usize = k_ct + basek * di;
let base2k: usize = 12;
let k_out: usize = 60;
let digits: usize = k_out.div_ceil(base2k);
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_ggsw: usize = k_out + base2k * di;
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(basek * digits);
let rows: usize = k_out.div_ceil(base2k * digits);
let mut ct_ggsw: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ggsw, rows, digits, rank);
let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
let mut pt_rgsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rank: rank.into(),
};
let ggsw_apply_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ggsw.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let mut ggsw_apply: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_apply_infos);
let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos);
let mut pt_ggsw: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos);
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]);
// Random input plaintext
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
pt_want.data.at_mut(0, 0)[1] = 1;
let k: usize = 1;
pt_rgsw.raw_mut()[k] = 1; // X^{k}
pt_ggsw.raw_mut()[k] = 1; // X^{k}
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, ct_ggsw.k(), rank)
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct_glwe.k())
| GLWECiphertext::external_product_inplace_scratch_space(
module,
basek,
ct_glwe.k(),
ct_ggsw.k(),
digits,
rank,
),
GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_apply_infos)
| GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_out_infos)
| GLWECiphertext::external_product_inplace_scratch_space(module, &glwe_out_infos, &ggsw_apply_infos),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into());
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_prepared: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
ct_ggsw.encrypt_sk(
ggsw_apply.encrypt_sk(
module,
&pt_rgsw,
&pt_ggsw,
&sk_prepared,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
ct_glwe.encrypt_sk(
glwe_out.encrypt_sk(
module,
&pt_want,
&sk_prepared,
@@ -262,9 +286,9 @@ where
scratch.borrow(),
);
let ct_ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ct_ggsw.prepare_alloc(module, scratch.borrow());
let ct_ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = ggsw_apply.prepare_alloc(module, scratch.borrow());
ct_glwe.external_product_inplace(module, &ct_ggsw_prepared, scratch.borrow());
glwe_out.external_product_inplace(module, &ct_ggsw_prepared, scratch.borrow());
module.vec_znx_rotate_inplace(k as i64, &mut pt_want.data, 0, scratch.borrow());
@@ -277,7 +301,7 @@ where
let max_noise: f64 = noise_ggsw_product(
n as f64,
basek * digits,
base2k * digits,
0.5,
var_msg,
var_a0_err,
@@ -285,11 +309,11 @@ where
var_gct_err_lhs,
var_gct_err_rhs,
rank as f64,
k_ct,
k_out,
k_ggsw,
);
ct_glwe.assert_noise(module, &sk_prepared, &pt_want, max_noise + 0.5);
});
});
glwe_out.assert_noise(module, &sk_prepared, &pt_want, max_noise + 0.5);
}
}
}

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace,
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAllocBytes, VecZnxDftApply,
VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub,
VecZnxSubABInplace, VecZnxSubScalarInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VecZnxSubInplace, VecZnxSubScalarInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScratchOwned},
@@ -18,13 +18,12 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWESwitchingKey, GLWESecret,
GGLWESwitchingKey, GGLWESwitchingKeyLayout, GLWESecret,
prepared::{GGLWESwitchingKeyPrepared, GLWESecretPrepared, PrepareAlloc},
},
noise::log2_std_noise_gglwe_product,
};
#[allow(clippy::too_many_arguments)]
pub fn test_gglwe_switching_key_keyswitch<B>(module: &Module<B>)
where
Module<B>: VecZnxDftAllocBytes
@@ -33,7 +32,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -65,77 +64,84 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_in: usize = 60;
let digits: usize = k_in.div_ceil(basek);
let digits: usize = k_in.div_ceil(base2k);
(1..3).for_each(|rank_in_s0s1| {
(1..3).for_each(|rank_out_s0s1| {
(1..3).for_each(|rank_out_s1s2| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_in + basek * di;
for rank_in_s0s1 in 1_usize..3 {
for rank_out_s0s1 in 1_usize..3 {
for rank_out_s1s2 in 1_usize..3 {
for di in 1_usize..digits + 1 {
let k_ksk: usize = k_in + base2k * di;
let k_out: usize = k_ksk; // Better capture noise.
let n: usize = module.n();
let rows: usize = k_in / basek;
let rows_apply: usize = k_in.div_ceil(basek * di);
let rows: usize = k_in / base2k;
let rows_apply: usize = k_in.div_ceil(base2k * di);
let digits_in: usize = 1;
let mut ct_gglwe_s0s1: GGLWESwitchingKey<Vec<u8>> =
GGLWESwitchingKey::alloc(n, basek, k_in, rows, digits_in, rank_in_s0s1, rank_out_s0s1);
let mut ct_gglwe_s1s2: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(
n,
basek,
k_ksk,
rows_apply,
di,
rank_out_s0s1,
rank_out_s1s2,
);
let mut ct_gglwe_s0s2: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(
n,
basek,
k_out,
rows,
digits_in,
rank_in_s0s1,
rank_out_s1s2,
);
let gglwe_s0s1_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
rows: rows.into(),
digits: digits_in.into(),
rank_in: rank_in_s0s1.into(),
rank_out: rank_out_s0s1.into(),
};
let gglwe_s1s2_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows_apply.into(),
digits: di.into(),
rank_in: rank_out_s0s1.into(),
rank_out: rank_out_s1s2.into(),
};
let gglwe_s0s2_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows_apply.into(),
digits: digits_in.into(),
rank_in: rank_in_s0s1.into(),
rank_out: rank_out_s1s2.into(),
};
let mut gglwe_s0s1: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_s0s1_infos);
let mut gglwe_s1s2: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_s1s2_infos);
let mut gglwe_s0s2: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_s0s2_infos);
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 scratch_enc: ScratchOwned<B> = ScratchOwned::alloc(GGLWESwitchingKey::encrypt_sk_scratch_space(
module,
basek,
k_ksk,
rank_in_s0s1 | rank_out_s0s1,
rank_out_s0s1 | rank_out_s1s2,
));
let mut scratch_enc: ScratchOwned<B> = ScratchOwned::alloc(
GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_s0s1_infos)
| GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_s1s2_infos)
| GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_s0s2_infos),
);
let mut scratch_apply: ScratchOwned<B> = ScratchOwned::alloc(GGLWESwitchingKey::keyswitch_scratch_space(
module,
basek,
k_out,
k_in,
k_ksk,
di,
ct_gglwe_s1s2.rank_in(),
ct_gglwe_s1s2.rank_out(),
&gglwe_s0s1_infos,
&gglwe_s0s2_infos,
&gglwe_s1s2_infos,
));
let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_in_s0s1);
let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in_s0s1.into());
sk0.fill_ternary_prob(0.5, &mut source_xs);
let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_out_s0s1);
let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out_s0s1.into());
sk1.fill_ternary_prob(0.5, &mut source_xs);
let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_out_s1s2);
let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out_s1s2.into());
sk2.fill_ternary_prob(0.5, &mut source_xs);
let sk2_prepared: GLWESecretPrepared<Vec<u8>, B> = sk2.prepare_alloc(module, scratch_apply.borrow());
// gglwe_{s1}(s0) = s0 -> s1
ct_gglwe_s0s1.encrypt_sk(
gglwe_s0s1.encrypt_sk(
module,
&sk0,
&sk1,
@@ -145,7 +151,7 @@ where
);
// gglwe_{s2}(s1) -> s1 -> s2
ct_gglwe_s1s2.encrypt_sk(
gglwe_s1s2.encrypt_sk(
module,
&sk1,
&sk2,
@@ -154,20 +160,20 @@ where
scratch_enc.borrow(),
);
let ct_gglwe_s1s2_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> =
ct_gglwe_s1s2.prepare_alloc(module, scratch_apply.borrow());
let gglwe_s1s2_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> =
gglwe_s1s2.prepare_alloc(module, scratch_apply.borrow());
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
ct_gglwe_s0s2.keyswitch(
gglwe_s0s2.keyswitch(
module,
&ct_gglwe_s0s1,
&ct_gglwe_s1s2_prepared,
&gglwe_s0s1,
&gglwe_s1s2_prepared,
scratch_apply.borrow(),
);
let max_noise: f64 = log2_std_noise_gglwe_product(
n as f64,
basek * di,
base2k * di,
0.5,
0.5,
0f64,
@@ -178,13 +184,13 @@ where
k_ksk,
);
ct_gglwe_s0s2
gglwe_s0s2
.key
.assert_noise(module, &sk2_prepared, &sk0.data, max_noise + 0.5);
});
});
});
});
}
}
}
}
}
#[allow(clippy::too_many_arguments)]
@@ -196,7 +202,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -228,52 +234,69 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 12;
let k_ct: usize = 60;
let digits: usize = k_ct.div_ceil(basek);
(1..3).for_each(|rank_in| {
(1..3).for_each(|rank_out| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_ct + basek * di;
let base2k: usize = 12;
let k_out: usize = 60;
let digits: usize = k_out.div_ceil(base2k);
for rank_in in 1_usize..3 {
for rank_out in 1_usize..3 {
for di in 1_usize..digits + 1 {
let k_ksk: usize = k_out + base2k * di;
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(basek * di);
let rows: usize = k_out.div_ceil(base2k * di);
let digits_in: usize = 1;
let mut ct_gglwe_s0s1: GGLWESwitchingKey<Vec<u8>> =
GGLWESwitchingKey::alloc(n, basek, k_ct, rows, digits_in, rank_in, rank_out);
let mut ct_gglwe_s1s2: GGLWESwitchingKey<Vec<u8>> =
GGLWESwitchingKey::alloc(n, basek, k_ksk, rows, di, rank_out, rank_out);
let gglwe_s0s1_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows.into(),
digits: digits_in.into(),
rank_in: rank_in.into(),
rank_out: rank_out.into(),
};
let gglwe_s1s2_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank_in: rank_out.into(),
rank_out: rank_out.into(),
};
let mut gglwe_s0s1: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_s0s1_infos);
let mut gglwe_s1s2: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&gglwe_s1s2_infos);
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 scratch_enc: ScratchOwned<B> = ScratchOwned::alloc(GGLWESwitchingKey::encrypt_sk_scratch_space(
module,
basek,
k_ksk,
rank_in | rank_out,
rank_out,
));
let mut scratch_enc: ScratchOwned<B> = ScratchOwned::alloc(
GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_s0s1_infos)
| GGLWESwitchingKey::encrypt_sk_scratch_space(module, &gglwe_s1s2_infos),
);
let mut scratch_apply: ScratchOwned<B> = ScratchOwned::alloc(GGLWESwitchingKey::keyswitch_inplace_scratch_space(
module, basek, k_ct, k_ksk, di, rank_out,
module,
&gglwe_s0s1_infos,
&gglwe_s1s2_infos,
));
let var_xs: f64 = 0.5;
let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_in);
let mut sk0: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into());
sk0.fill_ternary_prob(var_xs, &mut source_xs);
let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_out);
let mut sk1: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into());
sk1.fill_ternary_prob(var_xs, &mut source_xs);
let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_out);
let mut sk2: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into());
sk2.fill_ternary_prob(var_xs, &mut source_xs);
let sk2_prepared: GLWESecretPrepared<Vec<u8>, B> = sk2.prepare_alloc(module, scratch_apply.borrow());
// gglwe_{s1}(s0) = s0 -> s1
ct_gglwe_s0s1.encrypt_sk(
gglwe_s0s1.encrypt_sk(
module,
&sk0,
&sk1,
@@ -283,7 +306,7 @@ where
);
// gglwe_{s2}(s1) -> s1 -> s2
ct_gglwe_s1s2.encrypt_sk(
gglwe_s1s2.encrypt_sk(
module,
&sk1,
&sk2,
@@ -292,31 +315,31 @@ where
scratch_enc.borrow(),
);
let ct_gglwe_s1s2_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> =
ct_gglwe_s1s2.prepare_alloc(module, scratch_apply.borrow());
let gglwe_s1s2_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> =
gglwe_s1s2.prepare_alloc(module, scratch_apply.borrow());
// gglwe_{s1}(s0) (x) gglwe_{s2}(s1) = gglwe_{s2}(s0)
ct_gglwe_s0s1.keyswitch_inplace(module, &ct_gglwe_s1s2_prepared, scratch_apply.borrow());
gglwe_s0s1.keyswitch_inplace(module, &gglwe_s1s2_prepared, scratch_apply.borrow());
let ct_gglwe_s0s2: GGLWESwitchingKey<Vec<u8>> = ct_gglwe_s0s1;
let gglwe_s0s2: GGLWESwitchingKey<Vec<u8>> = gglwe_s0s1;
let max_noise: f64 = log2_std_noise_gglwe_product(
n as f64,
basek * di,
base2k * di,
var_xs,
var_xs,
0f64,
SIGMA * SIGMA,
0f64,
rank_out as f64,
k_ct,
k_out,
k_ksk,
);
ct_gglwe_s0s2
gglwe_s0s2
.key
.assert_noise(module, &sk2_prepared, &sk0.data, max_noise + 0.5);
});
});
});
}
}
}
}

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
SvpPrepare, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace,
VecZnxBigAlloc, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAddInplace, VecZnxDftAlloc,
VecZnxDftAllocBytes, VecZnxDftApply, VecZnxDftCopy, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA,
VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace, VecZnxSwitchRing,
VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing,
VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScalarZnx, ScratchOwned},
@@ -18,7 +18,8 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWESwitchingKey, GGLWETensorKey, GGSWCiphertext, GLWESecret,
GGLWESwitchingKey, GGLWESwitchingKeyLayout, GGLWETensorKey, GGLWETensorKeyLayout, GGSWCiphertext, GGSWCiphertextLayout,
GLWESecret,
prepared::{GGLWESwitchingKeyPrepared, GGLWETensorKeyPrepared, GLWESecretPrepared, PrepareAlloc},
},
noise::noise_ggsw_keyswitch,
@@ -33,7 +34,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -70,24 +71,61 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_in: usize = 54;
let digits: usize = k_in.div_ceil(basek);
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_in + basek * di;
let digits: usize = k_in.div_ceil(base2k);
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_ksk: usize = k_in + base2k * di;
let k_tsk: usize = k_ksk;
let k_out: usize = k_ksk; // Better capture noise.
let n: usize = module.n();
let rows: usize = k_in.div_ceil(di * basek);
let rows: usize = k_in.div_ceil(di * base2k);
let digits_in: usize = 1;
let mut ct_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_in, rows, digits_in, rank);
let mut ct_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_out, rows, digits_in, rank);
let mut tsk: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(n, basek, k_ksk, rows, di, rank);
let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(n, basek, k_ksk, rows, di, rank, rank);
let ggsw_in_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
rows: rows.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let tsk_infos: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_tsk.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let ksk_apply_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank_in: rank.into(),
rank_out: rank.into(),
};
let mut ggsw_in: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_in_infos);
let mut ggsw_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_infos);
let mut tsk: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tsk_infos);
let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&ksk_apply_infos);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
@@ -95,19 +133,25 @@ where
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_in, rank)
| GGLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank, rank)
| GGLWETensorKey::encrypt_sk_scratch_space(module, basek, k_tsk, rank)
| GGSWCiphertext::keyswitch_scratch_space(module, basek, k_out, k_in, k_ksk, di, k_tsk, di, rank),
GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_in_infos)
| GGLWESwitchingKey::encrypt_sk_scratch_space(module, &ksk_apply_infos)
| GGLWETensorKey::encrypt_sk_scratch_space(module, &tsk_infos)
| GGSWCiphertext::keyswitch_scratch_space(
module,
&ggsw_out_infos,
&ggsw_in_infos,
&ksk_apply_infos,
&tsk_infos,
),
);
let var_xs: f64 = 0.5;
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into());
sk_in.fill_ternary_prob(var_xs, &mut source_xs);
let sk_in_dft: GLWESecretPrepared<Vec<u8>, B> = sk_in.prepare_alloc(module, scratch.borrow());
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into());
sk_out.fill_ternary_prob(var_xs, &mut source_xs);
let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow());
@@ -129,7 +173,7 @@ where
pt_scalar.fill_ternary_hw(0, n, &mut source_xs);
ct_in.encrypt_sk(
ggsw_in.encrypt_sk(
module,
&pt_scalar,
&sk_in_dft,
@@ -141,9 +185,9 @@ where
let ksk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow());
let tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = tsk.prepare_alloc(module, scratch.borrow());
ct_out.keyswitch(
ggsw_out.keyswitch(
module,
&ct_in,
&ggsw_in,
&ksk_prepared,
&tsk_prepared,
scratch.borrow(),
@@ -152,7 +196,7 @@ where
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
n as f64,
basek * di,
base2k * di,
col_j,
var_xs,
0f64,
@@ -165,9 +209,9 @@ where
) + 0.5
};
ct_out.assert_noise(module, &sk_out_prepared, &pt_scalar, max_noise);
});
});
ggsw_out.assert_noise(module, &sk_out_prepared, &pt_scalar, max_noise);
}
}
}
#[allow(clippy::too_many_arguments)]
@@ -179,7 +223,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -216,22 +260,50 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 12;
let k_ct: usize = 54;
let digits: usize = k_ct.div_ceil(basek);
(1..4).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_ct + basek * di;
let base2k: usize = 12;
let k_out: usize = 54;
let digits: usize = k_out.div_ceil(base2k);
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_ksk: usize = k_out + base2k * di;
let k_tsk: usize = k_ksk;
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(di * basek);
let rows: usize = k_out.div_ceil(di * base2k);
let digits_in: usize = 1;
let mut ct: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(n, basek, k_ct, rows, digits_in, rank);
let mut tsk: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(n, basek, k_tsk, rows, di, rank);
let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(n, basek, k_ksk, rows, di, rank, rank);
let ggsw_out_infos: GGSWCiphertextLayout = GGSWCiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rows: rows.into(),
digits: digits_in.into(),
rank: rank.into(),
};
let tsk_infos: GGLWETensorKeyLayout = GGLWETensorKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_tsk.into(),
rows: rows.into(),
digits: di.into(),
rank: rank.into(),
};
let ksk_apply_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank_in: rank.into(),
rank_out: rank.into(),
};
let mut ggsw_out: GGSWCiphertext<Vec<u8>> = GGSWCiphertext::alloc(&ggsw_out_infos);
let mut tsk: GGLWETensorKey<Vec<u8>> = GGLWETensorKey::alloc(&tsk_infos);
let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&ksk_apply_infos);
let mut pt_scalar: ScalarZnx<Vec<u8>> = ScalarZnx::alloc(n, 1);
let mut source_xs: Source = Source::new([0u8; 32]);
@@ -239,19 +311,19 @@ where
let mut source_xa: Source = Source::new([0u8; 32]);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGSWCiphertext::encrypt_sk_scratch_space(module, basek, k_ct, rank)
| GGLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank, rank)
| GGLWETensorKey::encrypt_sk_scratch_space(module, basek, k_tsk, rank)
| GGSWCiphertext::keyswitch_inplace_scratch_space(module, basek, k_ct, k_ksk, di, k_tsk, di, rank),
GGSWCiphertext::encrypt_sk_scratch_space(module, &ggsw_out_infos)
| GGLWESwitchingKey::encrypt_sk_scratch_space(module, &ksk_apply_infos)
| GGLWETensorKey::encrypt_sk_scratch_space(module, &tsk_infos)
| GGSWCiphertext::keyswitch_inplace_scratch_space(module, &ggsw_out_infos, &ksk_apply_infos, &tsk_infos),
);
let var_xs: f64 = 0.5;
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into());
sk_in.fill_ternary_prob(var_xs, &mut source_xs);
let sk_in_dft: GLWESecretPrepared<Vec<u8>, B> = sk_in.prepare_alloc(module, scratch.borrow());
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into());
sk_out.fill_ternary_prob(var_xs, &mut source_xs);
let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow());
@@ -273,7 +345,7 @@ where
pt_scalar.fill_ternary_hw(0, n, &mut source_xs);
ct.encrypt_sk(
ggsw_out.encrypt_sk(
module,
&pt_scalar,
&sk_in_dft,
@@ -285,25 +357,25 @@ where
let ksk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow());
let tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = tsk.prepare_alloc(module, scratch.borrow());
ct.keyswitch_inplace(module, &ksk_prepared, &tsk_prepared, scratch.borrow());
ggsw_out.keyswitch_inplace(module, &ksk_prepared, &tsk_prepared, scratch.borrow());
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
n as f64,
basek * di,
base2k * di,
col_j,
var_xs,
0f64,
SIGMA * SIGMA,
0f64,
rank as f64,
k_ct,
k_out,
k_ksk,
k_tsk,
) + 0.5
};
ct.assert_noise(module, &sk_out_prepared, &pt_scalar, max_noise);
});
});
ggsw_out.assert_noise(module, &sk_out_prepared, &pt_scalar, max_noise);
}
}
}

View File

@@ -4,7 +4,7 @@ use poulpy_hal::{
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace,
VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAllocBytes, VecZnxDftApply,
VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub,
VecZnxSubABInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc,
VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc,
VmpPrepare,
},
layouts::{Backend, Module, ScratchOwned},
@@ -18,7 +18,7 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWESwitchingKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos,
GGLWESwitchingKey, GGLWESwitchingKeyLayout, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret,
prepared::{GGLWESwitchingKeyPrepared, GLWESecretPrepared, PrepareAlloc},
},
noise::log2_std_noise_gglwe_product,
@@ -33,7 +33,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -64,51 +64,65 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 12;
let base2k: usize = 12;
let k_in: usize = 45;
let digits: usize = k_in.div_ceil(basek);
let digits: usize = k_in.div_ceil(base2k);
(1..3).for_each(|rank_in| {
(1..3).for_each(|rank_out| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_in + basek * di;
for rank_in in 1_usize..3 {
for rank_out in 1_usize..3 {
for di in 1_usize..digits + 1 {
let k_ksk: usize = k_in + base2k * di;
let k_out: usize = k_ksk; // better capture noise
let n: usize = module.n();
let rows: usize = k_in.div_ceil(basek * digits);
let rows: usize = k_in.div_ceil(base2k * digits);
let mut ksk: GGLWESwitchingKey<Vec<u8>> =
GGLWESwitchingKey::alloc(n, basek, k_ksk, rows, digits, rank_in, rank_out);
let mut ct_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_in, rank_in);
let mut ct_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_out, rank_out);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_in);
let glwe_in_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
rank: rank_in.into(),
};
let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rank: rank_out.into(),
};
let key_apply: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank_in: rank_in.into(),
rank_out: rank_out.into(),
};
let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&key_apply);
let mut glwe_in: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_in_infos);
let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_in_infos);
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]);
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGLWESwitchingKey::encrypt_sk_scratch_space(module, basek, ksk.k(), rank_in, rank_out)
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct_in.k())
| GLWECiphertext::keyswitch_scratch_space(
module,
basek,
ct_out.k(),
ct_in.k(),
ksk.k(),
digits,
rank_in,
rank_out,
),
GGLWESwitchingKey::encrypt_sk_scratch_space(module, &key_apply)
| GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_in_infos)
| GLWECiphertext::keyswitch_scratch_space(module, &glwe_out_infos, &glwe_in_infos, &key_apply),
);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_in);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_in.into());
sk_in.fill_ternary_prob(0.5, &mut source_xs);
let sk_in_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_in.prepare_alloc(module, scratch.borrow());
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank_out);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank_out.into());
sk_out.fill_ternary_prob(0.5, &mut source_xs);
let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow());
@@ -121,7 +135,7 @@ where
scratch.borrow(),
);
ct_in.encrypt_sk(
glwe_in.encrypt_sk(
module,
&pt_want,
&sk_in_prepared,
@@ -132,11 +146,11 @@ where
let ksk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow());
ct_out.keyswitch(module, &ct_in, &ksk_prepared, scratch.borrow());
glwe_out.keyswitch(module, &glwe_in, &ksk_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product(
module.n() as f64,
basek * digits,
base2k * digits,
0.5,
0.5,
0f64,
@@ -147,10 +161,10 @@ where
k_ksk,
);
ct_out.assert_noise(module, &sk_out_prepared, &pt_want, max_noise + 0.5);
})
});
});
glwe_out.assert_noise(module, &sk_out_prepared, &pt_want, max_noise + 0.5);
}
}
}
}
pub fn test_glwe_keyswitch_inplace<B>(module: &Module<B>)
@@ -161,7 +175,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -192,42 +206,59 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 12;
let k_ct: usize = 45;
let digits: usize = k_ct.div_ceil(basek);
let base2k: usize = 12;
let k_out: usize = 45;
let digits: usize = k_out.div_ceil(base2k);
(1..3).for_each(|rank| {
(1..digits + 1).for_each(|di| {
let k_ksk: usize = k_ct + basek * di;
for rank in 1_usize..3 {
for di in 1..digits + 1 {
let k_ksk: usize = k_out + base2k * di;
let n: usize = module.n();
let rows: usize = k_ct.div_ceil(basek * digits);
let rows: usize = k_out.div_ceil(base2k * digits);
let mut ksk: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(n, basek, k_ksk, rows, digits, rank, rank);
let mut ct_glwe: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_out.into(),
rank: rank.into(),
};
let key_apply_infos: GGLWESwitchingKeyLayout = GGLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
digits: di.into(),
rank_in: rank.into(),
rank_out: rank.into(),
};
let mut key_apply: GGLWESwitchingKey<Vec<u8>> = GGLWESwitchingKey::alloc(&key_apply_infos);
let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos);
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]);
module.vec_znx_fill_uniform(basek, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GGLWESwitchingKey::encrypt_sk_scratch_space(module, basek, ksk.k(), rank, rank)
| GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct_glwe.k())
| GLWECiphertext::keyswitch_inplace_scratch_space(module, basek, ct_glwe.k(), ksk.k(), digits, rank),
GGLWESwitchingKey::encrypt_sk_scratch_space(module, &key_apply_infos)
| GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_out_infos)
| GLWECiphertext::keyswitch_inplace_scratch_space(module, &glwe_out_infos, &key_apply_infos),
);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk_in: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into());
sk_in.fill_ternary_prob(0.5, &mut source_xs);
let sk_in_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_in.prepare_alloc(module, scratch.borrow());
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk_out: GLWESecret<Vec<u8>> = GLWESecret::alloc_with(n.into(), rank.into());
sk_out.fill_ternary_prob(0.5, &mut source_xs);
let sk_out_prepared: GLWESecretPrepared<Vec<u8>, B> = sk_out.prepare_alloc(module, scratch.borrow());
ksk.encrypt_sk(
key_apply.encrypt_sk(
module,
&sk_in,
&sk_out,
@@ -236,7 +267,7 @@ where
scratch.borrow(),
);
ct_glwe.encrypt_sk(
glwe_out.encrypt_sk(
module,
&pt_want,
&sk_in_prepared,
@@ -245,24 +276,24 @@ where
scratch.borrow(),
);
let ksk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow());
let ksk_prepared: GGLWESwitchingKeyPrepared<Vec<u8>, B> = key_apply.prepare_alloc(module, scratch.borrow());
ct_glwe.keyswitch_inplace(module, &ksk_prepared, scratch.borrow());
glwe_out.keyswitch_inplace(module, &ksk_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product(
module.n() as f64,
basek * digits,
base2k * digits,
0.5,
0.5,
0f64,
SIGMA * SIGMA,
0f64,
rank as f64,
k_ct,
k_out,
k_ksk,
);
ct_glwe.assert_noise(module, &sk_out_prepared, &pt_want, max_noise + 0.5);
});
});
glwe_out.assert_noise(module, &sk_out_prepared, &pt_want, max_noise + 0.5);
}
}
}

View File

@@ -2,9 +2,9 @@ use poulpy_hal::{
api::{
ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare,
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphismInplace, VecZnxBigAddInplace,
VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAllocBytes,
VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubABInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy,
VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace,
VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd,
VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare, ZnAddNormal, ZnFillUniform, ZnNormalizeInplace,
},
layouts::{Backend, Module, ScratchOwned, ZnxView},
@@ -16,7 +16,7 @@ use poulpy_hal::{
};
use crate::layouts::{
Infos, LWECiphertext, LWEPlaintext, LWESecret, LWESwitchingKey,
LWECiphertext, LWECiphertextLayout, LWEPlaintext, LWESecret, LWESwitchingKey, LWESwitchingKeyLayout,
prepared::{LWESwitchingKeyPrepared, PrepareAlloc},
};
@@ -28,7 +28,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -52,7 +52,8 @@ where
+ VecZnxAutomorphismInplace<B>
+ ZnNormalizeInplace<B>
+ ZnFillUniform
+ ZnAddNormal,
+ ZnAddNormal
+ VecZnxCopy,
B: Backend
+ TakeVecZnxDftImpl<B>
+ TakeVecZnxBigImpl<B>
@@ -64,37 +65,56 @@ where
+ TakeVecZnxImpl<B>,
{
let n: usize = module.n();
let basek: usize = 17;
let base2k: usize = 17;
let n_lwe_in: usize = 22;
let n_lwe_out: usize = 30;
let k_lwe_ct: usize = 2 * basek;
let k_lwe_ct: usize = 2 * base2k;
let k_lwe_pt: usize = 8;
let k_ksk: usize = k_lwe_ct + basek;
let k_ksk: usize = k_lwe_ct + base2k;
let rows: usize = k_lwe_ct.div_ceil(base2k);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
let mut source_xe: Source = Source::new([0u8; 32]);
let key_apply_infos: LWESwitchingKeyLayout = LWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rows: rows.into(),
};
let lwe_in_infos: LWECiphertextLayout = LWECiphertextLayout {
n: n_lwe_in.into(),
base2k: base2k.into(),
k: k_lwe_ct.into(),
};
let lwe_out_infos: LWECiphertextLayout = LWECiphertextLayout {
n: n_lwe_out.into(),
k: k_lwe_ct.into(),
base2k: base2k.into(),
};
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
LWESwitchingKey::encrypt_sk_scratch_space(module, basek, k_ksk)
| LWECiphertext::keyswitch_scratch_space(module, basek, k_lwe_ct, k_lwe_ct, k_ksk),
LWESwitchingKey::encrypt_sk_scratch_space(module, &key_apply_infos)
| LWECiphertext::keyswitch_scratch_space(module, &lwe_out_infos, &lwe_in_infos, &key_apply_infos),
);
let mut sk_lwe_in: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe_in);
let mut sk_lwe_in: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe_in.into());
sk_lwe_in.fill_ternary_prob(0.5, &mut source_xs);
let mut sk_lwe_out: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe_out);
let mut sk_lwe_out: LWESecret<Vec<u8>> = LWESecret::alloc(n_lwe_out.into());
sk_lwe_out.fill_ternary_prob(0.5, &mut source_xs);
let data: i64 = 17;
let mut lwe_pt_in: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe_pt);
let mut lwe_pt_in: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_with(base2k.into(), k_lwe_pt.into());
lwe_pt_in.encode_i64(data, k_lwe_pt.into());
lwe_pt_in.encode_i64(data, k_lwe_pt);
let mut lwe_ct_in: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe_in, basek, k_lwe_ct);
let mut lwe_ct_in: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_in_infos);
lwe_ct_in.encrypt_sk(
module,
&lwe_pt_in,
@@ -103,7 +123,7 @@ where
&mut source_xe,
);
let mut ksk: LWESwitchingKey<Vec<u8>> = LWESwitchingKey::alloc(n, basek, k_ksk, lwe_ct_in.size());
let mut ksk: LWESwitchingKey<Vec<u8>> = LWESwitchingKey::alloc(&key_apply_infos);
ksk.encrypt_sk(
module,
@@ -114,13 +134,13 @@ where
scratch.borrow(),
);
let mut lwe_ct_out: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(n_lwe_out, basek, k_lwe_ct);
let mut lwe_ct_out: LWECiphertext<Vec<u8>> = LWECiphertext::alloc(&lwe_out_infos);
let ksk_prepared: LWESwitchingKeyPrepared<Vec<u8>, B> = ksk.prepare_alloc(module, scratch.borrow());
lwe_ct_out.keyswitch(module, &lwe_ct_in, &ksk_prepared, scratch.borrow());
let mut lwe_pt_out: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(basek, k_lwe_ct);
let mut lwe_pt_out: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(&lwe_out_infos);
lwe_ct_out.decrypt(module, &mut lwe_pt_out, &sk_lwe_out);
assert_eq!(lwe_pt_in.data.at(0, 0)[0], lwe_pt_out.data.at(0, 0)[0]);

View File

@@ -5,9 +5,9 @@ use poulpy_hal::{
ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare,
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxAutomorphismInplace,
VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, VecZnxBigNormalize,
VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallBInplace, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply,
VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply,
VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace,
VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, VecZnxSubABInplace,
VecZnxNormalizeTmpBytes, VecZnxRotate, VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace,
VecZnxSwitchRing, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScratchOwned},
@@ -21,7 +21,7 @@ use poulpy_hal::{
use crate::{
GLWEOperations, GLWEPacker,
layouts::{
GGLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret,
GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret,
prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, PrepareAlloc},
},
};
@@ -31,7 +31,7 @@ where
Module<B>: VecZnxDftAllocBytes
+ VecZnxAutomorphism
+ VecZnxBigAutomorphismInplace<B>
+ VecZnxBigSubSmallBInplace<B>
+ VecZnxBigSubSmallNegateInplace<B>
+ VecZnxNegateInplace
+ VecZnxRshInplace<B>
+ VecZnxRotateInplace<B>
@@ -41,7 +41,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -79,37 +79,53 @@ where
let mut source_xa: Source = Source::new([0u8; 32]);
let n: usize = module.n();
let basek: usize = 18;
let base2k: usize = 18;
let k_ct: usize = 36;
let pt_k: usize = 18;
let rank: usize = 3;
let digits: usize = 1;
let k_ksk: usize = k_ct + basek * digits;
let k_ksk: usize = k_ct + base2k * digits;
let rows: usize = k_ct.div_ceil(basek * digits);
let rows: usize = k_ct.div_ceil(base2k * digits);
let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ct.into(),
rank: rank.into(),
};
let key_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_ksk.into(),
rank: rank.into(),
digits: digits.into(),
rows: rows.into(),
};
let mut scratch: ScratchOwned<B> = ScratchOwned::alloc(
GLWECiphertext::encrypt_sk_scratch_space(module, basek, k_ct)
| GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, basek, k_ksk, rank)
| GLWEPacker::scratch_space(module, basek, k_ct, k_ksk, digits, rank),
GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_out_infos)
| GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &key_infos)
| GLWEPacker::scratch_space(module, &glwe_out_infos, &key_infos),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_out_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_dft: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos);
let mut data: Vec<i64> = vec![0i64; n];
data.iter_mut().enumerate().for_each(|(i, x)| {
*x = i as i64;
});
pt.encode_vec_i64(&data, pt_k);
pt.encode_vec_i64(&data, pt_k.into());
let gal_els: Vec<i64> = GLWEPacker::galois_elements(module);
let mut auto_keys: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new();
let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_ksk, rows, digits, rank);
let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&key_infos);
gal_els.iter().for_each(|gal_el| {
tmp.encrypt_sk(
module,
@@ -125,9 +141,9 @@ where
let log_batch: usize = 0;
let mut packer: GLWEPacker = GLWEPacker::new(n, log_batch, basek, k_ct, rank);
let mut packer: GLWEPacker = GLWEPacker::new(&glwe_out_infos, log_batch);
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k_ct, rank);
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos);
ct.encrypt_sk(
module,
@@ -164,10 +180,10 @@ where
}
});
let mut res = GLWECiphertext::alloc(n, basek, k_ct, rank);
let mut res: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos);
packer.flush(module, &mut res);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k_ct);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos);
let mut data: Vec<i64> = vec![0i64; n];
data.iter_mut().enumerate().for_each(|(i, x)| {
if i.is_multiple_of(5) {
@@ -175,7 +191,7 @@ where
}
});
pt_want.encode_vec_i64(&data, pt_k);
pt_want.encode_vec_i64(&data, pt_k.into());
res.decrypt(module, &mut pt, &sk_dft, scratch.borrow());
@@ -184,9 +200,8 @@ where
let noise_have: f64 = pt.std().log2();
assert!(
noise_have < -((k_ct - basek) as f64),
"noise: {}",
noise_have
noise_have < -((k_ct - base2k) as f64),
"noise: {noise_have}"
);
}

View File

@@ -5,9 +5,9 @@ use poulpy_hal::{
ScratchOwnedAlloc, ScratchOwnedBorrow, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare,
VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxBigAddInplace,
VecZnxBigAddSmallInplace, VecZnxBigAllocBytes, VecZnxBigAutomorphismInplace, VecZnxBigNormalize,
VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallBInplace, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply,
VecZnxBigNormalizeTmpBytes, VecZnxBigSubSmallNegateInplace, VecZnxCopy, VecZnxDftAllocBytes, VecZnxDftApply,
VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes,
VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, VecZnxSubABInplace, VecZnxSwitchRing, VmpApplyDftToDft,
VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpApplyDftToDft,
VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, VmpPMatAlloc, VmpPrepare,
},
layouts::{Backend, Module, ScratchOwned, ZnxView, ZnxViewMut},
@@ -21,7 +21,8 @@ use poulpy_hal::{
use crate::{
encryption::SIGMA,
layouts::{
GGLWEAutomorphismKey, GLWECiphertext, GLWEPlaintext, GLWESecret, Infos,
GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GLWECiphertext, GLWECiphertextLayout, GLWEPlaintext, GLWESecret,
LWEInfos,
prepared::{GGLWEAutomorphismKeyPrepared, GLWESecretPrepared, PrepareAlloc},
},
noise::var_noise_gglwe_product,
@@ -32,7 +33,7 @@ where
Module<B>: VecZnxDftAllocBytes
+ VecZnxAutomorphism
+ VecZnxBigAutomorphismInplace<B>
+ VecZnxBigSubSmallBInplace<B>
+ VecZnxBigSubSmallNegateInplace<B>
+ VecZnxRshInplace<B>
+ VecZnxRotateInplace<B>
+ VecZnxBigNormalize<B>
@@ -40,7 +41,7 @@ where
+ SvpApplyDftToDftInplace<B>
+ VecZnxIdftApplyConsume<B>
+ VecZnxFillUniform
+ VecZnxSubABInplace
+ VecZnxSubInplace
+ VecZnxAddInplace
+ VecZnxNormalizeInplace<B>
+ VecZnxAddNormal
@@ -72,32 +73,48 @@ where
+ TakeScalarZnxImpl<B>
+ TakeVecZnxImpl<B>,
{
let basek: usize = 8;
let base2k: usize = 8;
let k: usize = 54;
(1..3).for_each(|rank| {
for rank in 1_usize..3 {
let n: usize = module.n();
let k_autokey: usize = k + basek;
let k_autokey: usize = k + base2k;
let digits: usize = 1;
let rows: usize = k.div_ceil(basek * digits);
let rows: usize = k.div_ceil(base2k * digits);
let mut ct: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(n, basek, k, rank);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k);
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(n, basek, k);
let glwe_out_infos: GLWECiphertextLayout = GLWECiphertextLayout {
n: n.into(),
base2k: base2k.into(),
k: k.into(),
rank: rank.into(),
};
let key_infos: GGLWEAutomorphismKeyLayout = GGLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_autokey.into(),
rank: rank.into(),
digits: digits.into(),
rows: rows.into(),
};
let mut glwe_out: GLWECiphertext<Vec<u8>> = GLWECiphertext::alloc(&glwe_out_infos);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos);
let mut pt_have: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc(&glwe_out_infos);
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 scratch: ScratchOwned<B> = ScratchOwned::alloc(
GLWECiphertext::encrypt_sk_scratch_space(module, basek, ct.k())
| GLWECiphertext::decrypt_scratch_space(module, basek, ct.k())
| GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, basek, k_autokey, rank)
| GLWECiphertext::trace_inplace_scratch_space(module, basek, ct.k(), k_autokey, digits, rank),
GLWECiphertext::encrypt_sk_scratch_space(module, &glwe_out_infos)
| GLWECiphertext::decrypt_scratch_space(module, &glwe_out_infos)
| GGLWEAutomorphismKey::encrypt_sk_scratch_space(module, &key_infos)
| GLWECiphertext::trace_inplace_scratch_space(module, &glwe_out_infos, &key_infos),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(n, rank);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(&glwe_out_infos);
sk.fill_ternary_prob(0.5, &mut source_xs);
let sk_dft: GLWESecretPrepared<Vec<u8>, B> = sk.prepare_alloc(module, scratch.borrow());
@@ -107,9 +124,9 @@ where
.iter_mut()
.for_each(|x| *x = source_xa.next_i64() & 0xFF);
module.vec_znx_fill_uniform(basek, &mut pt_have.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k, &mut pt_have.data, 0, &mut source_xa);
ct.encrypt_sk(
glwe_out.encrypt_sk(
module,
&pt_have,
&sk_dft,
@@ -120,7 +137,7 @@ where
let mut auto_keys: HashMap<i64, GGLWEAutomorphismKeyPrepared<Vec<u8>, B>> = HashMap::new();
let gal_els: Vec<i64> = GLWECiphertext::trace_galois_elements(module);
let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(n, basek, k_autokey, rows, digits, rank);
let mut tmp: GGLWEAutomorphismKey<Vec<u8>> = GGLWEAutomorphismKey::alloc(&key_infos);
gal_els.iter().for_each(|gal_el| {
tmp.encrypt_sk(
module,
@@ -134,21 +151,21 @@ where
auto_keys.insert(*gal_el, atk_prepared);
});
ct.trace_inplace(module, 0, 5, &auto_keys, scratch.borrow());
ct.trace_inplace(module, 5, module.log_n(), &auto_keys, scratch.borrow());
glwe_out.trace_inplace(module, 0, 5, &auto_keys, scratch.borrow());
glwe_out.trace_inplace(module, 5, module.log_n(), &auto_keys, scratch.borrow());
(0..pt_want.size()).for_each(|i| pt_want.data.at_mut(0, i)[0] = pt_have.data.at(0, i)[0]);
ct.decrypt(module, &mut pt_have, &sk_dft, scratch.borrow());
glwe_out.decrypt(module, &mut pt_have, &sk_dft, scratch.borrow());
module.vec_znx_sub_ab_inplace(&mut pt_want.data, 0, &pt_have.data, 0);
module.vec_znx_normalize_inplace(basek, &mut pt_want.data, 0, scratch.borrow());
module.vec_znx_sub_inplace(&mut pt_want.data, 0, &pt_have.data, 0);
module.vec_znx_normalize_inplace(base2k, &mut pt_want.data, 0, scratch.borrow());
let noise_have: f64 = pt_want.std().log2();
let mut noise_want: f64 = var_noise_gglwe_product(
n as f64,
basek,
base2k,
0.5,
0.5,
1.0 / 12.0,
@@ -164,9 +181,7 @@ where
assert!(
(noise_have - noise_want).abs() < 1.0,
"{} > {}",
noise_have,
noise_want
"{noise_have} > {noise_want}"
);
});
}
}