poulpy_core/layouts/
ggsw_ct.rs

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