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