fix cross-base2k vec_znx_normalize wrong early carry

This commit is contained in:
Pro7ech
2025-11-17 16:45:50 +01:00
parent 2613bf1450
commit 08d3f55af9
13 changed files with 101 additions and 115 deletions

View File

@@ -105,8 +105,6 @@ where
{
let res: &mut GGSWCompressed<&mut [u8]> = &mut res.to_mut();
println!("res.seed: {:?}", res.seed);
let (mut tmp_pt, scratch_1) = scratch.take_glwe_plaintext(res);
let mut source = Source::new(seed_xa);

View File

@@ -516,8 +516,6 @@ where
// ct[i] = uniform (+ pt)
self.vec_znx_fill_uniform(base2k, ct, col_ct, source_xa);
// println!("vec_znx_fill_uniform: {}", ct);
let (mut ci_dft, scratch_3) = scratch_2.take_vec_znx_dft(self, 1, size);
// ci = ct[i] - pt

View File

@@ -62,8 +62,6 @@ where
let noise_have: f64 = pt.data.stats(base2k, 0).std().log2();
println!("noise_have: {noise_have}");
assert!(
noise_have <= max_noise,
"noise_have: {noise_have} > max_noise: {max_noise}"

View File

@@ -6,64 +6,7 @@ mod serialization;
#[allow(unused_imports)]
use poulpy_hal::backend_test_suite;
#[cfg(test)]
backend_test_suite!(
mod cpu_spqlios,
backend = poulpy_backend::cpu_spqlios::FFT64Spqlios,
size = 1<<8,
tests = {
//GLWE Encryption
glwe_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_sk,
glwe_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_compressed_encrypt_sk,
glwe_encrypt_zero_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_zero_sk,
glwe_encrypt_pk => crate::tests::test_suite::encryption::test_glwe_encrypt_pk,
// GLWE Keyswitch
glwe_keyswitch => crate::tests::test_suite::keyswitch::test_glwe_keyswitch,
glwe_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_glwe_keyswitch_inplace,
// GLWE Automorphism
glwe_automorphism => crate::tests::test_suite::automorphism::test_glwe_automorphism,
glwe_automorphism_inplace => crate::tests::test_suite::automorphism::test_glwe_automorphism_inplace,
// GLWE External Product
glwe_external_product => crate::tests::test_suite::external_product::test_glwe_external_product,
glwe_external_product_inplace => crate::tests::test_suite::external_product::test_glwe_external_product_inplace,
// GLWE Trace
glwe_trace_inplace => crate::tests::test_suite::test_glwe_trace_inplace,
glwe_packing => crate::tests::test_suite::test_glwe_packer,
// GGLWE Encryption
gglwe_switching_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_encrypt_sk,
gglwe_switching_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_switching_key_compressed_encrypt_sk,
gglwe_automorphism_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphism_key_encrypt_sk,
gglwe_automorphism_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_automorphism_key_compressed_encrypt_sk,
gglwe_tensor_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_encrypt_sk,
gglwe_tensor_key_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_tensor_key_compressed_encrypt_sk,
gglwe_to_ggsw_key_encrypt_sk => crate::tests::test_suite::encryption::test_gglwe_to_ggsw_key_encrypt_sk,
// GGLWE Keyswitching
gglwe_switching_key_keyswitch => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch,
gglwe_switching_key_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_gglwe_switching_key_keyswitch_inplace,
// GGLWE External Product
gglwe_switching_key_external_product => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product,
gglwe_switching_key_external_product_inplace => crate::tests::test_suite::external_product::test_gglwe_switching_key_external_product_inplace,
// GGLWE Automorphism
gglwe_automorphism_key_automorphism => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism,
gglwe_automorphism_key_automorphism_inplace => crate::tests::test_suite::automorphism::test_gglwe_automorphism_key_automorphism_inplace,
// GGSW Encryption
ggsw_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_encrypt_sk,
ggsw_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_ggsw_compressed_encrypt_sk,
// GGSW Keyswitching
ggsw_keyswitch => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch,
ggsw_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_ggsw_keyswitch_inplace,
// GGSW External Product
ggsw_external_product => crate::tests::test_suite::external_product::test_ggsw_external_product,
ggsw_external_product_inplace => crate::tests::test_suite::external_product::test_ggsw_external_product_inplace,
// GGSW Automorphism
ggsw_automorphism => crate::tests::test_suite::automorphism::test_ggsw_automorphism,
ggsw_automorphism_inplace => crate::tests::test_suite::automorphism::test_ggsw_automorphism_inplace,
// LWE
lwe_keyswitch => crate::tests::test_suite::keyswitch::test_lwe_keyswitch,
glwe_to_lwe => crate::tests::test_suite::test_glwe_to_lwe,
lwe_to_glwe => crate::tests::test_suite::test_lwe_to_glwe,
}
);
#[cfg(test)]
backend_test_suite!(
mod cpu_ref,
@@ -75,9 +18,11 @@ backend_test_suite!(
glwe_compressed_encrypt_sk => crate::tests::test_suite::encryption::test_glwe_compressed_encrypt_sk,
glwe_encrypt_zero_sk => crate::tests::test_suite::encryption::test_glwe_encrypt_zero_sk,
glwe_encrypt_pk => crate::tests::test_suite::encryption::test_glwe_encrypt_pk,
// GLWE Base2k Conversion
glwe_base2k_conv => crate::tests::test_suite::test_glwe_base2k_conversion,
// GLWE Keyswitch
glwe_keyswitch => crate::tests::test_suite::keyswitch::test_glwe_keyswitch,
glwe_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_glwe_keyswitch_inplace,
//glwe_keyswitch_inplace => crate::tests::test_suite::keyswitch::test_glwe_keyswitch_inplace,
// GLWE Automorphism
glwe_automorphism => crate::tests::test_suite::automorphism::test_glwe_automorphism,
glwe_automorphism_inplace => crate::tests::test_suite::automorphism::test_glwe_automorphism_inplace,

View File

@@ -1,20 +1,88 @@
use poulpy_hal::{
api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow},
layouts::{Backend, Module, Scratch, ScratchOwned, ZnxView},
api::{ScratchAvailable, ScratchOwnedAlloc, ScratchOwnedBorrow, VecZnxFillUniform},
layouts::{Backend, FillUniform, Module, Scratch, ScratchOwned, ZnxView},
source::Source,
};
use rug::Float;
use crate::{
GLWEDecrypt, GLWEEncryptSk, GLWEFromLWE, GLWEToLWESwitchingKeyEncryptSk, LWEDecrypt, LWEEncryptSk, LWEFromGLWE,
LWEToGLWESwitchingKeyEncryptSk, ScratchTakeCore,
layouts::{
Base2K, Degree, Dnum, GLWE, GLWELayout, GLWEPlaintext, GLWESecret, GLWESecretPreparedFactory, GLWEToLWEKey,
GLWEToLWEKeyLayout, GLWEToLWEKeyPrepared, GLWEToLWEKeyPreparedFactory, LWE, LWELayout, LWEPlaintext, LWESecret,
LWEToGLWEKey, LWEToGLWEKeyLayout, LWEToGLWEKeyPrepared, LWEToGLWEKeyPreparedFactory, Rank, TorusPrecision,
prepared::GLWESecretPrepared,
},
GLWEDecrypt, GLWEEncryptSk, GLWEFromLWE, GLWENoise, GLWENormalize, GLWEToLWESwitchingKeyEncryptSk, LWEDecrypt, LWEEncryptSk, LWEFromGLWE, LWEToGLWESwitchingKeyEncryptSk, SIGMA, ScratchTakeCore, layouts::{
Base2K, Degree, Dnum, GLWE, GLWELayout, GLWEPlaintext, GLWESecret, GLWESecretPreparedFactory, GLWEToLWEKey, GLWEToLWEKeyLayout, GLWEToLWEKeyPrepared, GLWEToLWEKeyPreparedFactory, LWE, LWEInfos, LWELayout, LWEPlaintext, LWESecret, LWEToGLWEKey, LWEToGLWEKeyLayout, LWEToGLWEKeyPrepared, LWEToGLWEKeyPreparedFactory, Rank, TorusPrecision, prepared::GLWESecretPrepared
}
};
pub fn test_glwe_base2k_conversion<BE: Backend>(module: &Module<BE>)
where
Module<BE>: GLWEEncryptSk<BE>
+ GLWEDecrypt<BE>
+ GLWENormalize<BE>
+ VecZnxFillUniform
+ GLWESecretPreparedFactory<BE>
+ GLWENoise<BE>,
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let n_glwe: Degree = Degree(module.n() as u32);
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]);
for rank in 1_usize..3 {
for bases in [[12, 8], [8, 12]] {
let glwe_infos_in: GLWELayout = GLWELayout {
n: n_glwe,
base2k: Base2K(bases[0]),
k: TorusPrecision(34),
rank: Rank(rank as u32),
};
let glwe_infos_out: GLWELayout = GLWELayout {
n: n_glwe,
base2k: Base2K(bases[1]),
k: TorusPrecision(34),
rank: Rank(rank as u32),
};
let mut sk: GLWESecret<Vec<u8>> = GLWESecret::alloc(module.n().into(), rank.into());
sk.fill_ternary_prob(0.5, &mut source_xs);
let mut sk_prep: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc_from_infos(module, &sk);
sk_prep.prepare(module, &sk);
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
GLWE::encrypt_sk_tmp_bytes(module, &glwe_infos_in).max(GLWE::decrypt_tmp_bytes(module, &glwe_infos_out)),
);
let mut ct_in: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos_in);
let mut ct_out: GLWE<Vec<u8>> = GLWE::alloc_from_infos(&glwe_infos_out);
let pt_in: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos_in);
let pt_out: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&glwe_infos_in);
ct_in.encrypt_sk(
module,
&pt_in,
&sk_prep,
&mut source_xa,
&mut source_xe,
scratch.borrow(),
);
let mut data: Vec<Float> = (0..module.n()).map(|_| Float::with_val(128, 0)).collect();
ct_in.data().decode_vec_float(ct_in.base2k().into(), 0, &mut data);
ct_out.fill_uniform(ct_out.base2k().into(),&mut source_xa);
module.glwe_normalize(&mut ct_out, &ct_in, scratch.borrow());
let mut data_conv: Vec<Float> = (0..module.n()).map(|_| Float::with_val(128, 0)).collect();
ct_out.data().decode_vec_float(ct_out.base2k().into(), 0, &mut data_conv);
ct_out.assert_noise(module, &sk_prep, &pt_out, -(ct_out.k().as_u32() as f64) + SIGMA.log2() + 0.5);
}
}
}
pub fn test_lwe_to_glwe<BE: Backend>(module: &Module<BE>)
where
Module<BE>: GLWEFromLWE<BE>

View File

@@ -79,8 +79,6 @@ where
);
}
println!("pt_want: {}", pt_want.as_vec_znx());
module.gglwe_assert_noise(key.at(i), &sk_prepared, &pt_want, max_noise);
}
}

View File

@@ -92,7 +92,7 @@ where
let k_pt: usize = 30;
for rank in 1_usize..3 {
// println!("rank: {}", rank);
let n: usize = module.n();
let glwe_infos: GLWELayout = GLWELayout {

View File

@@ -28,36 +28,37 @@ where
ScratchOwned<BE>: ScratchOwnedAlloc<BE> + ScratchOwnedBorrow<BE>,
Scratch<BE>: ScratchAvailable + ScratchTakeCore<BE>,
{
let base2k: usize = 12;
let base2k_glwe: usize = 12;
let base2k_gglwe: usize = 8;
let k_in: usize = 45;
let dsize: usize = k_in.div_ceil(base2k);
let dsize: usize = k_in.div_ceil(base2k_gglwe);
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_in + base2k * di;
for di in 1_usize..dsize+1 {
let k_ksk: usize = k_in + base2k_gglwe * di;
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_gglwe * dsize);
let glwe_in_infos: GLWELayout = GLWELayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_glwe.into(),
k: k_in.into(),
rank: rank_in.into(),
};
let glwe_out_infos: GLWELayout = GLWELayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_glwe.into(),
k: k_out.into(),
rank: rank_out.into(),
};
let ksk: GLWESwitchingKeyLayout = GLWESwitchingKeyLayout {
n: n.into(),
base2k: base2k.into(),
base2k: base2k_gglwe.into(),
k: k_ksk.into(),
dnum: dnum.into(),
dsize: di.into(),
@@ -74,7 +75,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_glwe, &mut pt_want.data, 0, &mut source_xa);
let mut scratch: ScratchOwned<BE> = ScratchOwned::alloc(
GLWESwitchingKey::encrypt_sk_tmp_bytes(module, &ksk)
@@ -120,7 +121,7 @@ where
let max_noise: f64 = log2_std_noise_gglwe_product(
module.n() as f64,
base2k * dsize,
base2k_gglwe * dsize,
0.5,
0.5,
0f64,

View File

@@ -32,7 +32,7 @@ impl<D: DataRef> VecZnx<D> {
data.iter().for_each(|x| {
avg.add_assign_round(x, Round::Nearest);
max.max_mut(&Float::with_val(53, x.abs_ref()));
max.max_mut(&Float::with_val(prec, x.abs_ref()));
});
avg.div_assign_round(Float::with_val(prec, data.len()), Round::Nearest);
data.iter_mut().for_each(|x| {

View File

@@ -95,9 +95,9 @@ pub fn vec_znx_normalize<R, A, ZNXARI>(
// Get carry for limbs of a that have higher precision than res
for j in (a_min_size..a_size).rev() {
if j == a_size - 1 {
ZNXARI::znx_normalize_first_step_carry_only(res_base2k, 0, a.at(a_col, j), carry);
ZNXARI::znx_normalize_first_step_carry_only(a_base2k, 0, a.at(a_col, j), carry);
} else {
ZNXARI::znx_normalize_middle_step_carry_only(res_base2k, 0, a.at(a_col, j), carry);
ZNXARI::znx_normalize_middle_step_carry_only(a_base2k, 0, a.at(a_col, j), carry);
}
}
@@ -118,6 +118,10 @@ pub fn vec_znx_normalize<R, A, ZNXARI>(
// for the current limb.
let mut res_left: usize = res_base2k;
for j in 0..res_size {
ZNXARI::znx_zero(res.at_mut(res_col, j));
}
for j in (0..a_min_size).rev() {
// Trackers: wow much of a_norm is left to
// be flushed on res.
@@ -196,10 +200,6 @@ pub fn vec_znx_normalize<R, A, ZNXARI>(
}
}
}
for j in res_min_size..res_size {
ZNXARI::znx_zero(res.at_mut(res_col, j));
}
}
}
@@ -380,14 +380,6 @@ fn test_vec_znx_normalize_conv() {
err.sub_assign_round(&data_res[i], Round::Nearest);
err = err.abs();
// println!(
// "want: {} have: {} tmp: {} (want-have): {}",
// data_want[i].to_f64(),
// data_res[i].to_f64(),
// data_tmp[i].to_f64(),
// err.to_f64()
// );
let err_log2: f64 = err
.clone()
.max(&Float::with_val(prec as u32, 1e-60))

View File

@@ -49,8 +49,6 @@ where
a_enc.sext(module, j, keys, scratch.borrow());
// println!("{:08x} -> {:08x} {:08x}", a, sext(a, j), a_enc.decrypt(module, sk, scratch.borrow()));
assert_eq!(
sext(a, ((1 + j as u32) << 3) - 1),
a_enc.decrypt(module, sk, scratch.borrow())
@@ -70,8 +68,6 @@ where
a_enc.sext(module, j, keys, scratch.borrow());
// println!("{:08x} -> {:08x} {:08x}", a, sext(a, j), a_enc.decrypt(module, sk, scratch.borrow()));
assert_eq!(
sext(a, ((1 + j as u32) << 3) - 1),
a_enc.decrypt(module, sk, scratch.borrow())

View File

@@ -76,8 +76,6 @@ where
let k: u32 = source.next_u32();
// println!("k: {k}");
let mut k_enc_prep: FheUintPrepared<Vec<u8>, u32, BE> =
FheUintPrepared::<Vec<u8>, u32, BE>::alloc_from_infos(module, &ggsw_k_infos);
k_enc_prep.encrypt_sk(

View File

@@ -328,12 +328,6 @@ pub fn circuit_bootstrap_core<R, L, D, M, BRA: BlindRotationAlgo, BE: Backend>(
tmp_glwe.trace(module, 0, &res_glwe, &key.atk, scratch_2);
}
// let sk_glwe: &poulpy_core::layouts::GLWESecret<&[u8]> = &sk_glwe.to_ref();
// let sk_glwe_prepared: GLWESecretPrepared<Vec<u8>, BE> = GLWESecretPrepared::alloc(module, sk_glwe.rank());
// let mut pt: GLWEPlaintext<Vec<u8>> = GLWEPlaintext::alloc_from_infos(&res_glwe);
// res_glwe.decrypt(module, &mut pt, &sk_glwe_prepared, scratch_2);
// println!("pt[{i}]: {}", pt);
if i < dnum {
module.glwe_rotate_inplace(-(gap as i64), &mut res_glwe, scratch_2);
}