poulpy_core/layouts/compressed/
glwe_ct.rs1use 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}