poulpy/poulpy-core/src/layouts/prepared/gglwe_tsk.rs
poulpy-core/src/layouts/prepared/gglwe_tsk.rsRaw
1use poulpy_hal::{
2 api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
3 layouts::{Backend, Data, DataMut, DataRef, Module, Scratch},
4};
5
6use crate::layouts::{
7 Base2K, Degree, Digits, GGLWELayoutInfos, GGLWETensorKey, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision,
8 prepared::{GGLWESwitchingKeyPrepared, Prepare, PrepareAlloc},
9};
10
11#[derive(PartialEq, Eq)]
12pub struct GGLWETensorKeyPrepared<D: Data, B: Backend> {
13 pub(crate) keys: Vec<GGLWESwitchingKeyPrepared<D, B>>,
14}
15
16impl<D: Data, B: Backend> LWEInfos for GGLWETensorKeyPrepared<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 GGLWETensorKeyPrepared<D, B> {
35 fn rank(&self) -> Rank {
36 self.rank_out()
37 }
38}
39
40impl<D: Data, B: Backend> GGLWELayoutInfos for GGLWETensorKeyPrepared<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 digits(&self) -> Digits {
50 self.keys[0].digits()
51 }
52
53 fn rows(&self) -> Rows {
54 self.keys[0].rows()
55 }
56}
57
58impl<B: Backend> GGLWETensorKeyPrepared<Vec<u8>, B> {
59 pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
60 where
61 A: GGLWELayoutInfos,
62 Module<B>: VmpPMatAlloc<B>,
63 {
64 assert_eq!(
65 infos.rank_in(),
66 infos.rank_out(),
67 "rank_in != rank_out is not supported for GGLWETensorKeyPrepared"
68 );
69 Self::alloc_with(
70 module,
71 infos.base2k(),
72 infos.k(),
73 infos.rows(),
74 infos.digits(),
75 infos.rank_out(),
76 )
77 }
78
79 pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self
80 where
81 Module<B>: VmpPMatAlloc<B>,
82 {
83 let mut keys: Vec<GGLWESwitchingKeyPrepared<Vec<u8>, B>> = Vec::new();
84 let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1);
85 (0..pairs).for_each(|_| {
86 keys.push(GGLWESwitchingKeyPrepared::alloc_with(
87 module,
88 base2k,
89 k,
90 rows,
91 digits,
92 Rank(1),
93 rank,
94 ));
95 });
96 Self { keys }
97 }
98
99 pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
100 where
101 A: GGLWELayoutInfos,
102 Module<B>: VmpPMatAllocBytes,
103 {
104 assert_eq!(
105 infos.rank_in(),
106 infos.rank_out(),
107 "rank_in != rank_out is not supported for GGLWETensorKey"
108 );
109 let rank_out: usize = infos.rank_out().into();
110 let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1);
111 pairs
112 * GGLWESwitchingKeyPrepared::alloc_bytes_with(
113 module,
114 infos.base2k(),
115 infos.k(),
116 infos.rows(),
117 infos.digits(),
118 Rank(1),
119 infos.rank_out(),
120 )
121 }
122
123 pub fn alloc_bytes_with(
124 module: &Module<B>,
125 base2k: Base2K,
126 k: TorusPrecision,
127 rows: Rows,
128 digits: Digits,
129 rank: Rank,
130 ) -> usize
131 where
132 Module<B>: VmpPMatAllocBytes,
133 {
134 let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize;
135 pairs * GGLWESwitchingKeyPrepared::alloc_bytes_with(module, base2k, k, rows, digits, Rank(1), rank)
136 }
137}
138
139impl<D: DataMut, B: Backend> GGLWETensorKeyPrepared<D, B> {
140 // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
141 pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKeyPrepared<D, B> {
142 if i > j {
143 std::mem::swap(&mut i, &mut j);
144 };
145 let rank: usize = self.rank_out().into();
146 &mut self.keys[i * rank + j - (i * (i + 1) / 2)]
147 }
148}
149
150impl<D: DataRef, B: Backend> GGLWETensorKeyPrepared<D, B> {
151 // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
152 pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWESwitchingKeyPrepared<D, B> {
153 if i > j {
154 std::mem::swap(&mut i, &mut j);
155 };
156 let rank: usize = self.rank_out().into();
157 &self.keys[i * rank + j - (i * (i + 1) / 2)]
158 }
159}
160
161impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGLWETensorKey<DR>> for GGLWETensorKeyPrepared<D, B>
162where
163 Module<B>: VmpPrepare<B>,
164{
165 fn prepare(&mut self, module: &Module<B>, other: &GGLWETensorKey<DR>, scratch: &mut Scratch<B>) {
166 #[cfg(debug_assertions)]
167 {
168 assert_eq!(self.keys.len(), other.keys.len());
169 }
170 self.keys
171 .iter_mut()
172 .zip(other.keys.iter())
173 .for_each(|(a, b)| {
174 a.prepare(module, b, scratch);
175 });
176 }
177}
178
179impl<D: DataRef, B: Backend> PrepareAlloc<B, GGLWETensorKeyPrepared<Vec<u8>, B>> for GGLWETensorKey<D>
180where
181 Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>,
182{
183 fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGLWETensorKeyPrepared<Vec<u8>, B> {
184 let mut tsk_prepared: GGLWETensorKeyPrepared<Vec<u8>, B> = GGLWETensorKeyPrepared::alloc(module, self);
185 tsk_prepared.prepare(module, self, scratch);
186 tsk_prepared
187 }
188}