Remove Zn (replaced by VecZnx), add more cross-base2k ops & tests

This commit is contained in:
Pro7ech
2025-11-18 01:08:20 +01:00
parent a3264b8851
commit f39e3e2865
52 changed files with 952 additions and 1550 deletions

View File

@@ -9,10 +9,10 @@ use crate::{
encryption::SIGMA,
layouts::{
GGLWEInfos, GLWEAutomorphismKey, GLWEAutomorphismKeyLayout, GLWEAutomorphismKeyPreparedFactory, GLWEPlaintext,
GLWESecret, GLWESecretPreparedFactory,
GLWESecret, GLWESecretPreparedFactory, LWEInfos,
prepared::{GLWEAutomorphismKeyPrepared, GLWESecretPrepared},
},
noise::log2_std_noise_gglwe_product,
var_noise_gglwe_product_v2,
};
#[allow(clippy::too_many_arguments)]
@@ -29,26 +29,27 @@ where
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let k_in: usize = 60;
let k_out: usize = 40;
let dsize: usize = k_in.div_ceil(base2k);
let base2k_in: usize = 17;
let base2k_key: usize = 13;
let base2k_out: usize = base2k_in; // MUST BE SAME
let k_in: usize = 102;
let max_dsize: usize = k_in.div_ceil(base2k_key);
let p0: i64 = -1;
let p1: i64 = -5;
for rank in 1_usize..3 {
for di in 1..dsize + 1 {
let k_apply: usize = (dsize + di) * base2k;
for dsize in 1..max_dsize + 1 {
let k_ksk: usize = k_in + base2k_key * dsize;
let k_out: usize = k_ksk; // Better capture noise.
let n: usize = module.n();
let dsize_in: usize = 1;
let dnum_in: usize = k_in / (base2k * di);
let dnum_out: usize = k_out / (base2k * di);
let dnum_apply: usize = k_in.div_ceil(base2k * di);
let dnum_in: usize = k_in / base2k_in;
let dnum_ksk: usize = k_in.div_ceil(base2k_key * dsize);
let auto_key_in_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_in.into(),
k: k_in.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
@@ -57,19 +58,19 @@ where
let auto_key_out_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_out.into(),
k: k_out.into(),
dnum: dnum_out.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
rank: rank.into(),
};
let auto_key_apply_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_apply.into(),
dnum: dnum_apply.into(),
dsize: di.into(),
base2k: base2k_key.into(),
k: k_ksk.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank: rank.into(),
};
@@ -83,13 +84,16 @@ where
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &auto_key_in_infos)
| GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &auto_key_apply_infos)
| GLWEAutomorphismKey::automorphism_tmp_bytes(
.max(GLWEAutomorphismKey::encrypt_sk_tmp_bytes(
module,
&auto_key_apply_infos,
))
.max(GLWEAutomorphismKey::automorphism_tmp_bytes(
module,
&auto_key_out_infos,
&auto_key_in_infos,
&auto_key_apply_infos,
),
)),
);
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&auto_key_in);
@@ -128,7 +132,7 @@ where
scratch.borrow(),
);
let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&auto_key_out_infos);
let mut pt_out: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&auto_key_out_infos);
let mut sk_auto: GLWESecret<Vec<u8>> = GLWESecret::alloc_from_infos(&auto_key_out_infos);
sk_auto.fill_zero(); // Necessary to avoid panic of unfilled sk
@@ -145,41 +149,44 @@ where
let mut sk_auto_dft: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk_auto);
sk_auto_dft.prepare(module, &sk_auto);
(0..auto_key_out.rank_in().into()).for_each(|col_i| {
(0..auto_key_out.dnum().into()).for_each(|row_i| {
for col_i in 0..auto_key_out.rank_in().into() {
for row_i in 0..auto_key_out.dnum().into() {
auto_key_out
.at(row_i, col_i)
.decrypt(module, &mut pt, &sk_auto_dft, scratch.borrow());
.decrypt(module, &mut pt_out, &sk_auto_dft, scratch.borrow());
module.vec_znx_sub_scalar_inplace(
&mut pt.data,
&mut pt_out.data,
0,
(dsize_in - 1) + row_i * dsize_in,
&sk.data,
col_i,
);
let noise_have: f64 = pt.data.stats(base2k, 0).std().log2();
let noise_want: f64 = log2_std_noise_gglwe_product(
n as f64,
base2k * di,
let noise_have: f64 = pt_out.data.stats(pt_out.base2k().into(), 0).std().log2();
let max_noise: f64 = var_noise_gglwe_product_v2(
module.n() as f64,
k_ksk,
dnum_ksk,
dsize,
base2k_key,
0.5,
0.5,
0f64,
SIGMA * SIGMA,
0f64,
rank as f64,
k_out,
k_apply,
);
)
.sqrt()
.log2();
assert!(
noise_have < noise_want + 0.5,
noise_have < max_noise + 0.5,
"{noise_have} {}",
noise_want + 0.5
max_noise + 0.5
);
});
});
}
}
}
}
}
@@ -198,25 +205,27 @@ where
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let k_in: usize = 60;
let dsize: usize = k_in.div_ceil(base2k);
let base2k_out: usize = 17;
let base2k_key: usize = 13;
let k_out: usize = 102;
let max_dsize: usize = k_out.div_ceil(base2k_key);
let p0: i64 = -1;
let p1: i64 = -5;
for rank in 1_usize..3 {
for di in 1..dsize + 1 {
let k_apply: usize = (dsize + di) * base2k;
for dsize in 1..max_dsize + 1 {
let k_ksk: usize = k_out + base2k_key * dsize;
let n: usize = module.n();
let dsize_in: usize = 1;
let dnum_in: usize = k_in / (base2k * di);
let dnum_apply: usize = k_in.div_ceil(base2k * di);
let dnum_in: usize = k_out / base2k_out;
let dnum_ksk: usize = k_out.div_ceil(base2k_key * dsize);
let auto_key_layout: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_in.into(),
base2k: base2k_out.into(),
k: k_out.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
rank: rank.into(),
@@ -224,10 +233,10 @@ where
let auto_key_apply_layout: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
k: k_apply.into(),
dnum: dnum_apply.into(),
dsize: di.into(),
base2k: base2k_key.into(),
k: k_ksk.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank: rank.into(),
};
@@ -306,24 +315,27 @@ where
col_i,
);
let noise_have: f64 = pt.data.stats(base2k, 0).std().log2();
let noise_want: f64 = log2_std_noise_gglwe_product(
n as f64,
base2k * di,
let noise_have: f64 = pt.data.stats(pt.base2k().into(), 0).std().log2();
let max_noise: f64 = var_noise_gglwe_product_v2(
module.n() as f64,
k_ksk,
dnum_ksk,
dsize,
base2k_key,
0.5,
0.5,
0f64,
SIGMA * SIGMA,
0f64,
rank as f64,
k_in,
k_apply,
);
)
.sqrt()
.log2();
assert!(
noise_have < noise_want + 0.5,
noise_have < max_noise + 0.5,
"{noise_have} {}",
noise_want + 0.5
max_noise + 0.5
);
});
});

View File

@@ -29,26 +29,28 @@ where
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let k_in: usize = 54;
let dsize: usize = k_in.div_ceil(base2k);
let p: i64 = -5;
let base2k_in: usize = 17;
let base2k_key: usize = 13;
let base2k_out: usize = base2k_in; // MUST BE SAME
let k_in: usize = 102;
let max_dsize: usize = k_in.div_ceil(base2k_key);
let p: i64 = -5;
for rank in 1_usize..3 {
for di in 1..dsize + 1 {
let k_ksk: usize = k_in + base2k * di;
for dsize in 1..max_dsize + 1 {
let k_ksk: usize = k_in + base2k_key * dsize;
let k_tsk: usize = k_ksk;
let k_out: usize = k_ksk; // Better capture noise.
let n: usize = module.n();
let dnum: usize = k_in.div_ceil(base2k * di);
let dnum_in: usize = k_in.div_euclid(base2k * di);
let dnum_in: usize = k_in / base2k_in;
let dnum_ksk: usize = k_in.div_ceil(base2k_key * dsize);
let dsize_in: usize = 1;
let ggsw_in_layout: GGSWLayout = GGSWLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_in.into(),
k: k_in.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
@@ -57,7 +59,7 @@ where
let ggsw_out_layout: GGSWLayout = GGSWLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_out.into(),
k: k_out.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
@@ -66,19 +68,19 @@ where
let tsk_layout: GGLWEToGGSWKeyLayout = GGLWEToGGSWKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_tsk.into(),
dnum: dnum.into(),
dsize: di.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank: rank.into(),
};
let auto_key_layout: GGLWEToGGSWKeyLayout = GGLWEToGGSWKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_ksk.into(),
dnum: dnum.into(),
dsize: di.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank: rank.into(),
};
@@ -154,7 +156,7 @@ where
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
n as f64,
base2k * di,
base2k_key * dsize,
col_j,
var_xs,
0f64,
@@ -187,23 +189,25 @@ where
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let k_out: usize = 54;
let dsize: usize = k_out.div_ceil(base2k);
let base2k_out: usize = 17;
let base2k_key: usize = 13;
let k_out: usize = 102;
let max_dsize: usize = k_out.div_ceil(base2k_key);
let p: i64 = -1;
for rank in 1_usize..3 {
for di in 1..dsize + 1 {
let k_ksk: usize = k_out + base2k * di;
for dsize in 1..max_dsize + 1 {
let k_ksk: usize = k_out + base2k_key * dsize;
let k_tsk: usize = k_ksk;
let n: usize = module.n();
let dnum: usize = k_out.div_ceil(di * base2k);
let dnum_in: usize = k_out.div_euclid(base2k * di);
let dnum_in: usize = k_out / base2k_out;
let dnum_ksk: usize = k_out.div_ceil(base2k_key * dsize);
let dsize_in: usize = 1;
let ggsw_out_layout: GGSWLayout = GGSWLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_out.into(),
k: k_out.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
@@ -212,19 +216,19 @@ where
let tsk_layout: GGLWEToGGSWKeyLayout = GGLWEToGGSWKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_tsk.into(),
dnum: dnum.into(),
dsize: di.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank: rank.into(),
};
let auto_key_layout: GGLWEToGGSWKeyLayout = GGLWEToGGSWKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_ksk.into(),
dnum: dnum.into(),
dsize: di.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank: rank.into(),
};
@@ -293,7 +297,7 @@ where
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
n as f64,
base2k * di,
base2k_key * dsize,
col_j,
var_xs,
0f64,

View File

@@ -5,14 +5,14 @@ use poulpy_hal::{
};
use crate::{
GLWEAutomorphism, GLWEAutomorphismKeyEncryptSk, GLWEDecrypt, GLWEEncryptSk, GLWENoise, ScratchTakeCore,
GLWEAutomorphism, GLWEAutomorphismKeyEncryptSk, GLWEDecrypt, GLWEEncryptSk, GLWENoise, GLWENormalize, ScratchTakeCore,
encryption::SIGMA,
layouts::{
GLWE, GLWEAutomorphismKey, GLWEAutomorphismKeyLayout, GLWEAutomorphismKeyPreparedFactory, GLWELayout, GLWEPlaintext,
GLWESecret, GLWESecretPreparedFactory,
prepared::{GLWEAutomorphismKeyPrepared, GLWESecretPrepared},
},
noise::log2_std_noise_gglwe_product,
var_noise_gglwe_product_v2,
};
pub fn test_glwe_automorphism<BE: Backend>(module: &Module<BE>)
@@ -25,55 +25,59 @@ where
+ GLWEAutomorphismKeyEncryptSk<BE>
+ GLWEAutomorphismKeyPreparedFactory<BE>
+ GLWENoise<BE>
+ VecZnxAutomorphismInplace<BE>,
+ VecZnxAutomorphismInplace<BE>
+ GLWENormalize<BE>,
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let k_in: usize = 60;
let dsize: usize = k_in.div_ceil(base2k);
let base2k_in: usize = 17;
let base2k_key: usize = 13;
let base2k_out: usize = 15;
let k_in: usize = 102;
let max_dsize: usize = k_in.div_ceil(base2k_key);
let p: i64 = -5;
for rank in 1_usize..3 {
for di in 1..dsize + 1 {
let k_ksk: usize = k_in + base2k * di;
for dsize in 1..max_dsize + 1 {
let k_ksk: usize = k_in + base2k_key * dsize;
let k_out: usize = k_ksk; // Better capture noise.
let n: usize = module.n();
let dnum: usize = k_in.div_ceil(base2k * dsize);
let dnum: usize = k_in.div_ceil(base2k_key * dsize);
let ct_in_infos: GLWELayout = GLWELayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_in.into(),
k: k_in.into(),
rank: rank.into(),
};
let ct_out_infos: GLWELayout = GLWELayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_out.into(),
k: k_out.into(),
rank: rank.into(),
};
let autokey_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_out.into(),
rank: rank.into(),
dnum: dnum.into(),
dsize: di.into(),
dsize: dsize.into(),
};
let mut autokey: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&autokey_infos);
let mut ct_in: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&ct_in_infos);
let mut ct_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&ct_out_infos);
let mut pt_want: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&ct_out_infos);
let mut pt_in: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&ct_in_infos);
let mut pt_out: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&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(base2k, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k_in, &mut pt_in.data, 0, &mut source_xa);
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &autokey)
@@ -99,7 +103,7 @@ where
ct_in.encrypt_sk(
module,
&pt_want,
&pt_in,
&sk_prepared,
&mut source_xa,
&mut source_xe,
@@ -112,22 +116,26 @@ where
ct_out.automorphism(module, &ct_in, &autokey_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product(
let max_noise: f64 = var_noise_gglwe_product_v2(
module.n() as f64,
base2k * dsize,
k_ksk,
dnum,
max_dsize,
base2k_key,
0.5,
0.5,
0f64,
SIGMA * SIGMA,
0f64,
rank as f64,
k_in,
k_ksk,
);
)
.sqrt()
.log2();
module.vec_znx_automorphism_inplace(p, &mut pt_want.data, 0, scratch.borrow());
module.glwe_normalize(&mut pt_out, &pt_in, scratch.borrow());
module.vec_znx_automorphism_inplace(p, &mut pt_out.data, 0, scratch.borrow());
ct_out.assert_noise(module, &sk_prepared, &pt_want, max_noise + 1.0);
ct_out.assert_noise(module, &sk_prepared, &pt_out, max_noise + 1.0);
}
}
}
@@ -147,31 +155,33 @@ where
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let k_out: usize = 60;
let dsize: usize = k_out.div_ceil(base2k);
let base2k_out: usize = 17;
let base2k_key: usize = 13;
let k_out: usize = 102;
let max_dsize: usize = k_out.div_ceil(base2k_key);
let p = -5;
for rank in 1_usize..3 {
for di in 1..dsize + 1 {
let k_ksk: usize = k_out + base2k * di;
for dsize in 1..max_dsize + 1 {
let k_ksk: usize = k_out + base2k_key * dsize;
let n: usize = module.n();
let dnum: usize = k_out.div_ceil(base2k * dsize);
let dnum: usize = k_out.div_ceil(base2k_key * dsize);
let ct_out_infos: GLWELayout = GLWELayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_out.into(),
k: k_out.into(),
rank: rank.into(),
};
let autokey_infos: GLWEAutomorphismKeyLayout = GLWEAutomorphismKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_ksk.into(),
rank: rank.into(),
dnum: dnum.into(),
dsize: di.into(),
dsize: dsize.into(),
};
let mut autokey: GLWEAutomorphismKey<Vec<u8>> = GLWEAutomorphismKey::alloc_from_infos(&autokey_infos);
@@ -182,7 +192,7 @@ where
let mut source_xe: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
module.vec_znx_fill_uniform(base2k, &mut pt_want.data, 0, &mut source_xa);
module.vec_znx_fill_uniform(base2k_out, &mut pt_want.data, 0, &mut source_xa);
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
GLWEAutomorphismKey::encrypt_sk_tmp_bytes(module, &autokey)
@@ -221,18 +231,21 @@ where
ct.automorphism_inplace(module, &autokey_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product(
let max_noise: f64 = var_noise_gglwe_product_v2(
module.n() as f64,
base2k * dsize,
k_ksk,
dnum,
dsize,
base2k_key,
0.5,
0.5,
0f64,
SIGMA * SIGMA,
0f64,
rank as f64,
k_out,
k_ksk,
);
)
.sqrt()
.log2();
module.vec_znx_automorphism_inplace(p, &mut pt_want.data, 0, scratch.borrow());

View File

@@ -1,5 +1,5 @@
use poulpy_hal::{
api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform},
api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform, VecZnxNormalize},
layouts::{Backend, FillUniform, Module, Scratch, ScratchOwned, ZnxView},
source::Source,
};
@@ -104,7 +104,8 @@ where
+ GLWEDecrypt<BE>
+ GLWESecretPreparedFactory<BE>
+ LWEEncryptSk<BE>
+ LWEToGLWEKeyPreparedFactory<BE>,
+ LWEToGLWEKeyPreparedFactory<BE>
+ VecZnxNormalize<BE>,
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
@@ -120,23 +121,23 @@ where
let lwe_to_glwe_infos: LWEToGLWEKeyLayout = LWEToGLWEKeyLayout {
n: n_glwe,
base2k: Base2K(17),
k: TorusPrecision(51),
base2k: Base2K(13),
k: TorusPrecision(92),
dnum: Dnum(2),
rank_out: rank,
};
let glwe_infos: GLWELayout = GLWELayout {
n: n_glwe,
base2k: Base2K(17),
k: TorusPrecision(34),
base2k: Base2K(15),
k: TorusPrecision(75),
rank,
};
let lwe_infos: LWELayout = LWELayout {
n: n_lwe,
base2k: Base2K(17),
k: TorusPrecision(34),
k: TorusPrecision(75),
};
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
@@ -160,7 +161,14 @@ where
lwe_pt.encode_i64(data, k_lwe_pt);
let mut lwe_ct: LWE<Vec<u8>> = LWE::alloc_from_infos(&lwe_infos);
lwe_ct.encrypt_sk(module, &lwe_pt, &sk_lwe, &mut source_xa, &mut source_xe);
lwe_ct.encrypt_sk(
module,
&lwe_pt,
&sk_lwe,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let mut ksk: LWEToGLWEKey<Vec<u8>> = LWEToGLWEKey::alloc_from_infos(&lwe_to_glwe_infos);
@@ -183,7 +191,19 @@ where
let mut glwe_pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&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]);
let mut lwe_pt_conv = LWEPlaintext::alloc(glwe_pt.base2k(), lwe_pt.k());
module.vec_znx_normalize(
glwe_pt.base2k().as_usize(),
lwe_pt_conv.data_mut(),
0,
lwe_pt.base2k().as_usize(),
lwe_pt.data(),
0,
scratch.borrow(),
);
assert_eq!(glwe_pt.data.at(0, 0)[0], lwe_pt_conv.data.at(0, 0)[0]);
}
pub fn test_glwe_to_lwe<BE: Backend>(module: &Module<BE>)
@@ -196,7 +216,8 @@ where
+ GLWEDecrypt<BE>
+ GLWESecretPreparedFactory<BE>
+ GLWEToLWESwitchingKeyEncryptSk<BE>
+ GLWEToLWEKeyPreparedFactory<BE>,
+ GLWEToLWEKeyPreparedFactory<BE>
+ VecZnxNormalize<BE>,
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
@@ -208,8 +229,8 @@ where
let glwe_to_lwe_infos: GLWEToLWEKeyLayout = GLWEToLWEKeyLayout {
n: n_glwe,
base2k: Base2K(17),
k: TorusPrecision(51),
base2k: Base2K(13),
k: TorusPrecision(91),
dnum: Dnum(2),
rank_in: rank,
};
@@ -217,14 +238,14 @@ where
let glwe_infos: GLWELayout = GLWELayout {
n: n_glwe,
base2k: Base2K(17),
k: TorusPrecision(34),
k: TorusPrecision(72),
rank,
};
let lwe_infos: LWELayout = LWELayout {
n: n_lwe,
base2k: Base2K(17),
k: TorusPrecision(34),
base2k: Base2K(15),
k: TorusPrecision(72),
};
let mut source_xs: Source = Source::new([0u8; 32]);
@@ -284,7 +305,19 @@ where
lwe_ct.from_glwe(module, &glwe_ct, a_idx, &ksk_prepared, scratch.borrow());
let mut lwe_pt: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_from_infos(&lwe_infos);
lwe_ct.decrypt(module, &mut lwe_pt, &sk_lwe);
lwe_ct.decrypt(module, &mut lwe_pt, &sk_lwe, scratch.borrow());
assert_eq!(glwe_pt.data.at(0, 0)[a_idx], lwe_pt.data.at(0, 0)[0]);
let mut glwe_pt_conv = GLWEPlaintext::alloc(glwe_ct.n(), lwe_pt.base2k(), lwe_pt.k());
module.vec_znx_normalize(
lwe_pt.base2k().as_usize(),
glwe_pt_conv.data_mut(),
0,
glwe_ct.base2k().as_usize(),
glwe_pt.data(),
0,
scratch.borrow(),
);
assert_eq!(glwe_pt_conv.data.at(0, 0)[a_idx], lwe_pt.data.at(0, 0)[0]);
}

View File

@@ -12,6 +12,7 @@ use crate::{
prepared::{GLWESecretPrepared, GLWESwitchingKeyPrepared},
},
noise::log2_std_noise_gglwe_product,
var_noise_gglwe_product_v2,
};
pub fn test_gglwe_switching_key_keyswitch<BE: Backend>(module: &Module<BE>)
@@ -24,27 +25,29 @@ where
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let k_in: usize = 60;
let dsize: usize = k_in.div_ceil(base2k);
let base2k_in: usize = 17;
let base2k_key: usize = 13;
let base2k_out: usize = base2k_in; // MUST BE SAME
let k_in: usize = 102;
let max_dsize: usize = k_in.div_ceil(base2k_key);
for rank_in_s0s1 in 1_usize..3 {
for rank_in_s0s1 in 1_usize..2 {
for rank_out_s0s1 in 1_usize..3 {
for rank_out_s1s2 in 1_usize..3 {
for di in 1_usize..dsize + 1 {
let k_ksk: usize = k_in + base2k * di;
for dsize in 1_usize..max_dsize + 1 {
let k_ksk: usize = k_in + base2k_key * dsize;
let k_out: usize = k_ksk; // Better capture noise.
let n: usize = module.n();
let dnum: usize = k_in / base2k;
let dnum_apply: usize = k_in.div_ceil(base2k * di);
let dsize_in: usize = 1;
let dnum_in: usize = k_in / base2k_in;
let dnum_ksk: usize = k_in.div_ceil(base2k_key * dsize);
let gglwe_s0s1_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_in.into(),
k: k_in.into(),
dnum: dnum.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
rank_in: rank_in_s0s1.into(),
rank_out: rank_out_s0s1.into(),
@@ -52,19 +55,19 @@ where
let gglwe_s1s2_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_ksk.into(),
dnum: dnum_apply.into(),
dsize: di.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank_in: rank_out_s0s1.into(),
rank_out: rank_out_s1s2.into(),
};
let gglwe_s0s2_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_out.into(),
k: k_out.into(),
dnum: dnum_apply.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
rank_in: rank_in_s0s1.into(),
rank_out: rank_out_s1s2.into(),
@@ -85,8 +88,8 @@ where
);
let mut scratch_apply: ScratchOwned<BE> = ScratchOwned::alloc(GLWESwitchingKey::keyswitch_tmp_bytes(
module,
&gglwe_s0s1_infos,
&gglwe_s0s2_infos,
&gglwe_s0s1_infos,
&gglwe_s1s2_infos,
));
@@ -135,18 +138,21 @@ where
scratch_apply.borrow(),
);
let max_noise: f64 = log2_std_noise_gglwe_product(
n as f64,
base2k * di,
let max_noise: f64 = var_noise_gglwe_product_v2(
module.n() as f64,
k_ksk,
dnum_ksk,
dsize,
base2k_key,
0.5,
0.5,
0f64,
SIGMA * SIGMA,
0f64,
rank_out_s0s1 as f64,
k_in,
k_ksk,
);
)
.sqrt()
.log2();
gglwe_s0s2
.key
@@ -168,23 +174,27 @@ where
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let k_out: usize = 60;
let dsize: usize = k_out.div_ceil(base2k);
let base2k_out: usize = 17;
let base2k_key: usize = 13;
let k_out: usize = 102;
let max_dsize: usize = k_out.div_ceil(base2k_key);
for rank_in in 1_usize..3 {
for rank_out in 1_usize..3 {
for di in 1_usize..dsize + 1 {
let k_ksk: usize = k_out + base2k * di;
for dsize in 1_usize..max_dsize + 1 {
let k_ksk: usize = k_out + base2k_key * dsize;
let n: usize = module.n();
let dnum: usize = k_out.div_ceil(base2k * di);
let dsize_in: usize = 1;
let dnum_in: usize = k_out / base2k_out;
let dnum_ksk: usize = k_out.div_ceil(base2k_key * dsize);
let gglwe_s0s1_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_out.into(),
k: k_out.into(),
dnum: dnum.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
rank_in: rank_in.into(),
rank_out: rank_out.into(),
@@ -192,10 +202,10 @@ where
let gglwe_s1s2_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_ksk.into(),
dnum: dnum.into(),
dsize: di.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank_in: rank_out.into(),
rank_out: rank_out.into(),
};
@@ -263,7 +273,7 @@ where
let max_noise: f64 = log2_std_noise_gglwe_product(
n as f64,
base2k * di,
base2k_key * dsize,
var_xs,
var_xs,
0f64,

View File

@@ -30,53 +30,57 @@ where
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let k_in: usize = 54;
let dsize: usize = k_in.div_ceil(base2k);
let base2k_in: usize = 17;
let base2k_key: usize = 13;
let base2k_out: usize = base2k_in; // MUST BE SAME
let k_in: usize = 102;
let max_dsize: usize = k_in.div_ceil(base2k_key);
for rank in 1_usize..3 {
for di in 1..dsize + 1 {
let k_ksk: usize = k_in + base2k * di;
for dsize in 1..max_dsize + 1 {
let k_ksk: usize = k_in + base2k_key * dsize;
let k_tsk: usize = k_ksk;
let k_out: usize = k_ksk; // Better capture noise.
let n: usize = module.n();
let dnum: usize = k_in.div_ceil(di * base2k);
let dnum_in: usize = k_in / base2k_in;
let dnum_ksk: usize = k_in.div_ceil(base2k_key * dsize);
let dsize_in: usize = 1;
let ggsw_in_infos: GGSWLayout = GGSWLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_in.into(),
k: k_in.into(),
dnum: dnum.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
rank: rank.into(),
};
let ggsw_out_infos: GGSWLayout = GGSWLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_out.into(),
k: k_out.into(),
dnum: dnum.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
rank: rank.into(),
};
let tsk_infos: GLWETensorKeyLayout = GLWETensorKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_tsk.into(),
dnum: dnum.into(),
dsize: di.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank: rank.into(),
};
let ksk_apply_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_ksk.into(),
dnum: dnum.into(),
dsize: di.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank_in: rank.into(),
rank_out: rank.into(),
};
@@ -163,7 +167,7 @@ where
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
n as f64,
base2k * di,
base2k_key * dsize,
col_j,
var_xs,
0f64,
@@ -195,43 +199,45 @@ where
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let k_out: usize = 54;
let dsize: usize = k_out.div_ceil(base2k);
let base2k_out: usize = 17;
let base2k_key: usize = 13;
let k_out: usize = 102;
let max_dsize: usize = k_out.div_ceil(base2k_key);
for rank in 1_usize..3 {
for di in 1..dsize + 1 {
let k_ksk: usize = k_out + base2k * di;
for dsize in 1..max_dsize + 1 {
let k_ksk: usize = k_out + base2k_key * dsize;
let k_tsk: usize = k_ksk;
let n: usize = module.n();
let dnum: usize = k_out.div_ceil(di * base2k);
let dnum_in: usize = k_out / base2k_out;
let dnum_ksk: usize = k_out.div_ceil(base2k_key * dsize);
let dsize_in: usize = 1;
let ggsw_out_infos: GGSWLayout = GGSWLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_out.into(),
k: k_out.into(),
dnum: dnum.into(),
dnum: dnum_in.into(),
dsize: dsize_in.into(),
rank: rank.into(),
};
let tsk_infos: GLWETensorKeyLayout = GLWETensorKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_tsk.into(),
dnum: dnum.into(),
dsize: di.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank: rank.into(),
};
let ksk_apply_infos: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_ksk.into(),
dnum: dnum.into(),
dsize: di.into(),
dnum: dnum_ksk.into(),
dsize: dsize.into(),
rank_in: rank.into(),
rank_out: rank.into(),
};
@@ -311,7 +317,7 @@ where
let max_noise = |col_j: usize| -> f64 {
noise_ggsw_keyswitch(
n as f64,
base2k * di,
base2k_key * dsize,
col_j,
var_xs,
0f64,

View File

@@ -12,7 +12,6 @@ use crate::{
GLWESwitchingKeyPreparedFactory, LWEInfos,
prepared::{GLWESecretPrepared, GLWESwitchingKeyPrepared},
},
noise::log2_std_noise_gglwe_product,
var_noise_gglwe_product_v2,
};

View File

@@ -1,5 +1,5 @@
use poulpy_hal::{
api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow},
api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxNormalize},
layouts::{Backend, Module, Scratch, ScratchOwned, ZnxView},
source::Source,
};
@@ -14,21 +14,27 @@ use crate::{
pub fn test_lwe_keyswitch<BE: Backend>(module: &Module<BE>)
where
Module<BE>:
LWEKeySwitch<BE> + LWESwitchingKeyEncrypt<BE> + LWEEncryptSk<BE> + LWESwitchingKeyPreparedFactory<BE> + LWEDecrypt<BE>,
Module<BE>: LWEKeySwitch<BE>
+ LWESwitchingKeyEncrypt<BE>
+ LWEEncryptSk<BE>
+ LWESwitchingKeyPreparedFactory<BE>
+ LWEDecrypt<BE>
+ VecZnxNormalize<BE>,
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let n: usize = module.n();
let base2k: usize = 17;
let base2k_in: usize = 17;
let base2k_out: usize = 15;
let base2k_key: usize = 13;
let n_lwe_in: usize = 22;
let n_lwe_out: usize = 30;
let k_lwe_ct: usize = 2 * base2k;
let n_lwe_in: usize = module.n() >> 1;
let n_lwe_out: usize = module.n() >> 1;
let k_lwe_ct: usize = 102;
let k_lwe_pt: usize = 8;
let k_ksk: usize = k_lwe_ct + base2k;
let dnum: usize = k_lwe_ct.div_ceil(base2k);
let k_ksk: usize = k_lwe_ct + base2k_key;
let dnum: usize = k_lwe_ct.div_ceil(base2k_key);
let mut source_xs: Source = Source::new([0u8; 32]);
let mut source_xa: Source = Source::new([0u8; 32]);
@@ -36,21 +42,21 @@ where
let key_apply_infos: LWESwitchingKeyLayout = LWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_key.into(),
k: k_ksk.into(),
dnum: dnum.into(),
};
let lwe_in_infos: LWELayout = LWELayout {
n: n_lwe_in.into(),
base2k: base2k.into(),
base2k: base2k_in.into(),
k: k_lwe_ct.into(),
};
let lwe_out_infos: LWELayout = LWELayout {
n: n_lwe_out.into(),
k: k_lwe_ct.into(),
base2k: base2k.into(),
base2k: base2k_out.into(),
};
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
@@ -66,7 +72,7 @@ where
let data: i64 = 17;
let mut lwe_pt_in: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(base2k.into(), k_lwe_pt.into());
let mut lwe_pt_in: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc(base2k_in.into(), k_lwe_pt.into());
lwe_pt_in.encode_i64(data, k_lwe_pt.into());
let mut lwe_ct_in: LWE<Vec<u8>> = LWE::alloc_from_infos(&lwe_in_infos);
@@ -76,6 +82,7 @@ where
&sk_lwe_in,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let mut ksk: LWESwitchingKey<Vec<u8>> = LWESwitchingKey::alloc_from_infos(&key_apply_infos);
@@ -97,7 +104,18 @@ where
lwe_ct_out.keyswitch(module, &lwe_ct_in, &ksk_prepared, scratch.borrow());
let mut lwe_pt_out: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_from_infos(&lwe_out_infos);
lwe_ct_out.decrypt(module, &mut lwe_pt_out, &sk_lwe_out);
lwe_ct_out.decrypt(module, &mut lwe_pt_out, &sk_lwe_out, scratch.borrow());
assert_eq!(lwe_pt_in.data.at(0, 0)[0], lwe_pt_out.data.at(0, 0)[0]);
let mut lwe_pt_want: LWEPlaintext<Vec<u8>> = LWEPlaintext::alloc_from_infos(&lwe_out_infos);
module.vec_znx_normalize(
base2k_out,
lwe_pt_want.data_mut(),
0,
base2k_in,
lwe_pt_in.data(),
0,
scratch.borrow(),
);
assert_eq!(lwe_pt_want.data.at(0, 0)[0], lwe_pt_out.data.at(0, 0)[0]);
}