From 2559d8ea81c7416fd5065a570fe7da8b6da4eaa5 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bossuat Date: Fri, 16 Jan 2026 18:14:07 +0100 Subject: [PATCH] Fix #130 & #131 (#132) * fix #131 * fix #130 * update CHANGELOG.md --- CHANGELOG.md | 5 ++ poulpy-core/src/decryption/glwe.rs | 60 ++++++++++--------- poulpy-core/src/encryption/glwe_public_key.rs | 7 +-- poulpy-core/src/layouts/glwe_plaintext.rs | 4 +- poulpy-core/src/layouts/glwe_tensor.rs | 1 + poulpy-core/src/noise/gglwe.rs | 8 +-- poulpy-core/src/noise/glwe.rs | 6 +- 7 files changed, 49 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b5c0d1..40b5193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## [0.4.3] - 2026-01-16 + +- Fix [#131](https://github.com/phantomzone-org/poulpy/issues/131) +- Fix [#130](https://github.com/phantomzone-org/poulpy/issues/130) + ## [0.4.2] - 2025-12-21 ## `poulpy-core` diff --git a/poulpy-core/src/decryption/glwe.rs b/poulpy-core/src/decryption/glwe.rs index f558fe4..db3d2ec 100644 --- a/poulpy-core/src/decryption/glwe.rs +++ b/poulpy-core/src/decryption/glwe.rs @@ -7,8 +7,7 @@ use poulpy_hal::{ }; use crate::layouts::{ - GLWE, GLWEInfos, GLWEPlaintext, GLWEPlaintextToMut, GLWEToRef, LWEInfos, - prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, + GLWE, GLWEInfos, GLWEPlaintextToMut, GLWESecretPrepared, GLWEToRef, LWEInfos, SetGLWEInfos, prepared::GLWESecretPreparedToRef, }; impl GLWE> { @@ -24,8 +23,8 @@ impl GLWE> { impl GLWE { pub fn decrypt(&self, module: &M, pt: &mut P, sk: &S, scratch: &mut Scratch) where - P: GLWEPlaintextToMut, - S: GLWESecretPreparedToRef, + P: GLWEPlaintextToMut + GLWEInfos + SetGLWEInfos, + S: GLWESecretPreparedToRef + GLWEInfos, M: GLWEDecrypt, Scratch: ScratchTakeBasic, { @@ -40,9 +39,9 @@ pub trait GLWEDecrypt { fn glwe_decrypt(&self, res: &R, pt: &mut P, sk: &S, scratch: &mut Scratch) where - R: GLWEToRef, - P: GLWEPlaintextToMut, - S: GLWESecretPreparedToRef; + R: GLWEToRef + GLWEInfos, + P: GLWEPlaintextToMut + GLWEInfos + SetGLWEInfos, + S: GLWESecretPreparedToRef + GLWEInfos; } impl GLWEDecrypt for Module @@ -69,17 +68,16 @@ where fn glwe_decrypt(&self, res: &R, pt: &mut P, sk: &S, scratch: &mut Scratch) where - R: GLWEToRef, - P: GLWEPlaintextToMut, - S: GLWESecretPreparedToRef, + R: GLWEToRef + GLWEInfos, + P: GLWEPlaintextToMut + GLWEInfos + SetGLWEInfos, + S: GLWESecretPreparedToRef + GLWEInfos, { let res: &GLWE<&[u8]> = &res.to_ref(); - let pt: &mut GLWEPlaintext<&mut [u8]> = &mut pt.to_ref(); let sk: &GLWESecretPrepared<&[u8], BE> = &sk.to_ref(); #[cfg(debug_assertions)] { - assert_eq!(res.rank(), sk.rank()); + assert_eq!(res.rank(), sk.rank()); //NOTE: res.rank() != res.to_ref().rank() if res is of type GLWETensor assert_eq!(res.n(), sk.n()); assert_eq!(pt.n(), sk.n()); } @@ -89,28 +87,34 @@ where let (mut c0_big, scratch_1) = scratch.take_vec_znx_big(self, 1, res.size()); // TODO optimize size when pt << ct c0_big.data_mut().fill(0); - { - (1..cols).for_each(|i| { - // ci_dft = DFT(a[i]) * DFT(s[i]) - let (mut ci_dft, _) = scratch_1.take_vec_znx_dft(self, 1, res.size()); // TODO optimize size when pt << ct - self.vec_znx_dft_apply(1, 0, &mut ci_dft, 0, &res.data, i); - self.svp_apply_dft_to_dft_inplace(&mut ci_dft, 0, &sk.data, i - 1); - let ci_big = self.vec_znx_idft_apply_consume(ci_dft); + (1..cols).for_each(|i| { + // ci_dft = DFT(a[i]) * DFT(s[i]) + let (mut ci_dft, _) = scratch_1.take_vec_znx_dft(self, 1, res.size()); // TODO optimize size when pt << ct + self.vec_znx_dft_apply(1, 0, &mut ci_dft, 0, res.data(), i); + self.svp_apply_dft_to_dft_inplace(&mut ci_dft, 0, &sk.data, i - 1); + let ci_big = self.vec_znx_idft_apply_consume(ci_dft); - // c0_big += a[i] * s[i] - self.vec_znx_big_add_inplace(&mut c0_big, 0, &ci_big, 0); - }); - } + // c0_big += a[i] * s[i] + self.vec_znx_big_add_inplace(&mut c0_big, 0, &ci_big, 0); + }); // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e) - self.vec_znx_big_add_small_inplace(&mut c0_big, 0, &res.data, 0); + self.vec_znx_big_add_small_inplace(&mut c0_big, 0, res.data(), 0); - let res_base2k: usize = res.base2k().into(); + let pt_base2k: usize = pt.base2k().into(); // pt = norm(BIG(m + e)) - self.vec_znx_big_normalize(&mut pt.data, res_base2k, 0, 0, &c0_big, res_base2k, 0, scratch_1); + self.vec_znx_big_normalize( + pt.to_mut().data_mut(), + pt_base2k, + 0, + 0, + &c0_big, + res.base2k().into(), + 0, + scratch_1, + ); - pt.base2k = res.base2k(); - pt.k = pt.k().min(res.k()); + pt.set_k(pt.k().min(res.k())); } } diff --git a/poulpy-core/src/encryption/glwe_public_key.rs b/poulpy-core/src/encryption/glwe_public_key.rs index 460b037..014fdb2 100644 --- a/poulpy-core/src/encryption/glwe_public_key.rs +++ b/poulpy-core/src/encryption/glwe_public_key.rs @@ -7,7 +7,7 @@ use poulpy_hal::{ use crate::{ Distribution, GLWEEncryptSk, GetDistribution, GetDistributionMut, ScratchTakeCore, layouts::{ - GLWE, GLWEInfos, GLWEPublicKey, GLWEToMut, + GLWEInfos, GLWEPublicKey, GLWEToMut, prepared::{GLWESecretPrepared, GLWESecretPreparedToRef}, }, }; @@ -52,10 +52,7 @@ where // Its ok to allocate scratch space here since pk is usually generated only once. let mut scratch: ScratchOwned = ScratchOwned::alloc(self.glwe_encrypt_sk_tmp_bytes(res)); - - let mut tmp: GLWE> = GLWE::alloc_from_infos(res); - - tmp.encrypt_zero_sk(self, sk, source_xa, source_xe, scratch.borrow()); + res.to_mut().encrypt_zero_sk(self, sk, source_xa, source_xe, scratch.borrow()); } *res.dist_mut() = *sk.dist(); } diff --git a/poulpy-core/src/layouts/glwe_plaintext.rs b/poulpy-core/src/layouts/glwe_plaintext.rs index 27aa1f9..0456f66 100644 --- a/poulpy-core/src/layouts/glwe_plaintext.rs +++ b/poulpy-core/src/layouts/glwe_plaintext.rs @@ -140,11 +140,11 @@ impl GLWEPlaintextToRef for GLWEPlaintext { } pub trait GLWEPlaintextToMut { - fn to_ref(&mut self) -> GLWEPlaintext<&mut [u8]>; + fn to_mut(&mut self) -> GLWEPlaintext<&mut [u8]>; } impl GLWEPlaintextToMut for GLWEPlaintext { - fn to_ref(&mut self) -> GLWEPlaintext<&mut [u8]> { + fn to_mut(&mut self) -> GLWEPlaintext<&mut [u8]> { GLWEPlaintext { base2k: self.base2k, k: self.k, diff --git a/poulpy-core/src/layouts/glwe_tensor.rs b/poulpy-core/src/layouts/glwe_tensor.rs index 5d93563..8353552 100644 --- a/poulpy-core/src/layouts/glwe_tensor.rs +++ b/poulpy-core/src/layouts/glwe_tensor.rs @@ -55,6 +55,7 @@ impl LWEInfos for GLWETensor { } impl GLWEInfos for GLWETensor { + ///NOTE: self.rank() != self.to_ref().rank() if self is of type [GLWETensor] fn rank(&self) -> Rank { self.rank } diff --git a/poulpy-core/src/noise/gglwe.rs b/poulpy-core/src/noise/gglwe.rs index 187c5e4..9a444ed 100644 --- a/poulpy-core/src/noise/gglwe.rs +++ b/poulpy-core/src/noise/gglwe.rs @@ -5,7 +5,7 @@ use poulpy_hal::{ use crate::{ GLWENoise, - layouts::{GGLWE, GGLWEInfos, GGLWEToRef, prepared::GLWESecretPreparedToRef}, + layouts::{GGLWE, GGLWEInfos, GGLWEToRef, GLWEInfos, prepared::GLWESecretPreparedToRef}, }; use crate::{ScratchTakeCore, layouts::GLWEPlaintext}; @@ -20,7 +20,7 @@ impl GGLWE { scratch: &mut Scratch, ) -> Stats where - S: GLWESecretPreparedToRef, + S: GLWESecretPreparedToRef + GLWEInfos, P: ScalarZnxToRef, M: GGLWENoise, { @@ -44,7 +44,7 @@ pub trait GGLWENoise { ) -> Stats where R: GGLWEToRef, - S: GLWESecretPreparedToRef, + S: GLWESecretPreparedToRef + GLWEInfos, P: ScalarZnxToRef; } @@ -71,7 +71,7 @@ where ) -> Stats where R: GGLWEToRef, - S: GLWESecretPreparedToRef, + S: GLWESecretPreparedToRef + GLWEInfos, P: ScalarZnxToRef, { let res: &GGLWE<&[u8]> = &res.to_ref(); diff --git a/poulpy-core/src/noise/glwe.rs b/poulpy-core/src/noise/glwe.rs index 75bcbdd..0f13321 100644 --- a/poulpy-core/src/noise/glwe.rs +++ b/poulpy-core/src/noise/glwe.rs @@ -11,7 +11,7 @@ impl GLWE { where M: GLWENoise, P: GLWEToRef, - S: GLWESecretPreparedToRef, + S: GLWESecretPreparedToRef + GLWEInfos, { module.glwe_noise(self, pt_want, sk_prepared, scratch) } @@ -26,7 +26,7 @@ pub trait GLWENoise { where R: GLWEToRef + GLWEInfos, P: GLWEToRef, - S: GLWESecretPreparedToRef; + S: GLWESecretPreparedToRef + GLWEInfos; } impl GLWENoise for Module @@ -45,7 +45,7 @@ where where R: GLWEToRef + GLWEInfos, P: GLWEToRef, - S: GLWESecretPreparedToRef, + S: GLWESecretPreparedToRef + GLWEInfos, { let (mut pt_have, scratch_1) = scratch.take_glwe_plaintext(res); self.glwe_decrypt(res, &mut pt_have, sk_prepared, scratch_1);