1use poulpy_hal::{
2 layouts::{Backend, Data, FillUniform, HostDataMut, HostDataRef, ReaderFrom, WriterTo},
3 source::Source,
4};
5
6use crate::layouts::{
7 Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEAtBackendMut, GGLWEAtBackendRef, GGLWEAtViewMut, GGLWEAtViewRef, GGLWEBackendMut,
8 GGLWEBackendRef, GGLWEInfos, GGLWEToBackendMut, GGLWEToBackendRef, GLWE, GLWEInfos, GLWEViewMut, GLWEViewRef, LWEInfos, Rank,
9 TorusPrecision,
10};
11
12use poulpy_hal::layouts::ZnxWord;
13use std::fmt;
14
15#[derive(PartialEq, Eq, Copy, Clone, Debug)]
22pub struct GLWETensorKeyLayout {
23 pub n: Degree,
24 pub base2k: Base2K,
25 pub dnum: Dnum,
26 pub k_aux: TorusPrecision,
27 pub rank: Rank,
28 pub dsize: Dsize,
29}
30
31#[derive(PartialEq, Eq, Clone)]
39pub struct GLWETensorKey<D: Data, W: ZnxWord>(pub(crate) GGLWE<D, W>);
40
41impl<D: Data, W: ZnxWord> LWEInfos for GLWETensorKey<D, W> {
42 fn n(&self) -> Degree {
43 self.0.n()
44 }
45
46 fn base2k(&self) -> Base2K {
47 self.0.base2k()
48 }
49
50 fn max_size(&self) -> usize {
51 self.0.max_size()
52 }
53
54 fn k(&self) -> TorusPrecision {
55 self.0.k()
56 }
57}
58
59impl<D: Data, W: ZnxWord> GLWEInfos for GLWETensorKey<D, W> {
60 fn rank(&self) -> Rank {
61 self.0.rank_out()
62 }
63}
64
65impl<D: Data, W: ZnxWord> GGLWEInfos for GLWETensorKey<D, W> {
66 fn k_aux(&self) -> TorusPrecision {
67 self.0.k_aux()
68 }
69
70 fn rank_in(&self) -> Rank {
71 let rank_out: usize = self.rank_out().as_usize();
72 let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1);
73 pairs.into()
74 }
75
76 fn rank_out(&self) -> Rank {
77 self.0.rank_out()
78 }
79
80 fn dsize(&self) -> Dsize {
81 self.0.dsize()
82 }
83
84 fn dnum(&self) -> Dnum {
85 self.0.dnum()
86 }
87}
88
89impl LWEInfos for GLWETensorKeyLayout {
90 fn n(&self) -> Degree {
91 self.n
92 }
93
94 fn base2k(&self) -> Base2K {
95 self.base2k
96 }
97
98 fn max_size(&self) -> usize {
99 crate::layouts::key_size(self.base2k, self.dnum, self.dsize, self.k_aux)
100 }
101
102 fn k(&self) -> TorusPrecision {
103 crate::layouts::key_k(self.base2k, self.dnum, self.dsize, self.k_aux)
104 }
105}
106
107impl GLWEInfos for GLWETensorKeyLayout {
108 fn rank(&self) -> Rank {
109 self.rank_out()
110 }
111}
112
113impl GGLWEInfos for GLWETensorKeyLayout {
114 fn k_aux(&self) -> TorusPrecision {
115 self.k_aux
116 }
117
118 fn dnum(&self) -> Dnum {
119 self.dnum
120 }
121
122 fn rank_in(&self) -> Rank {
123 let rank_out: usize = self.rank_out().as_usize();
124 let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1);
125 pairs.into()
126 }
127
128 fn dsize(&self) -> Dsize {
129 self.dsize
130 }
131
132 fn rank_out(&self) -> Rank {
133 self.rank
134 }
135}
136
137impl<BE: Backend> GGLWEAtBackendRef<BE> for GLWETensorKey<BE::OwnedBuf, BE::ZnxWord> {
138 fn at_backend(&self, row: usize, col: usize) -> GLWE<BE::BufRef<'_>, BE::ZnxWord> {
139 <GGLWE<BE::OwnedBuf, BE::ZnxWord> as GGLWEAtBackendRef<BE>>::at_backend(&self.0, row, col)
140 }
141}
142
143impl<BE: Backend> GGLWEAtBackendMut<BE> for GLWETensorKey<BE::OwnedBuf, BE::ZnxWord> {
144 fn at_backend_mut(&mut self, row: usize, col: usize) -> GLWE<BE::BufMut<'_>, BE::ZnxWord> {
145 <GGLWE<BE::OwnedBuf, BE::ZnxWord> as GGLWEAtBackendMut<BE>>::at_backend_mut(&mut self.0, row, col)
146 }
147}
148
149impl<D: HostDataRef, W: ZnxWord> fmt::Debug for GLWETensorKey<D, W> {
150 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151 write!(f, "{self}")
152 }
153}
154
155impl<D: HostDataMut, W: ZnxWord> FillUniform for GLWETensorKey<D, W> {
156 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
157 self.0.fill_uniform(log_bound, source)
158 }
159}
160
161impl<D: HostDataRef, W: ZnxWord> fmt::Display for GLWETensorKey<D, W> {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163 writeln!(f, "(GLWETensorKey)",)?;
164 write!(f, "{}", self.0)?;
165 Ok(())
166 }
167}
168
169#[expect(
170 dead_code,
171 reason = "host-owned constructors are kept for serialization and host-only staging"
172)]
173impl<W: ZnxWord> GLWETensorKey<Vec<u8>, W> {
174 pub(crate) fn alloc_from_infos<A>(infos: &A) -> Self
176 where
177 A: GGLWEInfos,
178 {
179 Self::alloc(
180 infos.n(),
181 infos.base2k(),
182 infos.dnum(),
183 infos.dsize(),
184 infos.k_aux(),
185 infos.rank(),
186 )
187 }
188
189 pub(crate) fn alloc(n: Degree, base2k: Base2K, dnum: Dnum, dsize: Dsize, k_aux: TorusPrecision, rank: Rank) -> Self {
191 let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1);
192 GLWETensorKey(GGLWE::alloc(n, base2k, dnum, dsize, k_aux, Rank(pairs), rank))
193 }
194
195 pub fn bytes_of_from_infos<A>(infos: &A) -> usize
197 where
198 A: GGLWEInfos,
199 {
200 Self::bytes_of(
201 infos.n(),
202 infos.base2k(),
203 infos.dnum(),
204 infos.dsize(),
205 infos.k_aux(),
206 infos.rank(),
207 )
208 }
209
210 pub fn bytes_of(n: Degree, base2k: Base2K, dnum: Dnum, dsize: Dsize, k_aux: TorusPrecision, rank: Rank) -> usize {
212 let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1);
213 GGLWE::<Vec<u8>, W>::bytes_of(n, base2k, dnum, dsize, k_aux, Rank(pairs), rank)
214 }
215}
216
217impl<D: HostDataMut, W: ZnxWord> ReaderFrom for GLWETensorKey<D, W> {
218 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
219 self.0.read_from(reader)?;
220 Ok(())
221 }
222}
223
224impl<D: HostDataRef, W: ZnxWord> WriterTo for GLWETensorKey<D, W> {
225 fn write_to<Wr: std::io::Write>(&self, writer: &mut Wr) -> std::io::Result<()> {
226 self.0.write_to(writer)?;
227 Ok(())
228 }
229}
230
231impl_gglwe_to_backend_for_field!(GLWETensorKey<D, BE::ZnxWord>, 0, GGLWE<D, BE::ZnxWord>);
232
233impl_gglwe_at_view_for_field!(GLWETensorKey<BE::OwnedBuf, BE::ZnxWord>; 0);