poulpy/poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/block_prepared.rs
poulpy-schemes/src/tfhe/bdd_arithmetic/ciphertexts/block_prepared.rsRaw
1use std::marker::PhantomData;
2
3use poulpy_core::layouts::{
4 Base2K, Dnum, Dsize, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::GGSWCiphertextPrepared,
5};
6#[cfg(test)]
7use poulpy_core::{
8 TakeGGSW,
9 layouts::{GGSWCiphertext, prepared::GLWESecretPrepared},
10};
11use poulpy_hal::{
12 api::VmpPMatAlloc,
13 layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
14};
15#[cfg(test)]
16use poulpy_hal::{
17 api::{
18 ScratchAvailable, SvpApplyDftToDftInplace, TakeScalarZnx, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal,
19 VecZnxAddScalarInplace, VecZnxBigAddInplace, VecZnxBigAddSmallInplace, VecZnxBigAlloc, VecZnxBigAllocBytes,
20 VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftAlloc, VecZnxDftAllocBytes, VecZnxDftApply, VecZnxFillUniform,
21 VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub,
22 VecZnxSubInplace, VmpPrepare,
23 },
24 oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl, TakeVecZnxBigImpl, TakeVecZnxDftImpl},
25 source::Source,
26};
27
28use crate::tfhe::bdd_arithmetic::{FheUintBlocks, FheUintPrepare, ToBits, UnsignedInteger};
29
30#[cfg(test)]
31pub(crate) struct FheUintBlocksPrepDebug<D: Data, T: UnsignedInteger> {
32 pub(crate) blocks: Vec<GGSWCiphertext<D>>,
33 pub(crate) _base: u8,
34 pub(crate) _phantom: PhantomData<T>,
35}
36
37#[cfg(test)]
38impl<T: UnsignedInteger> FheUintBlocksPrepDebug<Vec<u8>, T> {
39 #[allow(dead_code)]
40 pub(crate) fn alloc<A, BE: Backend>(module: &Module<BE>, infos: &A) -> Self
41 where
42 A: GGSWInfos,
43 {
44 Self::alloc_with(
45 module,
46 infos.base2k(),
47 infos.k(),
48 infos.dnum(),
49 infos.dsize(),
50 infos.rank(),
51 )
52 }
53
54 #[allow(dead_code)]
55 pub(crate) fn alloc_with<BE: Backend>(
56 module: &Module<BE>,
57 base2k: Base2K,
58 k: TorusPrecision,
59 dnum: Dnum,
60 dsize: Dsize,
61 rank: Rank,
62 ) -> Self {
63 Self {
64 blocks: (0..T::WORD_SIZE)
65 .map(|_| GGSWCiphertext::alloc_with(module.n().into(), base2k, k, rank, dnum, dsize))
66 .collect(),
67 _base: 1,
68 _phantom: PhantomData,
69 }
70 }
71}
72
73/// A prepared FHE ciphertext encrypting the bits of an [UnsignedInteger].
74pub struct FheUintBlocksPrep<D: Data, B: Backend, T: UnsignedInteger> {
75 pub(crate) blocks: Vec<GGSWCiphertextPrepared<D, B>>,
76 pub(crate) _base: u8,
77 pub(crate) _phantom: PhantomData<T>,
78}
79
80impl<T: UnsignedInteger, BE: Backend> FheUintBlocksPrep<Vec<u8>, BE, T>
81where
82 Module<BE>: VmpPMatAlloc<BE>,
83{
84 #[allow(dead_code)]
85 pub(crate) fn alloc<A>(module: &Module<BE>, infos: &A) -> Self
86 where
87 A: GGSWInfos,
88 {
89 Self::alloc_with(
90 module,
91 infos.base2k(),
92 infos.k(),
93 infos.dnum(),
94 infos.dsize(),
95 infos.rank(),
96 )
97 }
98
99 #[allow(dead_code)]
100 pub(crate) fn alloc_with(module: &Module<BE>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self
101 where
102 Module<BE>: VmpPMatAlloc<BE>,
103 {
104 Self {
105 blocks: (0..T::WORD_SIZE)
106 .map(|_| GGSWCiphertextPrepared::alloc_with(module, base2k, k, dnum, dsize, rank))
107 .collect(),
108 _base: 1,
109 _phantom: PhantomData,
110 }
111 }
112}
113
114impl<D: DataMut, T: UnsignedInteger + ToBits, BE: Backend> FheUintBlocksPrep<D, BE, T> {
115 #[allow(dead_code)]
116 #[cfg(test)]
117 pub(crate) fn encrypt_sk<S>(
118 &mut self,
119 module: &Module<BE>,
120 value: T,
121 sk: &GLWESecretPrepared<S, BE>,
122 source_xa: &mut Source,
123 source_xe: &mut Source,
124 scratch: &mut Scratch<BE>,
125 ) where
126 S: DataRef,
127 Module<BE>: VecZnxAddScalarInplace
128 + VecZnxDftAllocBytes
129 + VecZnxBigNormalize<BE>
130 + VecZnxDftApply<BE>
131 + SvpApplyDftToDftInplace<BE>
132 + VecZnxIdftApplyConsume<BE>
133 + VecZnxNormalizeTmpBytes
134 + VecZnxFillUniform
135 + VecZnxSubInplace
136 + VecZnxAddInplace
137 + VecZnxNormalizeInplace<BE>
138 + VecZnxAddNormal
139 + VecZnxNormalize<BE>
140 + VecZnxSub
141 + VmpPrepare<BE>,
142 Scratch<BE>: TakeVecZnxDft<BE> + ScratchAvailable + TakeVecZnx + TakeGGSW + TakeScalarZnx,
143 {
144 #[cfg(debug_assertions)]
145 {
146 assert!(module.n().is_multiple_of(T::WORD_SIZE));
147 assert_eq!(self.n(), module.n() as u32);
148 assert_eq!(sk.n(), module.n() as u32);
149 }
150
151 let (mut tmp_ggsw, scratch_1) = scratch.take_ggsw(self);
152 let (mut pt, scratch_2) = scratch_1.take_scalar_znx(module.n(), 1);
153
154 for i in 0..T::WORD_SIZE {
155 use poulpy_core::layouts::prepared::Prepare;
156 use poulpy_hal::layouts::ZnxViewMut;
157
158 pt.at_mut(0, 0)[0] = value.bit(i) as i64;
159 tmp_ggsw.encrypt_sk(&module, &pt, sk, source_xa, source_xe, scratch_2);
160 self.blocks[i].prepare(module, &tmp_ggsw, scratch_2);
161 }
162 }
163
164 /// Prepares [FheUintBits] to [FheUintBitsPrep].
165 pub fn prepare<BIT, KEY>(&mut self, module: &Module<BE>, bits: &FheUintBlocks<BIT, T>, key: &KEY, scratch: &mut Scratch<BE>)
166 where
167 BIT: DataRef,
168 KEY: FheUintPrepare<BE, FheUintBlocksPrep<D, BE, T>, FheUintBlocks<BIT, T>>,
169 {
170 key.prepare(module, self, bits, scratch);
171 }
172}
173
174#[cfg(test)]
175impl<D: DataMut, T: UnsignedInteger + ToBits> FheUintBlocksPrepDebug<D, T> {
176 pub(crate) fn prepare<BIT, KEY, BE: Backend>(
177 &mut self,
178 module: &Module<BE>,
179 bits: &FheUintBlocks<BIT, T>,
180 key: &KEY,
181 scratch: &mut Scratch<BE>,
182 ) where
183 BIT: DataRef,
184 KEY: FheUintPrepare<BE, FheUintBlocksPrepDebug<D, T>, FheUintBlocks<BIT, T>>,
185 {
186 key.prepare(module, self, bits, scratch);
187 }
188}
189
190#[cfg(test)]
191impl<D: DataRef, T: UnsignedInteger + ToBits> FheUintBlocksPrepDebug<D, T> {
192 #[allow(dead_code)]
193 pub(crate) fn noise<S: DataRef, BE: Backend>(&self, module: &Module<BE>, sk: &GLWESecretPrepared<S, BE>, want: T)
194 where
195 Module<BE>: VecZnxDftAllocBytes
196 + VecZnxBigAllocBytes
197 + VecZnxDftApply<BE>
198 + SvpApplyDftToDftInplace<BE>
199 + VecZnxIdftApplyConsume<BE>
200 + VecZnxBigAddInplace<BE>
201 + VecZnxBigAddSmallInplace<BE>
202 + VecZnxBigNormalize<BE>
203 + VecZnxNormalizeTmpBytes
204 + VecZnxBigAlloc<BE>
205 + VecZnxDftAlloc<BE>
206 + VecZnxBigNormalizeTmpBytes
207 + VecZnxIdftApplyTmpA<BE>
208 + VecZnxAddScalarInplace
209 + VecZnxSubInplace,
210 BE: Backend + TakeVecZnxDftImpl<BE> + TakeVecZnxBigImpl<BE> + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE>,
211 {
212 for (i, ggsw) in self.blocks.iter().enumerate() {
213 use poulpy_hal::layouts::{ScalarZnx, ZnxViewMut};
214 let mut pt_want = ScalarZnx::alloc(self.n().into(), 1);
215 pt_want.at_mut(0, 0)[0] = want.bit(i) as i64;
216 ggsw.print_noise(module, sk, &pt_want);
217 }
218 }
219}
220
221impl<D: DataRef, T: UnsignedInteger, B: Backend> LWEInfos for FheUintBlocksPrep<D, B, T> {
222 fn base2k(&self) -> poulpy_core::layouts::Base2K {
223 self.blocks[0].base2k()
224 }
225
226 fn k(&self) -> poulpy_core::layouts::TorusPrecision {
227 self.blocks[0].k()
228 }
229
230 fn n(&self) -> poulpy_core::layouts::Degree {
231 self.blocks[0].n()
232 }
233}
234
235impl<D: DataRef, T: UnsignedInteger, B: Backend> GLWEInfos for FheUintBlocksPrep<D, B, T> {
236 fn rank(&self) -> poulpy_core::layouts::Rank {
237 self.blocks[0].rank()
238 }
239}
240
241impl<D: DataRef, T: UnsignedInteger, B: Backend> GGSWInfos for FheUintBlocksPrep<D, B, T> {
242 fn dsize(&self) -> poulpy_core::layouts::Dsize {
243 self.blocks[0].dsize()
244 }
245
246 fn dnum(&self) -> poulpy_core::layouts::Dnum {
247 self.blocks[0].dnum()
248 }
249}
250
251#[cfg(test)]
252impl<D: DataRef, T: UnsignedInteger> LWEInfos for FheUintBlocksPrepDebug<D, T> {
253 fn base2k(&self) -> poulpy_core::layouts::Base2K {
254 self.blocks[0].base2k()
255 }
256
257 fn k(&self) -> poulpy_core::layouts::TorusPrecision {
258 self.blocks[0].k()
259 }
260
261 fn n(&self) -> poulpy_core::layouts::Degree {
262 self.blocks[0].n()
263 }
264}
265
266#[cfg(test)]
267impl<D: DataRef, T: UnsignedInteger> GLWEInfos for FheUintBlocksPrepDebug<D, T> {
268 fn rank(&self) -> poulpy_core::layouts::Rank {
269 self.blocks[0].rank()
270 }
271}
272
273#[cfg(test)]
274impl<D: DataRef, T: UnsignedInteger> GGSWInfos for FheUintBlocksPrepDebug<D, T> {
275 fn dsize(&self) -> poulpy_core::layouts::Dsize {
276 self.blocks[0].dsize()
277 }
278
279 fn dnum(&self) -> poulpy_core::layouts::Dnum {
280 self.blocks[0].dnum()
281 }
282}