arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/src/layouts/compressed/glwe_ct.rs
poulpy-core/src/layouts/compressed/glwe_ct.rsRaw
  1use poulpy_hal::{
  2    api::{VecZnxCopy, VecZnxFillUniform},
  3    layouts::{
  4        Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, VecZnx, VecZnxToMut, VecZnxToRef, WriterTo, ZnxInfos,
  5    },
  6    source::Source,
  7};
  8
  9use crate::layouts::{
 10    Base2K, GLWE, GLWEInfos, GLWEToMut, GetRingDegree, LWEInfos, Rank, RingDegree, SetGLWEInfos, TorusPrecision,
 11};
 12use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
 13use std::fmt;
 14
 15#[derive(PartialEq, Eq, Clone)]
 16pub struct GLWECompressed<D: Data> {
 17    pub(crate) data: VecZnx<D>,
 18    pub(crate) base2k: Base2K,
 19    pub(crate) k: TorusPrecision,
 20    pub(crate) rank: Rank,
 21    pub(crate) seed: [u8; 32],
 22}
 23
 24impl<D: Data> LWEInfos for GLWECompressed<D> {
 25    fn base2k(&self) -> Base2K {
 26        self.base2k
 27    }
 28
 29    fn k(&self) -> TorusPrecision {
 30        self.k
 31    }
 32
 33    fn size(&self) -> usize {
 34        self.data.size()
 35    }
 36
 37    fn n(&self) -> RingDegree {
 38        RingDegree(self.data.n() as u32)
 39    }
 40}
 41impl<D: Data> GLWEInfos for GLWECompressed<D> {
 42    fn rank(&self) -> Rank {
 43        self.rank
 44    }
 45}
 46
 47impl<D: DataRef> fmt::Debug for GLWECompressed<D> {
 48    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 49        write!(f, "{self}")
 50    }
 51}
 52
 53impl<D: DataRef> fmt::Display for GLWECompressed<D> {
 54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 55        write!(
 56            f,
 57            "GLWECompressed: base2k={} k={} rank={} seed={:?}: {}",
 58            self.base2k(),
 59            self.k(),
 60            self.rank(),
 61            self.seed,
 62            self.data
 63        )
 64    }
 65}
 66
 67impl<D: DataMut> FillUniform for GLWECompressed<D> {
 68    fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
 69        self.data.fill_uniform(log_bound, source);
 70    }
 71}
 72
 73pub trait GLWECompressedAlloc
 74where
 75    Self: GetRingDegree,
 76{
 77    fn alloc_glwe_compressed(&self, base2k: Base2K, k: TorusPrecision, rank: Rank) -> GLWECompressed<Vec<u8>> {
 78        GLWECompressed {
 79            data: VecZnx::alloc(
 80                self.ring_degree().into(),
 81                1,
 82                k.0.div_ceil(base2k.0) as usize,
 83            ),
 84            base2k,
 85            k,
 86            rank,
 87            seed: [0u8; 32],
 88        }
 89    }
 90
 91    fn alloc_glwe_compressed_from_infos<A>(&self, infos: &A) -> GLWECompressed<Vec<u8>>
 92    where
 93        A: GLWEInfos,
 94    {
 95        assert_eq!(self.ring_degree(), infos.n());
 96        self.alloc_glwe_compressed(infos.base2k(), infos.k(), infos.rank())
 97    }
 98
 99    fn bytes_of_glwe_compressed(&self, base2k: Base2K, k: TorusPrecision) -> usize {
100        VecZnx::bytes_of(
101            self.ring_degree().into(),
102            1,
103            k.0.div_ceil(base2k.0) as usize,
104        )
105    }
106
107    fn bytes_of_glwe_compressed_from_infos<A>(&self, infos: &A) -> usize
108    where
109        A: GLWEInfos,
110    {
111        assert_eq!(self.ring_degree(), infos.n());
112        self.bytes_of_glwe_compressed(infos.base2k(), infos.k())
113    }
114}
115
116impl<B: Backend> GLWECompressedAlloc for Module<B> where Self: GetRingDegree {}
117
118impl GLWECompressed<Vec<u8>> {
119    pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
120    where
121        A: GLWEInfos,
122        M: GLWECompressedAlloc,
123    {
124        module.alloc_glwe_compressed_from_infos(infos)
125    }
126
127    pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self
128    where
129        M: GLWECompressedAlloc,
130    {
131        module.alloc_glwe_compressed(base2k, k, rank)
132    }
133
134    pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
135    where
136        A: GLWEInfos,
137        M: GLWECompressedAlloc,
138    {
139        module.bytes_of_glwe_compressed_from_infos(infos)
140    }
141
142    pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision) -> usize
143    where
144        M: GLWECompressedAlloc,
145    {
146        module.bytes_of_glwe_compressed(base2k, k)
147    }
148}
149
150impl<D: DataMut> ReaderFrom for GLWECompressed<D> {
151    fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
152        self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
153        self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
154        self.rank = Rank(reader.read_u32::<LittleEndian>()?);
155        reader.read_exact(&mut self.seed)?;
156        self.data.read_from(reader)
157    }
158}
159
160impl<D: DataRef> WriterTo for GLWECompressed<D> {
161    fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
162        writer.write_u32::<LittleEndian>(self.k.into())?;
163        writer.write_u32::<LittleEndian>(self.base2k.into())?;
164        writer.write_u32::<LittleEndian>(self.rank.into())?;
165        writer.write_all(&self.seed)?;
166        self.data.write_to(writer)
167    }
168}
169
170pub trait GLWEDecompress
171where
172    Self: GetRingDegree + VecZnxFillUniform + VecZnxCopy,
173{
174    fn decompress_glwe<R, O>(&self, res: &mut R, other: &O)
175    where
176        R: GLWEToMut + SetGLWEInfos,
177        O: GLWECompressedToRef + GLWEInfos,
178    {
179        {
180            let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
181            let other: &GLWECompressed<&[u8]> = &other.to_ref();
182            assert_eq!(
183                res.n(),
184                self.ring_degree(),
185                "invalid receiver: res.n()={} != other.n()={}",
186                res.n(),
187                self.ring_degree()
188            );
189
190            assert_eq!(res.lwe_layout(), other.lwe_layout());
191            assert_eq!(res.glwe_layout(), other.glwe_layout());
192
193            let mut source: Source = Source::new(other.seed);
194
195            self.vec_znx_copy(&mut res.data, 0, &other.data, 0);
196            (1..(other.rank() + 1).into()).for_each(|i| {
197                self.vec_znx_fill_uniform(other.base2k.into(), &mut res.data, i, &mut source);
198            });
199        }
200
201        res.set_base2k(other.base2k());
202        res.set_k(other.k());
203    }
204}
205
206impl<B: Backend> GLWEDecompress for Module<B> where Self: GetRingDegree + VecZnxFillUniform + VecZnxCopy {}
207
208impl<D: DataMut> GLWE<D> {
209    pub fn decompress<O, M>(&mut self, module: &M, other: &O)
210    where
211        O: GLWECompressedToRef + GLWEInfos,
212        M: GLWEDecompress,
213    {
214        module.decompress_glwe(self, other);
215    }
216}
217
218pub trait GLWECompressedToRef {
219    fn to_ref(&self) -> GLWECompressed<&[u8]>;
220}
221
222impl<D: DataRef> GLWECompressedToRef for GLWECompressed<D> {
223    fn to_ref(&self) -> GLWECompressed<&[u8]> {
224        GLWECompressed {
225            seed: self.seed.clone(),
226            base2k: self.base2k,
227            k: self.k,
228            rank: self.rank,
229            data: self.data.to_ref(),
230        }
231    }
232}
233
234pub trait GLWECompressedToMut {
235    fn to_mut(&mut self) -> GLWECompressed<&mut [u8]>;
236}
237
238impl<D: DataMut> GLWECompressedToMut for GLWECompressed<D> {
239    fn to_mut(&mut self) -> GLWECompressed<&mut [u8]> {
240        GLWECompressed {
241            seed: self.seed.clone(),
242            base2k: self.base2k,
243            k: self.k,
244            rank: self.rank,
245            data: self.data.to_mut(),
246        }
247    }
248}