poulpy_core/layouts/
glwe_pk.rs

1use poulpy_hal::layouts::{Data, DataMut, DataRef, ReaderFrom, VecZnx, WriterTo, ZnxInfos};
2
3use crate::{
4    dist::Distribution,
5    layouts::{Base2K, BuildError, Degree, GLWEInfos, LWEInfos, Rank, TorusPrecision},
6};
7use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
8
9#[derive(PartialEq, Eq)]
10pub struct GLWEPublicKey<D: Data> {
11    pub(crate) data: VecZnx<D>,
12    pub(crate) base2k: Base2K,
13    pub(crate) k: TorusPrecision,
14    pub(crate) dist: Distribution,
15}
16
17#[derive(PartialEq, Eq, Copy, Clone, Debug)]
18pub struct GLWEPublicKeyLayout {
19    pub n: Degree,
20    pub base2k: Base2K,
21    pub k: TorusPrecision,
22    pub rank: Rank,
23}
24
25impl<D: Data> LWEInfos for GLWEPublicKey<D> {
26    fn base2k(&self) -> Base2K {
27        self.base2k
28    }
29
30    fn k(&self) -> TorusPrecision {
31        self.k
32    }
33
34    fn n(&self) -> Degree {
35        Degree(self.data.n() as u32)
36    }
37
38    fn size(&self) -> usize {
39        self.data.size()
40    }
41}
42
43impl<D: Data> GLWEInfos for GLWEPublicKey<D> {
44    fn rank(&self) -> Rank {
45        Rank(self.data.cols() as u32 - 1)
46    }
47}
48
49impl LWEInfos for GLWEPublicKeyLayout {
50    fn base2k(&self) -> Base2K {
51        self.base2k
52    }
53
54    fn k(&self) -> TorusPrecision {
55        self.k
56    }
57
58    fn n(&self) -> Degree {
59        self.n
60    }
61
62    fn size(&self) -> usize {
63        self.k.0.div_ceil(self.base2k.0) as usize
64    }
65}
66
67impl GLWEInfos for GLWEPublicKeyLayout {
68    fn rank(&self) -> Rank {
69        self.rank
70    }
71}
72
73pub struct GLWEPublicKeyBuilder<D: Data> {
74    data: Option<VecZnx<D>>,
75    base2k: Option<Base2K>,
76    k: Option<TorusPrecision>,
77}
78
79impl<D: Data> GLWEPublicKey<D> {
80    #[inline]
81    pub fn builder() -> GLWEPublicKeyBuilder<D> {
82        GLWEPublicKeyBuilder {
83            data: None,
84            base2k: None,
85            k: None,
86        }
87    }
88}
89
90impl GLWEPublicKeyBuilder<Vec<u8>> {
91    #[inline]
92    pub fn layout<A>(mut self, layout: &A) -> Self
93    where
94        A: GLWEInfos,
95    {
96        self.data = Some(VecZnx::alloc(
97            layout.n().into(),
98            (layout.rank() + 1).into(),
99            layout.size(),
100        ));
101        self.base2k = Some(layout.base2k());
102        self.k = Some(layout.k());
103        self
104    }
105}
106
107impl<D: Data> GLWEPublicKeyBuilder<D> {
108    #[inline]
109    pub fn data(mut self, data: VecZnx<D>) -> Self {
110        self.data = Some(data);
111        self
112    }
113    #[inline]
114    pub fn base2k(mut self, base2k: Base2K) -> Self {
115        self.base2k = Some(base2k);
116        self
117    }
118    #[inline]
119    pub fn k(mut self, k: TorusPrecision) -> Self {
120        self.k = Some(k);
121        self
122    }
123
124    pub fn build(self) -> Result<GLWEPublicKey<D>, BuildError> {
125        let data: VecZnx<D> = self.data.ok_or(BuildError::MissingData)?;
126        let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
127        let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
128
129        if base2k == 0_u32 {
130            return Err(BuildError::ZeroBase2K);
131        }
132
133        if k == 0_u32 {
134            return Err(BuildError::ZeroTorusPrecision);
135        }
136
137        if data.n() == 0 {
138            return Err(BuildError::ZeroDegree);
139        }
140
141        if data.cols() == 0 {
142            return Err(BuildError::ZeroCols);
143        }
144
145        if data.size() == 0 {
146            return Err(BuildError::ZeroLimbs);
147        }
148
149        Ok(GLWEPublicKey {
150            data,
151            base2k,
152            k,
153            dist: Distribution::NONE,
154        })
155    }
156}
157
158impl GLWEPublicKey<Vec<u8>> {
159    pub fn alloc<A>(infos: &A) -> Self
160    where
161        A: GLWEInfos,
162    {
163        Self::alloc_with(infos.n(), infos.base2k(), infos.k(), infos.rank())
164    }
165
166    pub fn alloc_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self {
167        Self {
168            data: VecZnx::alloc(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize),
169            base2k,
170            k,
171            dist: Distribution::NONE,
172        }
173    }
174
175    pub fn alloc_bytes<A>(infos: &A) -> usize
176    where
177        A: GLWEInfos,
178    {
179        Self::alloc_bytes_with(infos.n(), infos.base2k(), infos.k(), infos.rank())
180    }
181
182    pub fn alloc_bytes_with(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize {
183        VecZnx::alloc_bytes(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize)
184    }
185}
186
187impl<D: DataMut> ReaderFrom for GLWEPublicKey<D> {
188    fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
189        self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
190        self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
191        match Distribution::read_from(reader) {
192            Ok(dist) => self.dist = dist,
193            Err(e) => return Err(e),
194        }
195        self.data.read_from(reader)
196    }
197}
198
199impl<D: DataRef> WriterTo for GLWEPublicKey<D> {
200    fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
201        writer.write_u32::<LittleEndian>(self.k.0)?;
202        writer.write_u32::<LittleEndian>(self.base2k.0)?;
203        match self.dist.write_to(writer) {
204            Ok(()) => {}
205            Err(e) => return Err(e),
206        }
207        self.data.write_to(writer)
208    }
209}