1use poulpy_hal::{
2 layouts::{
3 Data, DataMut, DataRef, FillUniform, ReaderFrom, ToOwnedDeep, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo, ZnxInfos,
4 },
5 source::Source,
6};
7
8use crate::layouts::{Base2K, BuildError, Degree, LWEInfos, Rank, TorusPrecision};
9use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
10use std::fmt;
11
12pub trait GLWEInfos
13where
14 Self: LWEInfos,
15{
16 fn rank(&self) -> Rank;
17 fn glwe_layout(&self) -> GLWECiphertextLayout {
18 GLWECiphertextLayout {
19 n: self.n(),
20 base2k: self.base2k(),
21 k: self.k(),
22 rank: self.rank(),
23 }
24 }
25}
26
27pub trait GLWELayoutSet {
28 fn set_k(&mut self, k: TorusPrecision);
29 fn set_basek(&mut self, base2k: Base2K);
30}
31
32#[derive(PartialEq, Eq, Copy, Clone, Debug)]
33pub struct GLWECiphertextLayout {
34 pub n: Degree,
35 pub base2k: Base2K,
36 pub k: TorusPrecision,
37 pub rank: Rank,
38}
39
40impl LWEInfos for GLWECiphertextLayout {
41 fn n(&self) -> Degree {
42 self.n
43 }
44
45 fn base2k(&self) -> Base2K {
46 self.base2k
47 }
48
49 fn k(&self) -> TorusPrecision {
50 self.k
51 }
52}
53
54impl GLWEInfos for GLWECiphertextLayout {
55 fn rank(&self) -> Rank {
56 self.rank
57 }
58}
59
60#[derive(PartialEq, Eq, Clone)]
61pub struct GLWECiphertext<D: Data> {
62 pub(crate) data: VecZnx<D>,
63 pub(crate) base2k: Base2K,
64 pub(crate) k: TorusPrecision,
65}
66
67impl<D: DataMut> GLWELayoutSet for GLWECiphertext<D> {
68 fn set_basek(&mut self, base2k: Base2K) {
69 self.base2k = base2k
70 }
71
72 fn set_k(&mut self, k: TorusPrecision) {
73 self.k = k
74 }
75}
76
77impl<D: DataRef> GLWECiphertext<D> {
78 pub fn data(&self) -> &VecZnx<D> {
79 &self.data
80 }
81}
82
83impl<D: DataMut> GLWECiphertext<D> {
84 pub fn data_mut(&mut self) -> &mut VecZnx<D> {
85 &mut self.data
86 }
87}
88
89pub struct GLWECiphertextBuilder<D: Data> {
90 data: Option<VecZnx<D>>,
91 base2k: Option<Base2K>,
92 k: Option<TorusPrecision>,
93}
94
95impl<D: Data> GLWECiphertext<D> {
96 #[inline]
97 pub fn builder() -> GLWECiphertextBuilder<D> {
98 GLWECiphertextBuilder {
99 data: None,
100 base2k: None,
101 k: None,
102 }
103 }
104}
105
106impl GLWECiphertextBuilder<Vec<u8>> {
107 #[inline]
108 pub fn layout<A>(mut self, layout: &A) -> Self
109 where
110 A: GLWEInfos,
111 {
112 self.data = Some(VecZnx::alloc(
113 layout.n().into(),
114 (layout.rank() + 1).into(),
115 layout.size(),
116 ));
117 self.base2k = Some(layout.base2k());
118 self.k = Some(layout.k());
119 self
120 }
121}
122
123impl<D: Data> GLWECiphertextBuilder<D> {
124 #[inline]
125 pub fn data(mut self, data: VecZnx<D>) -> Self {
126 self.data = Some(data);
127 self
128 }
129 #[inline]
130 pub fn base2k(mut self, base2k: Base2K) -> Self {
131 self.base2k = Some(base2k);
132 self
133 }
134 #[inline]
135 pub fn k(mut self, k: TorusPrecision) -> Self {
136 self.k = Some(k);
137 self
138 }
139
140 pub fn build(self) -> Result<GLWECiphertext<D>, BuildError> {
141 let data: VecZnx<D> = self.data.ok_or(BuildError::MissingData)?;
142 let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
143 let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
144
145 if base2k == 0_u32 {
146 return Err(BuildError::ZeroBase2K);
147 }
148
149 if k == 0_u32 {
150 return Err(BuildError::ZeroTorusPrecision);
151 }
152
153 if data.n() == 0 {
154 return Err(BuildError::ZeroDegree);
155 }
156
157 if data.cols() == 0 {
158 return Err(BuildError::ZeroCols);
159 }
160
161 if data.size() == 0 {
162 return Err(BuildError::ZeroLimbs);
163 }
164
165 Ok(GLWECiphertext { data, base2k, k })
166 }
167}
168
169impl<D: Data> LWEInfos for GLWECiphertext<D> {
170 fn base2k(&self) -> Base2K {
171 self.base2k
172 }
173
174 fn k(&self) -> TorusPrecision {
175 self.k
176 }
177
178 fn n(&self) -> Degree {
179 Degree(self.data.n() as u32)
180 }
181
182 fn size(&self) -> usize {
183 self.data.size()
184 }
185}
186
187impl<D: Data> GLWEInfos for GLWECiphertext<D> {
188 fn rank(&self) -> Rank {
189 Rank(self.data.cols() as u32 - 1)
190 }
191}
192
193impl<D: DataRef> ToOwnedDeep for GLWECiphertext<D> {
194 type Owned = GLWECiphertext<Vec<u8>>;
195 fn to_owned_deep(&self) -> Self::Owned {
196 GLWECiphertext {
197 data: self.data.to_owned_deep(),
198 k: self.k,
199 base2k: self.base2k,
200 }
201 }
202}
203
204impl<D: DataRef> fmt::Debug for GLWECiphertext<D> {
205 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206 write!(f, "{self}")
207 }
208}
209
210impl<D: DataRef> fmt::Display for GLWECiphertext<D> {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 write!(
213 f,
214 "GLWECiphertext: base2k={} k={}: {}",
215 self.base2k().0,
216 self.k().0,
217 self.data
218 )
219 }
220}
221
222impl<D: DataMut> FillUniform for GLWECiphertext<D> {
223 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
224 self.data.fill_uniform(log_bound, source);
225 }
226}
227
228impl GLWECiphertext<Vec<u8>> {
229 pub fn alloc<A>(infos: &A) -> Self
230 where
231 A: GLWEInfos,
232 {
233 Self::alloc_with(infos.n(), infos.base2k(), infos.k(), infos.rank())
234 }
235
236 pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self {
237 Self {
238 data: VecZnx::alloc(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize),
239 base2k,
240 k,
241 }
242 }
243
244 pub fn alloc_bytes<A>(infos: &A) -> usize
245 where
246 A: GLWEInfos,
247 {
248 Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k(), infos.rank())
249 }
250
251 pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize {
252 VecZnx::alloc_bytes(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize)
253 }
254}
255
256pub trait GLWECiphertextToRef {
257 fn to_ref(&self) -> GLWECiphertext<&[u8]>;
258}
259
260impl<D: DataRef> GLWECiphertextToRef for GLWECiphertext<D> {
261 fn to_ref(&self) -> GLWECiphertext<&[u8]> {
262 GLWECiphertext::builder()
263 .k(self.k())
264 .base2k(self.base2k())
265 .data(self.data.to_ref())
266 .build()
267 .unwrap()
268 }
269}
270
271pub trait GLWECiphertextToMut {
272 fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]>;
273}
274
275impl<D: DataMut> GLWECiphertextToMut for GLWECiphertext<D> {
276 fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]> {
277 GLWECiphertext::builder()
278 .k(self.k())
279 .base2k(self.base2k())
280 .data(self.data.to_mut())
281 .build()
282 .unwrap()
283 }
284}
285
286impl<D: DataMut> ReaderFrom for GLWECiphertext<D> {
287 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
288 self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
289 self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
290 self.data.read_from(reader)
291 }
292}
293
294impl<D: DataRef> WriterTo for GLWECiphertext<D> {
295 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
296 writer.write_u32::<LittleEndian>(self.k.0)?;
297 writer.write_u32::<LittleEndian>(self.base2k.0)?;
298 self.data.write_to(writer)
299 }
300}