arnaucube
arnaucube/poulpyPublic Self-hosted repository
conversions
Pro7ech jeanphilippe.bossuat@gmail.com
Thu, 16 Oct 2025 22:40:23 +0200
commit

920b9252162ee5704592b75b252d1dfd8424457f

parent

93e0671edad6583e0a5be1322139981fcc3248b1

2 files changed, 174 insertions(+), 137 deletions(-)

jump to
M poulpy-core/src/conversion/glwe_to_lwe.rs → poulpy-core/src/conversion/glwe_to_lwe.rs

@@ -1,100 +1,125 @@

use poulpy_hal::{ - api::{ - VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftApply, VecZnxDftBytesOf, - VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, - VmpApplyDftToDftTmpBytes, + api::ModuleN, + layouts::{Backend, DataMut, Module, Scratch, ZnxView, ZnxViewMut, ZnxZero}, +}; + +use crate::{ + GLWEKeyswitch, ScratchTakeCore, + layouts::{ + GGLWEInfos, GLWE, GLWEAlloc, GLWEInfos, GLWELayout, GLWEToRef, LWE, LWEInfos, LWEToMut, Rank, + prepared::{LWEToGLWESwitchingKeyPrepared, LWEToGLWESwitchingKeyPreparedToRef}, }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxView, ZnxViewMut, ZnxZero}, }; -use crate::layouts::{GGLWEInfos, GLWE, GLWEInfos, GLWELayout, LWE, LWEInfos, Rank, prepared::GLWEToLWESwitchingKeyPrepared}; +pub trait LWESampleExtract +where + Self: ModuleN, +{ + fn lwe_sample_extract<R, A>(&self, res: &mut R, a: &A) + where + R: LWEToMut, + A: GLWEToRef, + { + let res: &mut LWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); -impl LWE<Vec<u8>> { - pub fn from_glwe_tmp_bytes<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - lwe_infos: &OUT, - glwe_infos: &IN, - key_infos: &KEY, - ) -> usize + assert!(res.n() <= a.n()); + assert_eq!(a.n(), self.n() as u32); + assert!(res.base2k() == a.base2k()); + + let min_size: usize = res.size().min(a.size()); + let n: usize = res.n().into(); + + res.data.zero(); + (0..min_size).for_each(|i| { + let data_lwe: &mut [i64] = res.data.at_mut(0, i); + data_lwe[0] = a.data.at(0, i)[0]; + data_lwe[1..].copy_from_slice(&a.data.at(1, i)[..n]); + }); + } +} + +impl<BE: Backend> LWESampleExtract for Module<BE> where Self: ModuleN {} +impl<BE: Backend> LWEFromGLWE<BE> for Module<BE> where Self: GLWEKeyswitch<BE> + GLWEAlloc + LWESampleExtract {} + +pub trait LWEFromGLWE<BE: Backend> +where + Self: GLWEKeyswitch<BE> + GLWEAlloc + LWESampleExtract, +{ + fn lwe_from_glwe_tmp_bytes<R, A, K>(&self, lwe_infos: &R, glwe_infos: &A, key_infos: &K) -> usize where - OUT: LWEInfos, - IN: GLWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + R: LWEInfos, + A: GLWEInfos, + K: GGLWEInfos, { - let glwe_layout: GLWELayout = GLWELayout { - n: module.n().into(), + let res_infos: GLWELayout = GLWELayout { + n: self.n().into(), base2k: lwe_infos.base2k(), k: lwe_infos.k(), rank: Rank(1), }; - GLWE::bytes_of( - module.n().into(), - lwe_infos.base2k(), - lwe_infos.k(), - 1u32.into(), - ) + GLWE::keyswitch_tmp_bytes(module, &glwe_layout, glwe_infos, key_infos) + self.bytes_of_glwe(lwe_infos.base2k(), lwe_infos.k(), 1u32.into()) + + self.glwe_keyswitch_tmp_bytes(&res_infos, glwe_infos, key_infos) } -} -impl<DLwe: DataMut> LWE<DLwe> { - pub fn sample_extract<DGlwe: DataRef>(&mut self, a: &GLWE<DGlwe>) { - #[cfg(debug_assertions)] - { - assert!(self.n() <= a.n()); - assert!(self.base2k() == a.base2k()); - } + fn lwe_from_glwe<R, A, K>(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + R: LWEToMut, + A: GLWEToRef, + K: LWEToGLWESwitchingKeyPreparedToRef<BE> + GGLWEInfos, + Scratch<BE>: ScratchTakeCore<BE>, + { + let res: &mut LWE<&mut [u8]> = &mut res.to_mut(); + let a: &GLWE<&[u8]> = &a.to_ref(); + let key: &LWEToGLWESwitchingKeyPrepared<&[u8], BE> = &key.to_ref(); + + assert_eq!(a.n(), self.n() as u32); + assert_eq!(key.n(), self.n() as u32); + assert!(res.n() <= self.n() as u32); - let min_size: usize = self.size().min(a.size()); - let n: usize = self.n().into(); + let glwe_layout: GLWELayout = GLWELayout { + n: self.n().into(), + base2k: res.base2k(), + k: res.k(), + rank: Rank(1), + }; - self.data.zero(); - (0..min_size).for_each(|i| { - let data_lwe: &mut [i64] = self.data.at_mut(0, i); - data_lwe[0] = a.data.at(0, i)[0]; - data_lwe[1..].copy_from_slice(&a.data.at(1, i)[..n]); - }); + let (mut tmp_glwe, scratch_1) = scratch.take_glwe_ct(self, &glwe_layout); + self.glwe_keyswitch(&mut tmp_glwe, a, &key.0, scratch_1); + self.lwe_sample_extract(res, &tmp_glwe); } +} - pub fn from_glwe<DGlwe, DKs, B: Backend>( - &mut self, - module: &Module<B>, - a: &GLWE<DGlwe>, - ks: &GLWEToLWESwitchingKeyPrepared<DKs, B>, - scratch: &mut Scratch<B>, - ) where - DGlwe: DataRef, - DKs: DataRef, - Module<B>: VecZnxDftBytesOf - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>:, +impl LWE<Vec<u8>> { + pub fn from_glwe_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, lwe_infos: &R, glwe_infos: &A, key_infos: &K) -> usize + where + R: LWEInfos, + A: GLWEInfos, + K: GGLWEInfos, + M: LWEFromGLWE<BE>, { - #[cfg(debug_assertions)] - { - assert_eq!(a.n(), module.n() as u32); - assert_eq!(ks.n(), module.n() as u32); - assert!(self.n() <= module.n() as u32); - } + module.lwe_from_glwe_tmp_bytes(lwe_infos, glwe_infos, key_infos) + } +} - let glwe_layout: GLWELayout = GLWELayout { - n: module.n().into(), - base2k: self.base2k(), - k: self.k(), - rank: Rank(1), - }; +impl<D: DataMut> LWE<D> { + pub fn sample_extract<A, M>(&mut self, module: &M, a: &A) + where + A: GLWEToRef, + M: LWESampleExtract, + { + module.lwe_sample_extract(self, a); + } - let (mut tmp_glwe, scratch_1) = scratch.take_glwe_ct(&glwe_layout); - tmp_glwe.keyswitch(module, a, &ks.0, scratch_1); - self.sample_extract(&tmp_glwe); + pub fn from_glwe<R, A, K, M, BE: Backend>(&self, module: &M, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>) + where + R: LWEToMut, + A: GLWEToRef, + K: LWEToGLWESwitchingKeyPreparedToRef<BE> + GGLWEInfos, + M: LWEFromGLWE<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.lwe_from_glwe(res, a, key, scratch); } }
M poulpy-core/src/conversion/lwe_to_glwe.rs → poulpy-core/src/conversion/lwe_to_glwe.rs

@@ -1,79 +1,67 @@

use poulpy_hal::{ - api::{ - ScratchAvailable, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftApply, - VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, - VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, + api::ScratchTakeBasic, + layouts::{Backend, DataMut, Module, Scratch, VecZnx, ZnxView, ZnxViewMut, ZnxZero}, +}; + +use crate::{ + GLWEKeyswitch, ScratchTakeCore, + layouts::{ + GGLWEInfos, GLWE, GLWEAlloc, GLWEInfos, GLWELayout, GLWEToMut, LWE, LWEInfos, LWEToRef, + prepared::{LWEToGLWESwitchingKeyPrepared, LWEToGLWESwitchingKeyPreparedToRef}, }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnx, ZnxView, ZnxViewMut, ZnxZero}, }; -use crate::layouts::{GGLWEInfos, GLWE, GLWEInfos, GLWELayout, LWE, LWEInfos, prepared::LWEToGLWESwitchingKeyPrepared}; +impl<BE: Backend> GLWEFromLWE<BE> for Module<BE> where Self: GLWEKeyswitch<BE> + GLWEAlloc {} -impl GLWE<Vec<u8>> { - pub fn from_lwe_tmp_bytes<B: Backend, OUT, IN, KEY>( - module: &Module<B>, - glwe_infos: &OUT, - lwe_infos: &IN, - key_infos: &KEY, - ) -> usize +pub trait GLWEFromLWE<BE: Backend> +where + Self: GLWEKeyswitch<BE> + GLWEAlloc, +{ + fn glwe_from_lwe_tmp_bytes<R, A, K>(&self, glwe_infos: &R, lwe_infos: &A, key_infos: &K) -> usize where - OUT: GLWEInfos, - IN: LWEInfos, - KEY: GGLWEInfos, - Module<B>: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, + R: GLWEInfos, + A: LWEInfos, + K: GGLWEInfos, { - let ct: usize = GLWE::bytes_of( - module.n().into(), + let ct: usize = self.bytes_of_glwe( key_infos.base2k(), lwe_infos.k().max(glwe_infos.k()), 1u32.into(), ); - let ks: usize = GLWE::keyswitch_inplace_tmp_bytes(module, glwe_infos, key_infos); + + let ks: usize = self.glwe_keyswitch_tmp_bytes(glwe_infos, glwe_infos, key_infos); if lwe_infos.base2k() == key_infos.base2k() { ct + ks } else { - let a_conv = VecZnx::bytes_of(module.n(), 1, lwe_infos.size()) + module.vec_znx_normalize_tmp_bytes(); + let a_conv = VecZnx::bytes_of(self.n(), 1, lwe_infos.size()) + self.vec_znx_normalize_tmp_bytes(); ct + a_conv + ks } } -} -impl<D: DataMut> GLWE<D> { - pub fn from_lwe<DLwe, DKsk, B: Backend>( - &mut self, - module: &Module<B>, - lwe: &LWE<DLwe>, - ksk: &LWEToGLWESwitchingKeyPrepared<DKsk, B>, - scratch: &mut Scratch<B>, - ) where - DLwe: DataRef, - DKsk: DataRef, - Module<B>: VecZnxDftBytesOf - + VmpApplyDftToDftTmpBytes - + VecZnxBigNormalizeTmpBytes - + VmpApplyDftToDft<B> - + VmpApplyDftToDftAdd<B> - + VecZnxDftApply<B> - + VecZnxIdftApplyConsume<B> - + VecZnxBigAddSmallInplace<B> - + VecZnxBigNormalize<B> - + VecZnxNormalize<B> - + VecZnxNormalizeTmpBytes, - Scratch<B>: ScratchAvailable, + fn glwe_from_lwe<R, A, K>(&self, res: &mut R, lwe: &A, ksk: &K, scratch: &mut Scratch<BE>) + where + R: GLWEToMut, + A: LWEToRef, + K: LWEToGLWESwitchingKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, { - #[cfg(debug_assertions)] - { - assert_eq!(self.n(), module.n() as u32); - assert_eq!(ksk.n(), module.n() as u32); - assert!(lwe.n() <= module.n() as u32); - } + let res: &mut GLWE<&mut [u8]> = &mut res.to_mut(); + let lwe: &LWE<&[u8]> = &lwe.to_ref(); + let ksk: &LWEToGLWESwitchingKeyPrepared<&[u8], BE> = &ksk.to_ref(); + + assert_eq!(res.n(), self.n() as u32); + assert_eq!(ksk.n(), self.n() as u32); + assert!(lwe.n() <= self.n() as u32); - let (mut glwe, scratch_1) = scratch.take_glwe_ct(&GLWELayout { - n: ksk.n(), - base2k: ksk.base2k(), - k: lwe.k(), - rank: 1u32.into(), - }); + let (mut glwe, scratch_1) = scratch.take_glwe_ct( + self, + &GLWELayout { + n: ksk.n(), + base2k: ksk.base2k(), + k: lwe.k(), + rank: 1u32.into(), + }, + ); glwe.data.zero(); let n_lwe: usize = lwe.n().into();

@@ -85,14 +73,14 @@ glwe.data.at_mut(0, i)[0] = data_lwe[0];

glwe.data.at_mut(1, i)[..n_lwe].copy_from_slice(&data_lwe[1..]); } } else { - let (mut a_conv, scratch_2) = scratch_1.take_vec_znx(module.n(), 1, lwe.size()); + let (mut a_conv, scratch_2) = scratch_1.take_vec_znx(self, 1, lwe.size()); a_conv.zero(); for j in 0..lwe.size() { let data_lwe: &[i64] = lwe.data.at(0, j); a_conv.at_mut(0, j)[0] = data_lwe[0] } - module.vec_znx_normalize( + self.vec_znx_normalize( ksk.base2k().into(), &mut glwe.data, 0,

@@ -108,7 +96,7 @@ let data_lwe: &[i64] = lwe.data.at(0, j);

a_conv.at_mut(0, j)[..n_lwe].copy_from_slice(&data_lwe[1..]); } - module.vec_znx_normalize( + self.vec_znx_normalize( ksk.base2k().into(), &mut glwe.data, 1,

@@ -119,6 +107,30 @@ scratch_2,

); } - self.keyswitch(module, &glwe, &ksk.0, scratch_1); + self.glwe_keyswitch(res, &glwe, &ksk.0, scratch_1); + } +} + +impl GLWE<Vec<u8>> { + pub fn from_lwe_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, glwe_infos: &R, lwe_infos: &A, key_infos: &K) -> usize + where + R: GLWEInfos, + A: LWEInfos, + K: GGLWEInfos, + M: GLWEFromLWE<BE>, + { + module.glwe_from_lwe_tmp_bytes(glwe_infos, lwe_infos, key_infos) + } +} + +impl<D: DataMut> GLWE<D> { + pub fn from_lwe<A, K, M, BE: Backend>(&mut self, module: &M, lwe: &A, ksk: &K, scratch: &mut Scratch<BE>) + where + M: GLWEFromLWE<BE>, + A: LWEToRef, + K: LWEToGLWESwitchingKeyPreparedToRef<BE>, + Scratch<BE>: ScratchTakeCore<BE>, + { + module.glwe_from_lwe(self, lwe, ksk, scratch); } }