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