arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/src/layouts/glwe_ct.rs
poulpy-core/src/layouts/glwe_ct.rsRaw
  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
256impl<D: DataMut> ReaderFrom for GLWECiphertext<D> {
257    fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
258        self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
259        self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
260        self.data.read_from(reader)
261    }
262}
263
264impl<D: DataRef> WriterTo for GLWECiphertext<D> {
265    fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
266        writer.write_u32::<LittleEndian>(self.k.0)?;
267        writer.write_u32::<LittleEndian>(self.base2k.0)?;
268        self.data.write_to(writer)
269    }
270}
271
272pub trait GLWECiphertextToRef {
273    fn to_ref(&self) -> GLWECiphertext<&[u8]>;
274}
275
276impl<D: DataRef> GLWECiphertextToRef for GLWECiphertext<D> {
277    fn to_ref(&self) -> GLWECiphertext<&[u8]> {
278        GLWECiphertext {
279            k: self.k,
280            base2k: self.base2k,
281            data: self.data.to_ref(),
282        }
283    }
284}
285
286pub trait GLWECiphertextToMut {
287    fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]>;
288}
289
290impl<D: DataMut> GLWECiphertextToMut for GLWECiphertext<D> {
291    fn to_mut(&mut self) -> GLWECiphertext<&mut [u8]> {
292        GLWECiphertext {
293            k: self.k,
294            base2k: self.base2k,
295            data: self.data.to_mut(),
296        }
297    }
298}