1use std::fmt;
2
3use poulpy_hal::{
4 layouts::{Backend, Data, FillUniform, HostDataMut, HostDataRef, ReaderFrom, WriterTo},
5 source::Source,
6};
7
8use crate::{
9 DeclaredK,
10 layouts::{
11 Base2K, Degree, Dnum, Dsize, GGLWEAtViewMut, GGLWEAtViewRef, GGLWEBackendMut, GGLWEBackendRef, GGLWEInfos,
12 GGLWEToBackendMut, GGLWEToBackendRef, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeyDegrees, GLWESwitchingKeyDegreesMut,
13 GLWEViewMut, GLWEViewRef, LWEInfos, Rank, TorusPrecision,
14 },
15};
16
17#[derive(PartialEq, Eq, Copy, Clone, Debug)]
18pub struct LWESwitchingKeyLayout {
19 pub n: Degree,
20 pub base2k: Base2K,
21 pub k: TorusPrecision,
22 pub dnum: Dnum,
23}
24
25impl DeclaredK for LWESwitchingKeyLayout {
26 fn k(&self) -> TorusPrecision {
27 self.k
28 }
29}
30
31impl LWEInfos for LWESwitchingKeyLayout {
32 fn n(&self) -> Degree {
33 self.n
34 }
35
36 fn base2k(&self) -> Base2K {
37 self.base2k
38 }
39
40 fn size(&self) -> usize {
41 self.k.as_usize().div_ceil(self.base2k.as_usize())
42 }
43}
44
45impl GLWEInfos for LWESwitchingKeyLayout {
46 fn rank(&self) -> Rank {
47 self.rank_out()
48 }
49}
50
51impl GGLWEInfos for LWESwitchingKeyLayout {
52 fn rank_in(&self) -> Rank {
53 Rank(1)
54 }
55
56 fn dsize(&self) -> Dsize {
57 Dsize(1)
58 }
59
60 fn rank_out(&self) -> Rank {
61 Rank(1)
62 }
63
64 fn dnum(&self) -> Dnum {
65 self.dnum
66 }
67}
68
69#[derive(PartialEq, Eq, Clone)]
70pub struct LWESwitchingKey<D: Data>(pub(crate) GLWESwitchingKey<D>);
71
72impl<D: Data> LWEInfos for LWESwitchingKey<D> {
73 fn base2k(&self) -> Base2K {
74 self.0.base2k()
75 }
76
77 fn n(&self) -> Degree {
78 self.0.n()
79 }
80
81 fn size(&self) -> usize {
82 self.0.size()
83 }
84}
85
86impl<D: Data> GLWEInfos for LWESwitchingKey<D> {
87 fn rank(&self) -> Rank {
88 self.rank_out()
89 }
90}
91
92impl<D: Data> GGLWEInfos for LWESwitchingKey<D> {
93 fn dsize(&self) -> Dsize {
94 self.0.dsize()
95 }
96
97 fn rank_in(&self) -> Rank {
98 self.0.rank_in()
99 }
100
101 fn rank_out(&self) -> Rank {
102 self.0.rank_out()
103 }
104
105 fn dnum(&self) -> Dnum {
106 self.0.dnum()
107 }
108}
109
110#[expect(
111 dead_code,
112 reason = "host-owned constructors are kept for serialization and host-only staging"
113)]
114impl LWESwitchingKey<Vec<u8>> {
115 pub(crate) fn alloc_from_infos<A>(infos: &A) -> Self
116 where
117 A: GGLWEInfos,
118 {
119 assert_eq!(infos.dsize().0, 1, "dsize > 1 is not supported for LWESwitchingKey");
120 assert_eq!(infos.rank_in().0, 1, "rank_in > 1 is not supported for LWESwitchingKey");
121 assert_eq!(infos.rank_out().0, 1, "rank_out > 1 is not supported for LWESwitchingKey");
122 Self::alloc(infos.n(), infos.base2k(), infos.max_k(), infos.dnum())
123 }
124
125 pub(crate) fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> Self {
126 LWESwitchingKey(GLWESwitchingKey::alloc(n, base2k, k, Rank(1), Rank(1), dnum, Dsize(1)))
127 }
128
129 pub fn bytes_of_from_infos<A>(infos: &A) -> usize
130 where
131 A: GGLWEInfos,
132 {
133 assert_eq!(infos.dsize().0, 1, "dsize > 1 is not supported for LWESwitchingKey");
134 assert_eq!(infos.rank_in().0, 1, "rank_in > 1 is not supported for LWESwitchingKey");
135 assert_eq!(infos.rank_out().0, 1, "rank_out > 1 is not supported for LWESwitchingKey");
136 Self::bytes_of(infos.n(), infos.base2k(), infos.max_k(), infos.dnum())
137 }
138
139 pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, dnum: Dnum) -> usize {
140 GLWESwitchingKey::bytes_of(n, base2k, k, Rank(1), Rank(1), dnum, Dsize(1))
141 }
142}
143
144impl<D: HostDataRef> fmt::Debug for LWESwitchingKey<D> {
145 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146 write!(f, "{self}")
147 }
148}
149
150impl<D: HostDataMut> FillUniform for LWESwitchingKey<D> {
151 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
152 self.0.fill_uniform(log_bound, source);
153 }
154}
155
156impl<D: HostDataRef> fmt::Display for LWESwitchingKey<D> {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 write!(f, "(LWESwitchingKey) {}", self.0)
159 }
160}
161
162impl<D: HostDataMut> ReaderFrom for LWESwitchingKey<D> {
163 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
164 self.0.read_from(reader)
165 }
166}
167
168impl<D: HostDataRef> WriterTo for LWESwitchingKey<D> {
169 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
170 self.0.write_to(writer)
171 }
172}
173
174impl_gglwe_to_backend_for_field!(LWESwitchingKey<D>, 0, GLWESwitchingKey<D>);
175
176impl_gglwe_at_view_for_field!(LWESwitchingKey<BE::OwnedBuf>; 0.key);
177
178impl<D: HostDataMut> GLWESwitchingKeyDegreesMut for LWESwitchingKey<D> {
179 fn input_degree(&mut self) -> &mut Degree {
180 &mut self.0.input_degree
181 }
182
183 fn output_degree(&mut self) -> &mut Degree {
184 &mut self.0.output_degree
185 }
186}
187
188impl<D: HostDataRef> GLWESwitchingKeyDegrees for LWESwitchingKey<D> {
189 fn input_degree(&self) -> &Degree {
190 &self.0.input_degree
191 }
192
193 fn output_degree(&self) -> &Degree {
194 &self.0.output_degree
195 }
196}