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, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, Rank, 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) -> Degree {
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>
118where
119 Module<B>: TensorKeyPreparedAlloc<B>,
120{
121 pub fn alloc_from_infos<A>(module: &Module<B>, infos: &A) -> Self
122 where
123 A: GGLWEInfos,
124 {
125 module.alloc_tensor_key_prepared_from_infos(infos)
126 }
127
128 pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self {
129 module.alloc_tensor_key_prepared(base2k, k, dnum, dsize, rank)
130 }
131
132 pub fn bytes_of_from_infos<A>(module: &Module<B>, infos: &A) -> usize
133 where
134 A: GGLWEInfos,
135 {
136 module.bytes_of_tensor_key_prepared_from_infos(infos)
137 }
138
139 pub fn bytes_of(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
140 module.bytes_of_tensor_key_prepared(base2k, k, rank, dnum, dsize)
141 }
142}
143
144impl<D: DataMut, B: Backend> TensorKeyPrepared<D, B> {
145 // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
146 pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GLWESwitchingKeyPrepared<D, B> {
147 if i > j {
148 std::mem::swap(&mut i, &mut j);
149 };
150 let rank: usize = self.rank_out().into();
151 &mut self.keys[i * rank + j - (i * (i + 1) / 2)]
152 }
153}
154
155impl<D: DataRef, B: Backend> TensorKeyPrepared<D, B> {
156 // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
157 pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKeyPrepared<D, B> {
158 if i > j {
159 std::mem::swap(&mut i, &mut j);
160 };
161 let rank: usize = self.rank_out().into();
162 &self.keys[i * rank + j - (i * (i + 1) / 2)]
163 }
164}
165
166pub trait TensorKeyPrepare<B: Backend>
167where
168 Self: GLWESwitchingKeyPrepare<B>,
169{
170 fn prepare_tensor_key_tmp_bytes<A>(&self, infos: &A) -> usize
171 where
172 A: GGLWEInfos,
173 {
174 self.prepare_glwe_switching_key_tmp_bytes(infos)
175 }
176
177 fn prepare_tensor_key<R, O>(&self, res: &mut R, other: &O, scratch: &mut Scratch<B>)
178 where
179 R: TensorKeyPreparedToMut<B>,
180 O: TensorKeyToRef,
181 {
182 let mut res: TensorKeyPrepared<&mut [u8], B> = res.to_mut();
183 let other: TensorKey<&[u8]> = other.to_ref();
184
185 assert_eq!(res.keys.len(), other.keys.len());
186
187 for (a, b) in res.keys.iter_mut().zip(other.keys.iter()) {
188 self.prepare_glwe_switching(a, b, scratch);
189 }
190 }
191}
192
193impl<B: Backend> TensorKeyPrepare<B> for Module<B> where Module<B>: GLWESwitchingKeyPrepare<B> {}
194
195impl<B: Backend> TensorKeyPrepared<Vec<u8>, B>
196where
197 Module<B>: TensorKeyPrepare<B>,
198{
199 fn prepare_tmp_bytes<A>(&self, module: &Module<B>, infos: &A) -> usize
200 where
201 A: GGLWEInfos,
202 {
203 module.prepare_tensor_key_tmp_bytes(infos)
204 }
205}
206
207impl<D: DataMut, B: Backend> TensorKeyPrepared<D, B>
208where
209 Module<B>: TensorKeyPrepare<B>,
210{
211 fn prepare<O>(&mut self, module: &Module<B>, other: &O, scratch: &mut Scratch<B>)
212 where
213 O: TensorKeyToRef,
214 {
215 module.prepare_tensor_key(self, other, scratch);
216 }
217}
218
219pub trait TensorKeyPreparedToMut<B: Backend> {
220 fn to_mut(&mut self) -> TensorKeyPrepared<&mut [u8], B>;
221}
222
223impl<D: DataMut, B: Backend> TensorKeyPreparedToMut<B> for TensorKeyPrepared<D, B>
224where
225 GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToMut<B>,
226{
227 fn to_mut(&mut self) -> TensorKeyPrepared<&mut [u8], B> {
228 TensorKeyPrepared {
229 keys: self.keys.iter_mut().map(|c| c.to_mut()).collect(),
230 }
231 }
232}
233
234pub trait TensorKeyPreparedToRef<B: Backend> {
235 fn to_ref(&self) -> TensorKeyPrepared<&[u8], B>;
236}
237
238impl<D: DataRef, B: Backend> TensorKeyPreparedToRef<B> for TensorKeyPrepared<D, B>
239where
240 GLWESwitchingKeyPrepared<D, B>: GLWESwitchingKeyPreparedToRef<B>,
241{
242 fn to_ref(&self) -> TensorKeyPrepared<&[u8], B> {
243 TensorKeyPrepared {
244 keys: self.keys.iter().map(|c| c.to_ref()).collect(),
245 }
246 }
247}