1use poulpy_hal::{
2 api::VecZnxAutomorphismBackend,
3 layouts::{
4 Backend, Data, HostDataMut, HostDataRef, Module, ScalarZnx, ScalarZnxAsVecZnxBackendMut, ScalarZnxToBackendMut,
5 ScalarZnxToBackendRef, TransferFrom, VecZnx, ZnxZero, scalar_znx_as_vec_znx_backend_ref_from_ref,
6 },
7 oep::HalVecZnxImpl,
8 source::Source,
9};
10
11use crate::{
12 GetDistribution,
13 api::ModuleTransfer,
14 dist::Distribution,
15 layouts::{Base2K, Degree, GLWEInfos, LWEInfos, Rank},
16};
17
18use super::{
19 ModuleCoreAlloc,
20 lwe_secret::{LWESecret, LWESecretToBackendRef},
21};
22
23#[derive(PartialEq, Eq, Copy, Clone, Debug)]
24pub struct GLWESecretLayout {
25 pub n: Degree,
26 pub rank: Rank,
27}
28
29impl LWEInfos for GLWESecretLayout {
30 fn base2k(&self) -> Base2K {
31 Base2K(0)
32 }
33
34 fn n(&self) -> Degree {
35 self.n
36 }
37
38 fn size(&self) -> usize {
39 1
40 }
41}
42impl GLWEInfos for GLWESecretLayout {
43 fn rank(&self) -> Rank {
44 self.rank
45 }
46}
47
48#[derive(PartialEq, Eq, Clone)]
49pub struct GLWESecret<D: Data> {
50 pub(crate) data: ScalarZnx<D>,
51 pub(crate) dist: Distribution,
52}
53
54pub type GLWESecretBackendRef<'a, BE> = GLWESecret<<BE as Backend>::BufRef<'a>>;
55pub type GLWESecretBackendMut<'a, BE> = GLWESecret<<BE as Backend>::BufMut<'a>>;
56
57impl<D: Data> LWEInfos for GLWESecret<D> {
58 fn base2k(&self) -> Base2K {
59 Base2K(0)
60 }
61
62 fn n(&self) -> Degree {
63 Degree(self.data.n() as u32)
64 }
65
66 fn size(&self) -> usize {
67 1
68 }
69}
70
71impl<D: Data> LWEInfos for &mut GLWESecret<D> {
72 fn base2k(&self) -> Base2K {
73 (**self).base2k()
74 }
75
76 fn n(&self) -> Degree {
77 (**self).n()
78 }
79
80 fn size(&self) -> usize {
81 (**self).size()
82 }
83}
84
85impl<D: Data> GetDistribution for GLWESecret<D> {
86 fn dist(&self) -> &Distribution {
87 &self.dist
88 }
89}
90
91impl<D: Data> GLWEInfos for GLWESecret<D> {
92 fn rank(&self) -> Rank {
93 Rank(self.data.cols() as u32)
94 }
95}
96
97impl<D: Data> GLWEInfos for &mut GLWESecret<D> {
98 fn rank(&self) -> Rank {
99 (**self).rank()
100 }
101}
102
103impl<D: HostDataRef> GLWESecret<D> {
104 pub fn to_backend<BE, To>(&self, dst: &Module<To>) -> GLWESecret<To::OwnedBuf>
107 where
108 BE: Backend<OwnedBuf = D>,
109 To: Backend,
110 To: TransferFrom<BE>,
111 {
112 dst.upload_glwe_secret(self)
113 }
114}
115
116impl<D: Data> GLWESecret<D> {
117 pub fn reinterpret<To>(self) -> GLWESecret<To::OwnedBuf>
119 where
120 To: Backend<OwnedBuf = D>,
121 {
122 let n = self.data.n();
123 let cols = self.data.cols();
124 let data = self.data.data;
125 GLWESecret {
126 data: ScalarZnx::from_data(data, n, cols),
127 dist: self.dist,
128 }
129 }
130}
131
132#[expect(
133 dead_code,
134 reason = "host-owned constructors are kept for serialization and host-only staging"
135)]
136impl GLWESecret<Vec<u8>> {
137 pub(crate) fn alloc_from_infos<A>(infos: &A) -> Self
138 where
139 A: GLWEInfos,
140 {
141 Self::alloc(infos.n(), infos.rank())
142 }
143
144 pub(crate) fn alloc(n: Degree, rank: Rank) -> Self {
145 GLWESecret {
146 data: ScalarZnx::from_data(
147 poulpy_hal::layouts::HostBytesBackend::alloc_bytes(ScalarZnx::<Vec<u8>>::bytes_of(n.into(), rank.into())),
148 n.into(),
149 rank.into(),
150 ),
151 dist: Distribution::NONE,
152 }
153 }
154
155 pub fn bytes_of_from_infos<A>(infos: &A) -> usize
156 where
157 A: GLWEInfos,
158 {
159 Self::bytes_of(infos.n(), infos.rank())
160 }
161
162 pub fn bytes_of(n: Degree, rank: Rank) -> usize {
163 ScalarZnx::bytes_of(n.into(), rank.into())
164 }
165}
166
167impl<D: HostDataMut> GLWESecret<D> {
168 pub fn fill_ternary_prob(&mut self, prob: f64, source: &mut Source) {
169 (0..self.rank().into()).for_each(|i| {
170 self.data.fill_ternary_prob(i, prob, source);
171 });
172 self.dist = Distribution::TernaryProb(prob);
173 }
174
175 pub fn fill_ternary_hw(&mut self, hw: usize, source: &mut Source) {
176 (0..self.rank().into()).for_each(|i| {
177 self.data.fill_ternary_hw(i, hw, source);
178 });
179 self.dist = Distribution::TernaryFixed(hw);
180 }
181
182 pub fn fill_binary_prob(&mut self, prob: f64, source: &mut Source) {
183 (0..self.rank().into()).for_each(|i| {
184 self.data.fill_binary_prob(i, prob, source);
185 });
186 self.dist = Distribution::BinaryProb(prob);
187 }
188
189 pub fn fill_binary_hw(&mut self, hw: usize, source: &mut Source) {
190 (0..self.rank().into()).for_each(|i| {
191 self.data.fill_binary_hw(i, hw, source);
192 });
193 self.dist = Distribution::BinaryFixed(hw);
194 }
195
196 pub fn fill_binary_block(&mut self, block_size: usize, source: &mut Source) {
197 (0..self.rank().into()).for_each(|i| {
198 self.data.fill_binary_block(i, block_size, source);
199 });
200 self.dist = Distribution::BinaryBlock(block_size);
201 }
202
203 pub fn fill_zero(&mut self) {
204 self.data.zero();
205 self.dist = Distribution::ZERO;
206 }
207}
208
209pub trait GLWESecretToBackendMut<BE: Backend>: GLWESecretToBackendRef<BE> {
210 fn to_backend_mut(&mut self) -> GLWESecretBackendMut<'_, BE>;
211}
212
213impl<BE: Backend> GLWESecretToBackendMut<BE> for GLWESecret<BE::OwnedBuf> {
214 fn to_backend_mut(&mut self) -> GLWESecretBackendMut<'_, BE> {
215 GLWESecret {
216 dist: self.dist,
217 data: <ScalarZnx<BE::OwnedBuf> as ScalarZnxToBackendMut<BE>>::to_backend_mut(&mut self.data),
218 }
219 }
220}
221
222impl<'b, BE: Backend + 'b> GLWESecretToBackendMut<BE> for &mut GLWESecret<BE::BufMut<'b>> {
223 fn to_backend_mut(&mut self) -> GLWESecretBackendMut<'_, BE> {
224 let n = self.data.n();
225 let cols = self.data.cols();
226 GLWESecret {
227 dist: self.dist,
228 data: ScalarZnx::from_data(BE::view_mut_ref(&mut self.data.data), n, cols),
229 }
230 }
231}
232
233pub trait GLWESecretToBackendRef<BE: Backend> {
234 fn to_backend_ref(&self) -> GLWESecretBackendRef<'_, BE>;
235}
236
237impl<BE: Backend> GLWESecretToBackendRef<BE> for GLWESecret<BE::OwnedBuf> {
238 fn to_backend_ref(&self) -> GLWESecretBackendRef<'_, BE> {
239 GLWESecret {
240 data: <ScalarZnx<BE::OwnedBuf> as ScalarZnxToBackendRef<BE>>::to_backend_ref(&self.data),
241 dist: self.dist,
242 }
243 }
244}
245
246impl<'b, BE: Backend + 'b> GLWESecretToBackendRef<BE> for &GLWESecret<BE::BufRef<'b>> {
247 fn to_backend_ref(&self) -> GLWESecretBackendRef<'_, BE> {
248 GLWESecret {
249 data: ScalarZnx::from_data(BE::view_ref(&self.data.data), self.data.n(), self.data.cols()),
250 dist: self.dist,
251 }
252 }
253}
254
255impl<'b, BE: Backend + 'b> GLWESecretToBackendRef<BE> for &mut GLWESecret<BE::BufMut<'b>> {
256 fn to_backend_ref(&self) -> GLWESecretBackendRef<'_, BE> {
257 GLWESecret {
258 data: ScalarZnx::from_data(BE::view_ref_mut(&self.data.data), self.data.n(), self.data.cols()),
259 dist: self.dist,
260 }
261 }
262}
263
264pub trait SecretConversion<B: Backend> {
265 fn glwe_secret_from_lwe_secret<S>(&self, src: &S) -> GLWESecret<B::OwnedBuf>
270 where
271 S: LWESecretToBackendRef<B>;
272
273 fn lwe_secret_from_glwe_secret<S>(&self, src: &S) -> LWESecret<B::OwnedBuf>
286 where
287 S: GLWESecretToBackendRef<B>;
288}
289
290impl<B: Backend + HalVecZnxImpl<B>> SecretConversion<B> for Module<B> {
291 fn glwe_secret_from_lwe_secret<S>(&self, src: &S) -> GLWESecret<B::OwnedBuf>
292 where
293 S: LWESecretToBackendRef<B>,
294 {
295 let src = src.to_backend_ref();
296 assert_eq!(src.n().as_usize(), self.n(), "LWE secret degree must equal module degree");
297 let mut res = self.glwe_secret_alloc(Rank(1));
298 res.dist = src.dist;
299 {
300 let src_vec = scalar_znx_as_vec_znx_backend_ref_from_ref::<B>(&src.data);
301 let mut res_vec = <ScalarZnx<B::OwnedBuf> as ScalarZnxAsVecZnxBackendMut<B>>::as_vec_znx_backend_mut(&mut res.data);
302 self.vec_znx_automorphism_backend(-1, &mut res_vec, 0, &src_vec, 0);
303 }
304 res
305 }
306
307 fn lwe_secret_from_glwe_secret<S>(&self, src: &S) -> LWESecret<B::OwnedBuf>
308 where
309 S: GLWESecretToBackendRef<B>,
310 {
311 let src = src.to_backend_ref();
312 let n = self.n();
313 let rank: usize = src.rank().into();
314 assert_eq!(src.n().as_usize(), n, "GLWE secret degree must equal module degree");
315 let mut res = self.lwe_secret_alloc(Degree((n * rank) as u32));
316 res.dist = src.dist;
317 {
318 let src_vec = scalar_znx_as_vec_znx_backend_ref_from_ref::<B>(&src.data);
319 let res_as_backend = <ScalarZnx<B::OwnedBuf> as ScalarZnxToBackendMut<B>>::to_backend_mut(&mut res.data);
320 let mut res_vec = VecZnx::from_data(res_as_backend.data, n, rank, 1);
321 for j in 0..rank {
322 self.vec_znx_automorphism_backend(-1, &mut res_vec, j, &src_vec, j);
323 }
324 }
325 res
326 }
327}