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