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, GGSWPreparedFactory, GLWEInfos, LWEInfos, Rank, TorusPrecision, prepared::GGSWPrepared,
5};
6#[cfg(test)]
7use poulpy_core::{GGSWEncryptSk, ScratchTakeCore, layouts::GLWESecretPreparedToRef};
8use poulpy_hal::layouts::{Backend, Data, DataRef, Module};
9#[cfg(test)]
10use poulpy_hal::{
11 api::ModuleN,
12 layouts::{DataMut, Scratch},
13 source::Source,
14};
15
16#[cfg(test)]
17use crate::tfhe::bdd_arithmetic::ToBits;
18use crate::tfhe::bdd_arithmetic::UnsignedInteger;
19
20/// A prepared FHE ciphertext encrypting the bits of an [UnsignedInteger].
21pub struct FheUintBlocksPrepared<D: Data, T: UnsignedInteger, B: Backend> {
22 pub(crate) blocks: Vec<GGSWPrepared<D, B>>,
23 pub(crate) _base: u8,
24 pub(crate) _phantom: PhantomData<T>,
25}
26
27impl<T: UnsignedInteger, BE: Backend> FheUintBlocksPreparedFactory<T, BE> for Module<BE> where
28 Self: Sized + GGSWPreparedFactory<BE>
29{
30}
31
32pub trait FheUintBlocksPreparedFactory<T: UnsignedInteger, BE: Backend>
33where
34 Self: Sized + GGSWPreparedFactory<BE>,
35{
36 fn alloc_fhe_uint_blocks_prepared(
37 &self,
38 base2k: Base2K,
39 k: TorusPrecision,
40 dnum: Dnum,
41 dsize: Dsize,
42 rank: Rank,
43 ) -> FheUintBlocksPrepared<Vec<u8>, T, BE> {
44 FheUintBlocksPrepared {
45 blocks: (0..T::WORD_SIZE)
46 .map(|_| GGSWPrepared::alloc(self, base2k, k, dnum, dsize, rank))
47 .collect(),
48 _base: 1,
49 _phantom: PhantomData,
50 }
51 }
52
53 fn alloc_fhe_uint_blocks_prepared_from_infos<A>(&self, infos: &A) -> FheUintBlocksPrepared<Vec<u8>, T, BE>
54 where
55 A: GGSWInfos,
56 {
57 self.alloc_fhe_uint_blocks_prepared(
58 infos.base2k(),
59 infos.k(),
60 infos.dnum(),
61 infos.dsize(),
62 infos.rank(),
63 )
64 }
65}
66
67impl<T: UnsignedInteger, BE: Backend> FheUintBlocksPrepared<Vec<u8>, T, BE> {
68 #[allow(dead_code)]
69 pub(crate) fn alloc<A, M>(module: &M, infos: &A) -> Self
70 where
71 A: GGSWInfos,
72 M: FheUintBlocksPreparedFactory<T, BE>,
73 {
74 module.alloc_fhe_uint_blocks_prepared_from_infos(infos)
75 }
76
77 #[allow(dead_code)]
78 pub(crate) fn alloc_with<M>(module: &M, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self
79 where
80 M: FheUintBlocksPreparedFactory<T, BE>,
81 {
82 module.alloc_fhe_uint_blocks_prepared(base2k, k, dnum, dsize, rank)
83 }
84}
85
86#[cfg(test)]
87impl<T: UnsignedInteger + ToBits, BE: Backend> FheUintBlocksPreparedEncryptSk<T, BE> for Module<BE> where
88 Self: Sized + ModuleN + GGSWEncryptSk<BE> + GGSWPreparedFactory<BE>
89{
90}
91
92#[cfg(test)]
93pub trait FheUintBlocksPreparedEncryptSk<T: UnsignedInteger + ToBits, BE: Backend>
94where
95 Self: Sized + ModuleN + GGSWEncryptSk<BE> + GGSWPreparedFactory<BE>,
96{
97 fn fhe_uint_blocks_prepared_encrypt_sk<DM, S>(
98 &self,
99 res: &mut FheUintBlocksPrepared<DM, T, BE>,
100 value: T,
101 sk: &S,
102 source_xa: &mut Source,
103 source_xe: &mut Source,
104 scratch: &mut Scratch<BE>,
105 ) where
106 DM: DataMut,
107 S: GLWESecretPreparedToRef<BE> + GLWEInfos,
108 Scratch<BE>: ScratchTakeCore<BE>,
109 {
110 use poulpy_hal::{api::ScratchTakeBasic, layouts::ZnxZero};
111
112 assert!(self.n().is_multiple_of(T::WORD_SIZE));
113 assert_eq!(res.n(), self.n() as u32);
114 assert_eq!(sk.n(), self.n() as u32);
115
116 let (mut tmp_ggsw, scratch_1) = scratch.take_ggsw(res);
117 let (mut pt, scratch_2) = scratch_1.take_scalar_znx(self.n(), 1);
118 pt.zero();
119
120 for i in 0..T::WORD_SIZE {
121 use poulpy_hal::layouts::ZnxViewMut;
122 pt.at_mut(0, 0)[0] = value.bit(i) as i64;
123 tmp_ggsw.encrypt_sk(self, &pt, sk, source_xa, source_xe, scratch_2);
124 res.blocks[i].prepare(self, &tmp_ggsw, scratch_2);
125 }
126 }
127}
128
129#[cfg(test)]
130impl<D: DataMut, T: UnsignedInteger + ToBits, BE: Backend> FheUintBlocksPrepared<D, T, BE> {
131 pub(crate) fn encrypt_sk<M, S>(
132 &mut self,
133 module: &M,
134 value: T,
135 sk: &S,
136 source_xa: &mut Source,
137 source_xe: &mut Source,
138 scratch: &mut Scratch<BE>,
139 ) where
140 S: GLWESecretPreparedToRef<BE> + GLWEInfos,
141 M: FheUintBlocksPreparedEncryptSk<T, BE>,
142 Scratch<BE>: ScratchTakeCore<BE>,
143 {
144 module.fhe_uint_blocks_prepared_encrypt_sk(self, value, sk, source_xa, source_xe, scratch);
145 }
146}
147
148impl<D: DataRef, T: UnsignedInteger, B: Backend> LWEInfos for FheUintBlocksPrepared<D, T, B> {
149 fn base2k(&self) -> poulpy_core::layouts::Base2K {
150 self.blocks[0].base2k()
151 }
152
153 fn k(&self) -> poulpy_core::layouts::TorusPrecision {
154 self.blocks[0].k()
155 }
156
157 fn n(&self) -> poulpy_core::layouts::Degree {
158 self.blocks[0].n()
159 }
160}
161
162impl<D: DataRef, T: UnsignedInteger, B: Backend> GLWEInfos for FheUintBlocksPrepared<D, T, B> {
163 fn rank(&self) -> poulpy_core::layouts::Rank {
164 self.blocks[0].rank()
165 }
166}
167
168impl<D: DataRef, T: UnsignedInteger, B: Backend> GGSWInfos for FheUintBlocksPrepared<D, T, B> {
169 fn dsize(&self) -> poulpy_core::layouts::Dsize {
170 self.blocks[0].dsize()
171 }
172
173 fn dnum(&self) -> poulpy_core::layouts::Dnum {
174 self.blocks[0].dnum()
175 }
176}