poulpy_core/layouts/compressed/
glwe_ct.rs

1use poulpy_hal::{
2    api::{VecZnxCopy, VecZnxFillUniform},
3    layouts::{Backend, Data, DataMut, DataRef, FillUniform, Module, ReaderFrom, Reset, VecZnx, WriterTo},
4    source::Source,
5};
6
7use crate::layouts::{GLWECiphertext, Infos, compressed::Decompress};
8use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
9use std::fmt;
10
11#[derive(PartialEq, Eq, Clone)]
12pub struct GLWECiphertextCompressed<D: Data> {
13    pub(crate) data: VecZnx<D>,
14    pub(crate) basek: usize,
15    pub(crate) k: usize,
16    pub(crate) rank: usize,
17    pub(crate) seed: [u8; 32],
18}
19
20impl<D: DataRef> fmt::Debug for GLWECiphertextCompressed<D> {
21    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22        write!(f, "{}", self)
23    }
24}
25
26impl<D: DataRef> fmt::Display for GLWECiphertextCompressed<D> {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        write!(
29            f,
30            "GLWECiphertextCompressed: basek={} k={} rank={} seed={:?}: {}",
31            self.basek(),
32            self.k(),
33            self.rank,
34            self.seed,
35            self.data
36        )
37    }
38}
39
40impl<D: DataMut> Reset for GLWECiphertextCompressed<D> {
41    fn reset(&mut self) {
42        self.data.reset();
43        self.basek = 0;
44        self.k = 0;
45        self.rank = 0;
46        self.seed = [0u8; 32];
47    }
48}
49
50impl<D: DataMut> FillUniform for GLWECiphertextCompressed<D> {
51    fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
52        self.data.fill_uniform(log_bound, source);
53    }
54}
55
56impl<D: Data> Infos for GLWECiphertextCompressed<D> {
57    type Inner = VecZnx<D>;
58
59    fn inner(&self) -> &Self::Inner {
60        &self.data
61    }
62
63    fn basek(&self) -> usize {
64        self.basek
65    }
66
67    fn k(&self) -> usize {
68        self.k
69    }
70}
71
72impl<D: Data> GLWECiphertextCompressed<D> {
73    pub fn rank(&self) -> usize {
74        self.rank
75    }
76}
77
78impl GLWECiphertextCompressed<Vec<u8>> {
79    pub fn alloc(n: usize, basek: usize, k: usize, rank: usize) -> Self {
80        Self {
81            data: VecZnx::alloc(n, 1, k.div_ceil(basek)),
82            basek,
83            k,
84            rank,
85            seed: [0u8; 32],
86        }
87    }
88
89    pub fn bytes_of(n: usize, basek: usize, k: usize) -> usize {
90        GLWECiphertext::bytes_of(n, basek, k, 1)
91    }
92}
93
94impl<D: DataMut> ReaderFrom for GLWECiphertextCompressed<D> {
95    fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
96        self.k = reader.read_u64::<LittleEndian>()? as usize;
97        self.basek = reader.read_u64::<LittleEndian>()? as usize;
98        self.rank = reader.read_u64::<LittleEndian>()? as usize;
99        reader.read_exact(&mut self.seed)?;
100        self.data.read_from(reader)
101    }
102}
103
104impl<D: DataRef> WriterTo for GLWECiphertextCompressed<D> {
105    fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
106        writer.write_u64::<LittleEndian>(self.k as u64)?;
107        writer.write_u64::<LittleEndian>(self.basek as u64)?;
108        writer.write_u64::<LittleEndian>(self.rank as u64)?;
109        writer.write_all(&self.seed)?;
110        self.data.write_to(writer)
111    }
112}
113
114impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GLWECiphertextCompressed<DR>> for GLWECiphertext<D>
115where
116    Module<B>: VecZnxFillUniform + VecZnxCopy,
117{
118    fn decompress(&mut self, module: &Module<B>, other: &GLWECiphertextCompressed<DR>) {
119        #[cfg(debug_assertions)]
120        {
121            use poulpy_hal::layouts::ZnxInfos;
122
123            assert_eq!(
124                self.n(),
125                other.data.n(),
126                "invalid receiver: self.n()={} != other.n()={}",
127                self.n(),
128                other.data.n()
129            );
130            assert_eq!(
131                self.size(),
132                other.size(),
133                "invalid receiver: self.size()={} != other.size()={}",
134                self.size(),
135                other.size()
136            );
137            assert_eq!(
138                self.rank(),
139                other.rank(),
140                "invalid receiver: self.rank()={} != other.rank()={}",
141                self.rank(),
142                other.rank()
143            );
144        }
145
146        let mut source: Source = Source::new(other.seed);
147        self.decompress_internal(module, other, &mut source);
148    }
149}
150
151impl<D: DataMut> GLWECiphertext<D> {
152    pub(crate) fn decompress_internal<DataOther, B: Backend>(
153        &mut self,
154        module: &Module<B>,
155        other: &GLWECiphertextCompressed<DataOther>,
156        source: &mut Source,
157    ) where
158        DataOther: DataRef,
159        Module<B>: VecZnxCopy + VecZnxFillUniform,
160    {
161        #[cfg(debug_assertions)]
162        {
163            assert_eq!(self.rank(), other.rank());
164            debug_assert_eq!(self.size(), other.size());
165        }
166
167        let k: usize = other.k;
168        let basek: usize = other.basek;
169        let cols: usize = other.rank() + 1;
170        module.vec_znx_copy(&mut self.data, 0, &other.data, 0);
171        (1..cols).for_each(|i| {
172            module.vec_znx_fill_uniform(basek, &mut self.data, i, source);
173        });
174
175        self.basek = basek;
176        self.k = k;
177    }
178}