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