poulpy/poulpy-core/src/layouts/prepared/gglwe_tsk.rs
poulpy-core/src/layouts/prepared/gglwe_tsk.rsRaw
1use poulpy_hal::{
2 api::{VmpPMatAlloc, VmpPMatAllocBytes},
3 layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
4};
5
6use crate::layouts::{
7 Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TensorKey, TensorKeyToRef, TorusPrecision,
8 compressed::TensorKeyCompressedToMut,
9 prepared::{
10 GLWESwitchingKeyPrepare, GLWESwitchingKeyPrepareTmpBytes, GLWESwitchingKeyPrepared, GLWESwitchingKeyPreparedToMut,
11 GLWESwitchingKeyPreparedToRef,
12 },
13};
14
15#[derive(PartialEq, Eq)]
16pub struct TensorKeyPrepared<D: Data, B: Backend> {
17 pub(crate) keys: Vec<GLWESwitchingKeyPrepared<D, B>>,
18}
19
20impl<D: Data, B: Backend> LWEInfos for TensorKeyPrepared<D, B> {
21 fn n(&self) -> Degree {
22 self.keys[0].n()
23 }
24
25 fn base2k(&self) -> Base2K {
26 self.keys[0].base2k()
27 }
28
29 fn k(&self) -> TorusPrecision {
30 self.keys[0].k()
31 }
32
33 fn size(&self) -> usize {
34 self.keys[0].size()
35 }
36}
37
38impl<D: Data, B: Backend> GLWEInfos for TensorKeyPrepared<D, B> {
39 fn rank(&self) -> Rank {
40 self.rank_out()
41 }
42}
43
44impl<D: Data, B: Backend> GGLWEInfos for TensorKeyPrepared<D, B> {
45 fn rank_in(&self) -> Rank {
46 self.rank_out()
47 }
48
49 fn rank_out(&self) -> Rank {
50 self.keys[0].rank_out()
51 }
52
53 fn dsize(&self) -> Dsize {
54 self.keys[0].dsize()
55 }
56
57 fn dnum(&self) -> Dnum {
58 self.keys[0].dnum()
59 }
60}
61
62impl<B: Backend> TensorKeyPrepared<Vec<u8>, B> {
63 pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
64 where
65 A: GGLWEInfos,
66 Module<B>: VmpPMatAlloc<B>,
67 {
68 assert_eq!(
69 infos.rank_in(),
70 infos.rank_out(),
71 "rank_in != rank_out is not supported for GGLWETensorKeyPrepared"
72 );
73 Self::alloc_with(
74 module,
75 infos.base2k(),
76 infos.k(),
77 infos.dnum(),
78 infos.dsize(),
79 infos.rank_out(),
80 )
81 }
82
83 pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self
84 where
85 Module<B>: VmpPMatAlloc<B>,
86 {
87 let mut keys: Vec<GLWESwitchingKeyPrepared<Vec<u8>, B>> = Vec::new();
88 let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1);
89 (0..pairs).for_each(|_| {
90 keys.push(GLWESwitchingKeyPrepared::alloc(
91 module,
92 base2k,
93 k,
94 Rank(1),
95 rank,
96 dnum,
97 dsize,
98 ));
99 });
100 Self { keys }
101 }
102
103 pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
104 where
105 A: GGLWEInfos,
106 Module<B>: VmpPMatAllocBytes,
107 {
108 assert_eq!(
109 infos.rank_in(),
110 infos.rank_out(),
111 "rank_in != rank_out is not supported for GGLWETensorKey"
112 );
113 let rank_out: usize = infos.rank_out().into();
114 let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1);
115 pairs
116 * GLWESwitchingKeyPrepared::alloc_bytes(
117 module,
118 infos.base2k(),
119 infos.k(),
120 Rank(1),
121 infos.rank_out(),
122 infos.dnum(),
123 infos.dsize(),
124 )
125 }
126
127 pub fn alloc_bytes_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
128 where
129 Module<B>: VmpPMatAllocBytes,
130 {
131 let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize;
132 pairs * GLWESwitchingKeyPrepared::alloc_bytes(module, base2k, k, Rank(1), rank, dnum, dsize)
133 }
134}
135
136impl<D: DataMut, B: Backend> TensorKeyPrepared<D, B> {
137 // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
138 pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GLWESwitchingKeyPrepared<D, B> {
139 if i > j {
140 std::mem::swap(&mut i, &mut j);
141 };
142 let rank: usize = self.rank_out().into();
143 &mut self.keys[i * rank + j - (i * (i + 1) / 2)]
144 }
145}
146
147impl<D: DataRef, B: Backend> TensorKeyPrepared<D, B> {
148 // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
149 pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKeyPrepared<D, B> {
150 if i > j {
151 std::mem::swap(&mut i, &mut j);
152 };
153 let rank: usize = self.rank_out().into();
154 &self.keys[i * rank + j - (i * (i + 1) / 2)]
155 }
156}
157
158pub trait TensorKeyPrepareTmpBytes {
159 fn tensor_key_prepare_tmp_bytes<A>(&self, infos: &A) -> usize;
160}
161
162impl<B: Backend> TensorKeyPrepareTmpBytes for Module<B>
163where
164 Module<B>: GLWESwitchingKeyPrepareTmpBytes,
165{
166 fn tensor_key_prepare_tmp_bytes<A>(&self, infos: &A) -> usize {
167 self.glwe_switching_key_prepare_tmp_bytes(infos)
168 }
169}
170
171impl<B: Backend> TensorKeyPrepared<Vec<u8>, B>
172where
173 Module<B>: TensorKeyPrepareTmpBytes,
174{
175 fn prepare_tmp_bytes<A>(&self, module: &Module<B>, infos: &A) -> usize
176 where
177 A: GGLWEInfos,
178 {
179 module.tensor_key_prepare_tmp_bytes(infos)
180 }
181}
182
183pub trait TensorKeyPrepare<B: Backend> {
184 fn tensor_key_prepare<R, O>(&self, res: &mut R, other: &O, scratch: &Scratch<B>)
185 where
186 R: TensorKeyPreparedToMut<B>,
187 O: TensorKeyToRef;
188}
189
190impl<B: Backend> TensorKeyPrepare<B> for Module<B>
191where
192 Module<B>: GLWESwitchingKeyPrepare<B>,
193{
194 fn tensor_key_prepare<R, O>(&self, res: &mut R, other: &O, scratch: &Scratch<B>)
195 where
196 R: TensorKeyPreparedToMut<B>,
197 O: TensorKeyToRef,
198 {
199 let res = res.to_mut();
200 let other = other.to_ref();
201
202 assert_eq!(self.keys.len(), other.keys.len());
203
204 for (a, b) in res.keys.iter_mut().zip(other.keys.iter()) {
205 self.glwe_switching_prepare(a, b, scratch);
206 }
207 }
208}
209
210impl<D: DataMut, B: Backend> TensorKeyPrepared<D, B>
211where
212 Module<B>: TensorKeyPrepare<B>,
213{
214 fn prepare<O>(&mut self, module: &Module<B>, other: &O, scratch: &mut Scratch<B>)
215 where
216 O: TensorKeyToRef,
217 {
218 module.tensor_key_prepare(self, other, scratch);
219 }
220}
221
222pub trait TensorKeyPrepareAlloc<B: Backend> {
223 fn tensor_key_prepare_alloc<O>(&self, other: &O, scratch: &mut Scratch<B>)
224 where
225 O: TensorKeyToRef;
226}
227
228impl<B: Backend> TensorKeyPrepareAlloc<B> for Module<B>
229where
230 Module<B>: TensorKeyPrepare<B>,
231{
232 fn tensor_key_prepare_alloc<O>(&self, other: &O, scratch: &mut Scratch<B>)
233 where
234 O: TensorKeyToRef,
235 {
236 let mut ct_prepared: TensorKeyPrepared<Vec<u8>, B> = TensorKeyPrepared::alloc(self, other);
237 self.tensor_key_prepare(ct_prepared, other, scratch);
238 ct_prepared
239 }
240}
241
242impl<D: DataRef> TensorKey<D> {
243 pub fn prepare_alloc<B: Backend>(&self, module: &Module<B>, scratch: &Scratch<B>)
244 where
245 Module<B>: TensorKeyPrepareAlloc<B>,
246 {
247 module.tensor_key_prepare_alloc(self, scratch);
248 }
249}
250
251pub trait TensorKeyPreparedToMut<B: Backend> {
252 fn to_mut(&mut self) -> TensorKeyPrepared<&mut [u8], B>;
253}
254
255impl<D: DataMut, B: Backend> TensorKeyPreparedToMut<B> for TensorKeyPrepared<D, B>
256where
257 GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToMut<B>,
258{
259 fn to_mut(&mut self) -> TensorKeyPrepared<&mut [u8], B> {
260 TensorKeyPrepared {
261 keys: self.keys.iter_mut().map(|c| c.to_mut()).collect(),
262 }
263 }
264}
265
266pub trait TensorKeyPreparedToRef<B: Backend> {
267 fn to_ref(&self) -> TensorKeyPrepared<&[u8], B>;
268}
269
270impl<D: DataRef, B: Backend> TensorKeyPreparedToRef<B> for TensorKeyPrepared<D, B>
271where
272 GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToRef<B>,
273{
274 fn to_ref(&self) -> TensorKeyPrepared<&[u8], B> {
275 TensorKeyPrepared {
276 keys: self.keys.iter().map(|c| c.to_ref()).collect(),
277 }
278 }
279}