poulpy_core/layouts/
gglwe_ct.rs1use poulpy_hal::{
2 layouts::{Data, DataMut, DataRef, FillUniform, MatZnx, ReaderFrom, Reset, WriterTo},
3 source::Source,
4};
5
6use crate::layouts::{GLWECiphertext, Infos};
7use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
8
9use std::fmt;
10
11#[derive(PartialEq, Eq, Clone)]
12pub struct GGLWECiphertext<D: Data> {
13 pub(crate) data: MatZnx<D>,
14 pub(crate) basek: usize,
15 pub(crate) k: usize,
16 pub(crate) digits: usize,
17}
18
19impl<D: DataRef> fmt::Debug for GGLWECiphertext<D> {
20 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21 write!(f, "{}", self)
22 }
23}
24
25impl<D: DataMut> FillUniform for GGLWECiphertext<D> {
26 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
27 self.data.fill_uniform(log_bound, source);
28 }
29}
30
31impl<D: DataMut> Reset for GGLWECiphertext<D> {
32 fn reset(&mut self) {
33 self.data.reset();
34 self.basek = 0;
35 self.k = 0;
36 self.digits = 0;
37 }
38}
39
40impl<D: DataRef> fmt::Display for GGLWECiphertext<D> {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 write!(
43 f,
44 "(GGLWECiphertext: basek={} k={} digits={}) {}",
45 self.basek, self.k, self.digits, self.data
46 )
47 }
48}
49
50impl<D: DataRef> GGLWECiphertext<D> {
51 pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
52 GLWECiphertext {
53 data: self.data.at(row, col),
54 basek: self.basek,
55 k: self.k,
56 }
57 }
58}
59
60impl<D: DataMut> GGLWECiphertext<D> {
61 pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
62 GLWECiphertext {
63 data: self.data.at_mut(row, col),
64 basek: self.basek,
65 k: self.k,
66 }
67 }
68}
69
70impl GGLWECiphertext<Vec<u8>> {
71 pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self {
72 let size: usize = k.div_ceil(basek);
73 debug_assert!(
74 size > digits,
75 "invalid gglwe: ceil(k/basek): {} <= digits: {}",
76 size,
77 digits
78 );
79
80 assert!(
81 rows * digits <= size,
82 "invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
83 rows,
84 digits,
85 size
86 );
87
88 Self {
89 data: MatZnx::alloc(n, rows, rank_in, rank_out + 1, size),
90 basek,
91 k,
92 digits,
93 }
94 }
95
96 pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> usize {
97 let size: usize = k.div_ceil(basek);
98 debug_assert!(
99 size > digits,
100 "invalid gglwe: ceil(k/basek): {} <= digits: {}",
101 size,
102 digits
103 );
104
105 assert!(
106 rows * digits <= size,
107 "invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
108 rows,
109 digits,
110 size
111 );
112
113 MatZnx::alloc_bytes(n, rows, rank_in, rank_out + 1, rows)
114 }
115}
116
117impl<D: Data> Infos for GGLWECiphertext<D> {
118 type Inner = MatZnx<D>;
119
120 fn inner(&self) -> &Self::Inner {
121 &self.data
122 }
123
124 fn basek(&self) -> usize {
125 self.basek
126 }
127
128 fn k(&self) -> usize {
129 self.k
130 }
131}
132
133impl<D: Data> GGLWECiphertext<D> {
134 pub fn rank(&self) -> usize {
135 self.data.cols_out() - 1
136 }
137
138 pub fn digits(&self) -> usize {
139 self.digits
140 }
141
142 pub fn rank_in(&self) -> usize {
143 self.data.cols_in()
144 }
145
146 pub fn rank_out(&self) -> usize {
147 self.data.cols_out() - 1
148 }
149}
150
151impl<D: DataMut> ReaderFrom for GGLWECiphertext<D> {
152 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
153 self.k = reader.read_u64::<LittleEndian>()? as usize;
154 self.basek = reader.read_u64::<LittleEndian>()? as usize;
155 self.digits = reader.read_u64::<LittleEndian>()? as usize;
156 self.data.read_from(reader)
157 }
158}
159
160impl<D: DataRef> WriterTo for GGLWECiphertext<D> {
161 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
162 writer.write_u64::<LittleEndian>(self.k as u64)?;
163 writer.write_u64::<LittleEndian>(self.basek as u64)?;
164 writer.write_u64::<LittleEndian>(self.digits as u64)?;
165 self.data.write_to(writer)
166 }
167}