poulpy/poulpy-core/src/layouts/gglwe_tsk.rs
poulpy-core/src/layouts/gglwe_tsk.rsRaw
1use poulpy_hal::{
2 layouts::{Data, DataMut, DataRef, FillUniform, ReaderFrom, WriterTo},
3 source::Source,
4};
5
6use crate::layouts::{Base2K, Degree, Dnum, Dsize, GGLWEInfos, GGLWESwitchingKey, GLWEInfos, LWEInfos, Rank, TorusPrecision};
7use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
8
9use std::fmt;
10
11#[derive(PartialEq, Eq, Copy, Clone, Debug)]
12pub struct GGLWETensorKeyLayout {
13 pub n: Degree,
14 pub base2k: Base2K,
15 pub k: TorusPrecision,
16 pub rank: Rank,
17 pub dnum: Dnum,
18 pub dsize: Dsize,
19}
20
21#[derive(PartialEq, Eq, Clone)]
22pub struct GGLWETensorKey<D: Data> {
23 pub(crate) keys: Vec<GGLWESwitchingKey<D>>,
24}
25
26impl<D: Data> LWEInfos for GGLWETensorKey<D> {
27 fn n(&self) -> Degree {
28 self.keys[0].n()
29 }
30
31 fn base2k(&self) -> Base2K {
32 self.keys[0].base2k()
33 }
34
35 fn k(&self) -> TorusPrecision {
36 self.keys[0].k()
37 }
38
39 fn size(&self) -> usize {
40 self.keys[0].size()
41 }
42}
43
44impl<D: Data> GLWEInfos for GGLWETensorKey<D> {
45 fn rank(&self) -> Rank {
46 self.keys[0].rank_out()
47 }
48}
49
50impl<D: Data> GGLWEInfos for GGLWETensorKey<D> {
51 fn rank_in(&self) -> Rank {
52 self.rank_out()
53 }
54
55 fn rank_out(&self) -> Rank {
56 self.keys[0].rank_out()
57 }
58
59 fn dsize(&self) -> Dsize {
60 self.keys[0].dsize()
61 }
62
63 fn dnum(&self) -> Dnum {
64 self.keys[0].dnum()
65 }
66}
67
68impl LWEInfos for GGLWETensorKeyLayout {
69 fn n(&self) -> Degree {
70 self.n
71 }
72
73 fn base2k(&self) -> Base2K {
74 self.base2k
75 }
76
77 fn k(&self) -> TorusPrecision {
78 self.k
79 }
80}
81
82impl GLWEInfos for GGLWETensorKeyLayout {
83 fn rank(&self) -> Rank {
84 self.rank_out()
85 }
86}
87
88impl GGLWEInfos for GGLWETensorKeyLayout {
89 fn rank_in(&self) -> Rank {
90 self.rank
91 }
92
93 fn dsize(&self) -> Dsize {
94 self.dsize
95 }
96
97 fn rank_out(&self) -> Rank {
98 self.rank
99 }
100
101 fn dnum(&self) -> Dnum {
102 self.dnum
103 }
104}
105
106impl<D: DataRef> fmt::Debug for GGLWETensorKey<D> {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 write!(f, "{self}")
109 }
110}
111
112impl<D: DataMut> FillUniform for GGLWETensorKey<D> {
113 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
114 self.keys
115 .iter_mut()
116 .for_each(|key: &mut GGLWESwitchingKey<D>| key.fill_uniform(log_bound, source))
117 }
118}
119
120impl<D: DataRef> fmt::Display for GGLWETensorKey<D> {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 writeln!(f, "(GLWETensorKey)",)?;
123 for (i, key) in self.keys.iter().enumerate() {
124 write!(f, "{i}: {key}")?;
125 }
126 Ok(())
127 }
128}
129
130impl GGLWETensorKey<Vec<u8>> {
131 pub fn alloc<A>(infos: &A) -> Self
132 where
133 A: GGLWEInfos,
134 {
135 assert_eq!(
136 infos.rank_in(),
137 infos.rank_out(),
138 "rank_in != rank_out is not supported for GGLWETensorKey"
139 );
140 Self::alloc_with(
141 infos.n(),
142 infos.base2k(),
143 infos.k(),
144 infos.rank_out(),
145 infos.dnum(),
146 infos.dsize(),
147 )
148 }
149
150 pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self {
151 let mut keys: Vec<GGLWESwitchingKey<Vec<u8>>> = Vec::new();
152 let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1);
153 (0..pairs).for_each(|_| {
154 keys.push(GGLWESwitchingKey::alloc_with(
155 n,
156 base2k,
157 k,
158 Rank(1),
159 rank,
160 dnum,
161 dsize,
162 ));
163 });
164 Self { keys }
165 }
166
167 pub fn alloc_bytes<A>(infos: &A) -> usize
168 where
169 A: GGLWEInfos,
170 {
171 assert_eq!(
172 infos.rank_in(),
173 infos.rank_out(),
174 "rank_in != rank_out is not supported for GGLWETensorKey"
175 );
176 let rank_out: usize = infos.rank_out().into();
177 let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1);
178 pairs
179 * GGLWESwitchingKey::alloc_bytes_with(
180 infos.n(),
181 infos.base2k(),
182 infos.k(),
183 Rank(1),
184 infos.rank_out(),
185 infos.dnum(),
186 infos.dsize(),
187 )
188 }
189
190 pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
191 let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize;
192 pairs * GGLWESwitchingKey::alloc_bytes_with(n, base2k, k, Rank(1), rank, dnum, dsize)
193 }
194}
195
196impl<D: DataMut> GGLWETensorKey<D> {
197 // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
198 pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GGLWESwitchingKey<D> {
199 if i > j {
200 std::mem::swap(&mut i, &mut j);
201 };
202 let rank: usize = self.rank_out().into();
203 &mut self.keys[i * rank + j - (i * (i + 1) / 2)]
204 }
205}
206
207impl<D: DataRef> GGLWETensorKey<D> {
208 // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
209 pub fn at(&self, mut i: usize, mut j: usize) -> &GGLWESwitchingKey<D> {
210 if i > j {
211 std::mem::swap(&mut i, &mut j);
212 };
213 let rank: usize = self.rank_out().into();
214 &self.keys[i * rank + j - (i * (i + 1) / 2)]
215 }
216}
217
218impl<D: DataMut> ReaderFrom for GGLWETensorKey<D> {
219 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
220 let len: usize = reader.read_u64::<LittleEndian>()? as usize;
221 if self.keys.len() != len {
222 return Err(std::io::Error::new(
223 std::io::ErrorKind::InvalidData,
224 format!("self.keys.len()={} != read len={}", self.keys.len(), len),
225 ));
226 }
227 for key in &mut self.keys {
228 key.read_from(reader)?;
229 }
230 Ok(())
231 }
232}
233
234impl<D: DataRef> WriterTo for GGLWETensorKey<D> {
235 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
236 writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
237 for key in &self.keys {
238 key.write_to(writer)?;
239 }
240 Ok(())
241 }
242}