1use poulpy_hal::{
2 layouts::{Backend, Data, FillUniform, HostDataMut, HostDataRef, ReaderFrom, WriterTo},
3 source::Source,
4};
5
6use crate::{
7 DeclaredK,
8 layouts::{
9 Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEAtViewMut, GGLWEAtViewRef, GGLWEBackendMut, GGLWEBackendRef, GGLWEInfos,
10 GGLWEToBackendMut, GGLWEToBackendRef, GLWE, GLWEInfos, GLWEViewMut, GLWEViewRef, LWEInfos, Rank, TorusPrecision,
11 },
12};
13use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
14
15use std::fmt;
16
17#[derive(PartialEq, Eq, Copy, Clone, Debug)]
23pub struct GLWESwitchingKeyLayout {
24 pub n: Degree,
25 pub base2k: Base2K,
26 pub k: TorusPrecision,
27 pub rank_in: Rank,
28 pub rank_out: Rank,
29 pub dnum: Dnum,
30 pub dsize: Dsize,
31}
32
33impl DeclaredK for GLWESwitchingKeyLayout {
34 fn k(&self) -> TorusPrecision {
35 self.k
36 }
37}
38
39impl LWEInfos for GLWESwitchingKeyLayout {
40 fn n(&self) -> Degree {
41 self.n
42 }
43
44 fn base2k(&self) -> Base2K {
45 self.base2k
46 }
47
48 fn size(&self) -> usize {
49 self.k.as_usize().div_ceil(self.base2k.as_usize())
50 }
51}
52
53impl GLWEInfos for GLWESwitchingKeyLayout {
54 fn rank(&self) -> Rank {
55 self.rank_out()
56 }
57}
58
59impl GGLWEInfos for GLWESwitchingKeyLayout {
60 fn rank_in(&self) -> Rank {
61 self.rank_in
62 }
63
64 fn rank_out(&self) -> Rank {
65 self.rank_out
66 }
67
68 fn dsize(&self) -> Dsize {
69 self.dsize
70 }
71
72 fn dnum(&self) -> Dnum {
73 self.dnum
74 }
75}
76
77#[derive(PartialEq, Eq, Clone)]
85pub struct GLWESwitchingKey<D: Data> {
86 pub(crate) key: GGLWE<D>,
87 pub(crate) input_degree: Degree, pub(crate) output_degree: Degree, }
90
91pub trait GLWESwitchingKeyDegrees {
94 fn input_degree(&self) -> &Degree;
96 fn output_degree(&self) -> &Degree;
98}
99
100impl<D: HostDataRef> GLWESwitchingKeyDegrees for GLWESwitchingKey<D> {
101 fn output_degree(&self) -> &Degree {
102 &self.output_degree
103 }
104
105 fn input_degree(&self) -> &Degree {
106 &self.input_degree
107 }
108}
109
110pub trait GLWESwitchingKeyDegreesMut {
113 fn input_degree(&mut self) -> &mut Degree;
115 fn output_degree(&mut self) -> &mut Degree;
117}
118
119impl<D: HostDataMut> GLWESwitchingKeyDegreesMut for GLWESwitchingKey<D> {
120 fn output_degree(&mut self) -> &mut Degree {
121 &mut self.output_degree
122 }
123
124 fn input_degree(&mut self) -> &mut Degree {
125 &mut self.input_degree
126 }
127}
128
129impl<D: Data> LWEInfos for GLWESwitchingKey<D> {
130 fn n(&self) -> Degree {
131 self.key.n()
132 }
133
134 fn base2k(&self) -> Base2K {
135 self.key.base2k()
136 }
137
138 fn size(&self) -> usize {
139 self.key.size()
140 }
141}
142
143impl<D: Data> GLWEInfos for GLWESwitchingKey<D> {
144 fn rank(&self) -> Rank {
145 self.rank_out()
146 }
147}
148
149impl<D: Data> GGLWEInfos for GLWESwitchingKey<D> {
150 fn rank_in(&self) -> Rank {
151 self.key.rank_in()
152 }
153
154 fn rank_out(&self) -> Rank {
155 self.key.rank_out()
156 }
157
158 fn dsize(&self) -> Dsize {
159 self.key.dsize()
160 }
161
162 fn dnum(&self) -> Dnum {
163 self.key.dnum()
164 }
165}
166
167impl<D: HostDataRef> fmt::Debug for GLWESwitchingKey<D> {
168 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169 write!(f, "{self}")
170 }
171}
172
173impl<D: HostDataRef> fmt::Display for GLWESwitchingKey<D> {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 write!(
176 f,
177 "(GLWESwitchingKey: sk_in_n={} sk_out_n={}) {}",
178 self.input_degree,
179 self.output_degree,
180 self.key.data()
181 )
182 }
183}
184
185impl<D: HostDataMut> FillUniform for GLWESwitchingKey<D> {
186 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
187 self.key.fill_uniform(log_bound, source);
188 }
189}
190
191#[expect(
192 dead_code,
193 reason = "host-owned constructors are kept for serialization and host-only staging"
194)]
195impl GLWESwitchingKey<Vec<u8>> {
196 pub(crate) fn alloc_from_infos<A>(infos: &A) -> Self
198 where
199 A: GGLWEInfos,
200 {
201 Self::alloc(
202 infos.n(),
203 infos.base2k(),
204 infos.max_k(),
205 infos.rank_in(),
206 infos.rank_out(),
207 infos.dnum(),
208 infos.dsize(),
209 )
210 }
211
212 pub(crate) fn alloc(
214 n: Degree,
215 base2k: Base2K,
216 k: TorusPrecision,
217 rank_in: Rank,
218 rank_out: Rank,
219 dnum: Dnum,
220 dsize: Dsize,
221 ) -> Self {
222 GLWESwitchingKey {
223 key: GGLWE::alloc(n, base2k, k, rank_in, rank_out, dnum, dsize),
224 input_degree: Degree(0),
225 output_degree: Degree(0),
226 }
227 }
228
229 pub fn bytes_of_from_infos<A>(infos: &A) -> usize
231 where
232 A: GGLWEInfos,
233 {
234 Self::bytes_of(
235 infos.n(),
236 infos.base2k(),
237 infos.max_k(),
238 infos.rank_in(),
239 infos.rank_out(),
240 infos.dnum(),
241 infos.dsize(),
242 )
243 }
244
245 pub fn bytes_of(
247 n: Degree,
248 base2k: Base2K,
249 k: TorusPrecision,
250 rank_in: Rank,
251 rank_out: Rank,
252 dnum: Dnum,
253 dsize: Dsize,
254 ) -> usize {
255 GGLWE::bytes_of(n, base2k, k, rank_in, rank_out, dnum, dsize)
256 }
257}
258
259impl_gglwe_to_backend_for_field!(GLWESwitchingKey<D>, key, GGLWE<D>);
260
261impl_gglwe_at_view_for_field!(GLWESwitchingKey<BE::OwnedBuf>; key);
262
263impl_glwe_host_at_for_field!(GLWESwitchingKey<D>; key);
264
265impl<D: HostDataMut> ReaderFrom for GLWESwitchingKey<D> {
266 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
268 self.input_degree = Degree(reader.read_u32::<LittleEndian>()?);
269 self.output_degree = Degree(reader.read_u32::<LittleEndian>()?);
270 self.key.read_from(reader)
271 }
272}
273
274impl<D: HostDataRef> WriterTo for GLWESwitchingKey<D> {
275 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
277 writer.write_u32::<LittleEndian>(self.input_degree.into())?;
278 writer.write_u32::<LittleEndian>(self.output_degree.into())?;
279 self.key.write_to(writer)
280 }
281}