fix cross-base2k vec_znx_normalize wrong early carry
jump to
@@ -105,8 +105,6 @@
{ 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);
@@ -516,8 +516,6 @@
// 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
@@ -62,8 +62,6 @@ self.vec_znx_sub_scalar_inplace(&mut pt.data, 0, (dsize - 1) + row_i * dsize, pt_want, col_i);
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}"
@@ -6,64 +6,7 @@
#[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 @@ 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 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,
@@ -1,19 +1,87 @@
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
@@ -79,8 +79,6 @@ 0,
); } - println!("pt_want: {}", pt_want.as_vec_znx()); - module.gglwe_assert_noise(key.at(i), &sk_prepared, &pt_want, max_noise); } }
@@ -92,7 +92,7 @@ let k_ct: usize = 54;
let k_pt: usize = 30; for rank in 1_usize..3 { - // println!("rank: {}", rank); + let n: usize = module.n(); let glwe_infos: GLWELayout = GLWELayout {
@@ -28,36 +28,37 @@ + GLWENoise<BE>,
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 @@ 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_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 @@ glwe_out.keyswitch(module, &glwe_in, &ksk_prepared, scratch.borrow());
let max_noise: f64 = log2_std_noise_gglwe_product( module.n() as f64, - base2k * dsize, + base2k_gglwe * dsize, 0.5, 0.5, 0f64,
@@ -32,7 +32,7 @@ let mut max: Float = Float::with_val(prec, 0);
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| {
@@ -95,9 +95,9 @@
// 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); } }@@ -117,6 +117,10 @@
// Trackers: wow much of res is left to be populated // 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@@ -195,10 +199,6 @@ ZNXARI::znx_add_inplace(carry, a_norm);
break; } } - } - - for j in res_min_size..res_size { - ZNXARI::znx_zero(res.at_mut(res_col, j)); } } }@@ -379,14 +379,6 @@ for i in 0..n {
let mut err: Float = data_want[i].clone(); 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()
@@ -49,8 +49,6 @@ );
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())@@ -69,8 +67,6 @@ scratch.borrow(),
); 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),
@@ -76,8 +76,6 @@ .for_each(|(i, x)| *x = i as i64);
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(
@@ -328,12 +328,6 @@ } else {
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); }