poulpy/backend/src/vec_znx_big_ops.rs
backend/src/vec_znx_big_ops.rsRaw
1use crate::ffi::vec_znx;
2use crate::znx_base::{ZnxInfos, ZnxView, ZnxViewMut};
3use crate::{
4 Backend, FFT64, Module, Scratch, VecZnx, VecZnxBig, VecZnxBigOwned, VecZnxBigToMut, VecZnxBigToRef, VecZnxScratch,
5 VecZnxToMut, VecZnxToRef, ZnxSliceSize, bytes_of_vec_znx_big,
6};
7
8pub trait VecZnxBigAlloc<B: Backend> {
9 /// Allocates a vector Z[X]/(X^N+1) that stores not normalized values.
10 fn new_vec_znx_big(&self, cols: usize, size: usize) -> VecZnxBigOwned<B>;
11
12 /// Returns a new [VecZnxBig] with the provided bytes array as backing array.
13 ///
14 /// Behavior: takes ownership of the backing array.
15 ///
16 /// # Arguments
17 ///
18 /// * `cols`: the number of polynomials..
19 /// * `size`: the number of polynomials per column.
20 /// * `bytes`: a byte array of size at least [Module::bytes_of_vec_znx_big].
21 ///
22 /// # Panics
23 /// If `bytes.len()` < [Module::bytes_of_vec_znx_big].
24 fn new_vec_znx_big_from_bytes(&self, cols: usize, size: usize, bytes: Vec<u8>) -> VecZnxBigOwned<B>;
25
26 // /// Returns a new [VecZnxBig] with the provided bytes array as backing array.
27 // ///
28 // /// Behavior: the backing array is only borrowed.
29 // ///
30 // /// # Arguments
31 // ///
32 // /// * `cols`: the number of polynomials..
33 // /// * `size`: the number of polynomials per column.
34 // /// * `bytes`: a byte array of size at least [Module::bytes_of_vec_znx_big].
35 // ///
36 // /// # Panics
37 // /// If `bytes.len()` < [Module::bytes_of_vec_znx_big].
38 // fn new_vec_znx_big_from_bytes_borrow(&self, cols: usize, size: usize, tmp_bytes: &mut [u8]) -> VecZnxBig<B>;
39
40 /// Returns the minimum number of bytes necessary to allocate
41 /// a new [VecZnxBig] through [VecZnxBig::from_bytes].
42 fn bytes_of_vec_znx_big(&self, cols: usize, size: usize) -> usize;
43}
44
45pub trait VecZnxBigOps<BACKEND: Backend> {
46 /// Adds `a` to `b` and stores the result on `c`.
47 fn vec_znx_big_add<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
48 where
49 R: VecZnxBigToMut<BACKEND>,
50 A: VecZnxBigToRef<BACKEND>,
51 B: VecZnxBigToRef<BACKEND>;
52
53 /// Adds `a` to `b` and stores the result on `b`.
54 fn vec_znx_big_add_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
55 where
56 R: VecZnxBigToMut<BACKEND>,
57 A: VecZnxBigToRef<BACKEND>;
58
59 /// Adds `a` to `b` and stores the result on `c`.
60 fn vec_znx_big_add_small<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
61 where
62 R: VecZnxBigToMut<BACKEND>,
63 A: VecZnxBigToRef<BACKEND>,
64 B: VecZnxToRef;
65
66 /// Adds `a` to `b` and stores the result on `b`.
67 fn vec_znx_big_add_small_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
68 where
69 R: VecZnxBigToMut<BACKEND>,
70 A: VecZnxToRef;
71
72 /// Subtracts `a` to `b` and stores the result on `c`.
73 fn vec_znx_big_sub<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
74 where
75 R: VecZnxBigToMut<BACKEND>,
76 A: VecZnxBigToRef<BACKEND>,
77 B: VecZnxBigToRef<BACKEND>;
78
79 /// Subtracts `a` from `b` and stores the result on `b`.
80 fn vec_znx_big_sub_ab_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
81 where
82 R: VecZnxBigToMut<BACKEND>,
83 A: VecZnxBigToRef<BACKEND>;
84
85 /// Subtracts `b` from `a` and stores the result on `b`.
86 fn vec_znx_big_sub_ba_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
87 where
88 R: VecZnxBigToMut<BACKEND>,
89 A: VecZnxBigToRef<BACKEND>;
90
91 /// Subtracts `b` from `a` and stores the result on `c`.
92 fn vec_znx_big_sub_small_a<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
93 where
94 R: VecZnxBigToMut<BACKEND>,
95 A: VecZnxToRef,
96 B: VecZnxBigToRef<BACKEND>;
97
98 /// Subtracts `a` from `res` and stores the result on `res`.
99 fn vec_znx_big_sub_small_a_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
100 where
101 R: VecZnxBigToMut<BACKEND>,
102 A: VecZnxToRef;
103
104 /// Subtracts `b` from `a` and stores the result on `c`.
105 fn vec_znx_big_sub_small_b<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
106 where
107 R: VecZnxBigToMut<BACKEND>,
108 A: VecZnxBigToRef<BACKEND>,
109 B: VecZnxToRef;
110
111 /// Subtracts `res` from `a` and stores the result on `res`.
112 fn vec_znx_big_sub_small_b_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
113 where
114 R: VecZnxBigToMut<BACKEND>,
115 A: VecZnxToRef;
116
117 /// Negates `a` inplace.
118 fn vec_znx_big_negate_inplace<A>(&self, a: &mut A, a_col: usize)
119 where
120 A: VecZnxBigToMut<BACKEND>;
121
122 /// Normalizes `a` and stores the result on `b`.
123 ///
124 /// # Arguments
125 ///
126 /// * `basek`: normalization basis.
127 /// * `tmp_bytes`: scratch space of size at least [VecZnxBigOps::vec_znx_big_normalize].
128 fn vec_znx_big_normalize<R, A>(&self, basek: usize, res: &mut R, res_col: usize, a: &A, a_col: usize, scratch: &mut Scratch)
129 where
130 R: VecZnxToMut,
131 A: VecZnxBigToRef<FFT64>;
132
133 /// Applies the automorphism X^i -> X^ik on `a` and stores the result on `b`.
134 fn vec_znx_big_automorphism<R, A>(&self, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
135 where
136 R: VecZnxBigToMut<BACKEND>,
137 A: VecZnxBigToRef<BACKEND>;
138
139 /// Applies the automorphism X^i -> X^ik on `a` and stores the result on `a`.
140 fn vec_znx_big_automorphism_inplace<A>(&self, k: i64, a: &mut A, a_col: usize)
141 where
142 A: VecZnxBigToMut<BACKEND>;
143}
144
145pub trait VecZnxBigScratch {
146 /// Returns the minimum number of bytes to apply [VecZnxBigOps::vec_znx_big_normalize].
147 fn vec_znx_big_normalize_tmp_bytes(&self) -> usize;
148}
149
150impl<B: Backend> VecZnxBigAlloc<B> for Module<B> {
151 fn new_vec_znx_big(&self, cols: usize, size: usize) -> VecZnxBigOwned<B> {
152 VecZnxBig::new(self, cols, size)
153 }
154
155 fn new_vec_znx_big_from_bytes(&self, cols: usize, size: usize, bytes: Vec<u8>) -> VecZnxBigOwned<B> {
156 VecZnxBig::new_from_bytes(self, cols, size, bytes)
157 }
158
159 fn bytes_of_vec_znx_big(&self, cols: usize, size: usize) -> usize {
160 bytes_of_vec_znx_big(self, cols, size)
161 }
162}
163
164impl VecZnxBigOps<FFT64> for Module<FFT64> {
165 fn vec_znx_big_add<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
166 where
167 R: VecZnxBigToMut<FFT64>,
168 A: VecZnxBigToRef<FFT64>,
169 B: VecZnxBigToRef<FFT64>,
170 {
171 let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
172 let b: VecZnxBig<&[u8], FFT64> = b.to_ref();
173 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
174
175 #[cfg(debug_assertions)]
176 {
177 assert_eq!(a.n(), self.n());
178 assert_eq!(b.n(), self.n());
179 assert_eq!(res.n(), self.n());
180 assert_ne!(a.as_ptr(), b.as_ptr());
181 }
182 unsafe {
183 vec_znx::vec_znx_add(
184 self.ptr,
185 res.at_mut_ptr(res_col, 0),
186 res.size() as u64,
187 res.sl() as u64,
188 a.at_ptr(a_col, 0),
189 a.size() as u64,
190 a.sl() as u64,
191 b.at_ptr(b_col, 0),
192 b.size() as u64,
193 b.sl() as u64,
194 )
195 }
196 }
197
198 fn vec_znx_big_add_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
199 where
200 R: VecZnxBigToMut<FFT64>,
201 A: VecZnxBigToRef<FFT64>,
202 {
203 let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
204 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
205
206 #[cfg(debug_assertions)]
207 {
208 assert_eq!(a.n(), self.n());
209 assert_eq!(res.n(), self.n());
210 }
211 unsafe {
212 vec_znx::vec_znx_add(
213 self.ptr,
214 res.at_mut_ptr(res_col, 0),
215 res.size() as u64,
216 res.sl() as u64,
217 a.at_ptr(a_col, 0),
218 a.size() as u64,
219 a.sl() as u64,
220 res.at_ptr(res_col, 0),
221 res.size() as u64,
222 res.sl() as u64,
223 )
224 }
225 }
226
227 fn vec_znx_big_sub<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
228 where
229 R: VecZnxBigToMut<FFT64>,
230 A: VecZnxBigToRef<FFT64>,
231 B: VecZnxBigToRef<FFT64>,
232 {
233 let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
234 let b: VecZnxBig<&[u8], FFT64> = b.to_ref();
235 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
236
237 #[cfg(debug_assertions)]
238 {
239 assert_eq!(a.n(), self.n());
240 assert_eq!(b.n(), self.n());
241 assert_eq!(res.n(), self.n());
242 assert_ne!(a.as_ptr(), b.as_ptr());
243 }
244 unsafe {
245 vec_znx::vec_znx_sub(
246 self.ptr,
247 res.at_mut_ptr(res_col, 0),
248 res.size() as u64,
249 res.sl() as u64,
250 a.at_ptr(a_col, 0),
251 a.size() as u64,
252 a.sl() as u64,
253 b.at_ptr(b_col, 0),
254 b.size() as u64,
255 b.sl() as u64,
256 )
257 }
258 }
259
260 fn vec_znx_big_sub_ab_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
261 where
262 R: VecZnxBigToMut<FFT64>,
263 A: VecZnxBigToRef<FFT64>,
264 {
265 let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
266 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
267
268 #[cfg(debug_assertions)]
269 {
270 assert_eq!(a.n(), self.n());
271 assert_eq!(res.n(), self.n());
272 }
273 unsafe {
274 vec_znx::vec_znx_sub(
275 self.ptr,
276 res.at_mut_ptr(res_col, 0),
277 res.size() as u64,
278 res.sl() as u64,
279 res.at_ptr(res_col, 0),
280 res.size() as u64,
281 res.sl() as u64,
282 a.at_ptr(a_col, 0),
283 a.size() as u64,
284 a.sl() as u64,
285 )
286 }
287 }
288
289 fn vec_znx_big_sub_ba_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
290 where
291 R: VecZnxBigToMut<FFT64>,
292 A: VecZnxBigToRef<FFT64>,
293 {
294 let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
295 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
296
297 #[cfg(debug_assertions)]
298 {
299 assert_eq!(a.n(), self.n());
300 assert_eq!(res.n(), self.n());
301 }
302 unsafe {
303 vec_znx::vec_znx_sub(
304 self.ptr,
305 res.at_mut_ptr(res_col, 0),
306 res.size() as u64,
307 res.sl() as u64,
308 a.at_ptr(a_col, 0),
309 a.size() as u64,
310 a.sl() as u64,
311 res.at_ptr(res_col, 0),
312 res.size() as u64,
313 res.sl() as u64,
314 )
315 }
316 }
317
318 fn vec_znx_big_sub_small_b<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
319 where
320 R: VecZnxBigToMut<FFT64>,
321 A: VecZnxBigToRef<FFT64>,
322 B: VecZnxToRef,
323 {
324 let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
325 let b: VecZnx<&[u8]> = b.to_ref();
326 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
327
328 #[cfg(debug_assertions)]
329 {
330 assert_eq!(a.n(), self.n());
331 assert_eq!(b.n(), self.n());
332 assert_eq!(res.n(), self.n());
333 assert_ne!(a.as_ptr(), b.as_ptr());
334 }
335 unsafe {
336 vec_znx::vec_znx_sub(
337 self.ptr,
338 res.at_mut_ptr(res_col, 0),
339 res.size() as u64,
340 res.sl() as u64,
341 a.at_ptr(a_col, 0),
342 a.size() as u64,
343 a.sl() as u64,
344 b.at_ptr(b_col, 0),
345 b.size() as u64,
346 b.sl() as u64,
347 )
348 }
349 }
350
351 fn vec_znx_big_sub_small_b_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
352 where
353 R: VecZnxBigToMut<FFT64>,
354 A: VecZnxToRef,
355 {
356 let a: VecZnx<&[u8]> = a.to_ref();
357 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
358
359 #[cfg(debug_assertions)]
360 {
361 assert_eq!(a.n(), self.n());
362 assert_eq!(res.n(), self.n());
363 }
364 unsafe {
365 vec_znx::vec_znx_sub(
366 self.ptr,
367 res.at_mut_ptr(res_col, 0),
368 res.size() as u64,
369 res.sl() as u64,
370 a.at_ptr(a_col, 0),
371 a.size() as u64,
372 a.sl() as u64,
373 res.at_ptr(res_col, 0),
374 res.size() as u64,
375 res.sl() as u64,
376 )
377 }
378 }
379
380 fn vec_znx_big_sub_small_a<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
381 where
382 R: VecZnxBigToMut<FFT64>,
383 A: VecZnxToRef,
384 B: VecZnxBigToRef<FFT64>,
385 {
386 let a: VecZnx<&[u8]> = a.to_ref();
387 let b: VecZnxBig<&[u8], FFT64> = b.to_ref();
388 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
389
390 #[cfg(debug_assertions)]
391 {
392 assert_eq!(a.n(), self.n());
393 assert_eq!(b.n(), self.n());
394 assert_eq!(res.n(), self.n());
395 assert_ne!(a.as_ptr(), b.as_ptr());
396 }
397 unsafe {
398 vec_znx::vec_znx_sub(
399 self.ptr,
400 res.at_mut_ptr(res_col, 0),
401 res.size() as u64,
402 res.sl() as u64,
403 a.at_ptr(a_col, 0),
404 a.size() as u64,
405 a.sl() as u64,
406 b.at_ptr(b_col, 0),
407 b.size() as u64,
408 b.sl() as u64,
409 )
410 }
411 }
412
413 fn vec_znx_big_sub_small_a_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
414 where
415 R: VecZnxBigToMut<FFT64>,
416 A: VecZnxToRef,
417 {
418 let a: VecZnx<&[u8]> = a.to_ref();
419 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
420
421 #[cfg(debug_assertions)]
422 {
423 assert_eq!(a.n(), self.n());
424 assert_eq!(res.n(), self.n());
425 }
426 unsafe {
427 vec_znx::vec_znx_sub(
428 self.ptr,
429 res.at_mut_ptr(res_col, 0),
430 res.size() as u64,
431 res.sl() as u64,
432 res.at_ptr(res_col, 0),
433 res.size() as u64,
434 res.sl() as u64,
435 a.at_ptr(a_col, 0),
436 a.size() as u64,
437 a.sl() as u64,
438 )
439 }
440 }
441
442 fn vec_znx_big_add_small<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
443 where
444 R: VecZnxBigToMut<FFT64>,
445 A: VecZnxBigToRef<FFT64>,
446 B: VecZnxToRef,
447 {
448 let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
449 let b: VecZnx<&[u8]> = b.to_ref();
450 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
451
452 #[cfg(debug_assertions)]
453 {
454 assert_eq!(a.n(), self.n());
455 assert_eq!(b.n(), self.n());
456 assert_eq!(res.n(), self.n());
457 assert_ne!(a.as_ptr(), b.as_ptr());
458 }
459 unsafe {
460 vec_znx::vec_znx_add(
461 self.ptr,
462 res.at_mut_ptr(res_col, 0),
463 res.size() as u64,
464 res.sl() as u64,
465 a.at_ptr(a_col, 0),
466 a.size() as u64,
467 a.sl() as u64,
468 b.at_ptr(b_col, 0),
469 b.size() as u64,
470 b.sl() as u64,
471 )
472 }
473 }
474
475 fn vec_znx_big_add_small_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
476 where
477 R: VecZnxBigToMut<FFT64>,
478 A: VecZnxToRef,
479 {
480 let a: VecZnx<&[u8]> = a.to_ref();
481 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
482
483 #[cfg(debug_assertions)]
484 {
485 assert_eq!(a.n(), self.n());
486 assert_eq!(res.n(), self.n());
487 }
488 unsafe {
489 vec_znx::vec_znx_add(
490 self.ptr,
491 res.at_mut_ptr(res_col, 0),
492 res.size() as u64,
493 res.sl() as u64,
494 res.at_ptr(res_col, 0),
495 res.size() as u64,
496 res.sl() as u64,
497 a.at_ptr(a_col, 0),
498 a.size() as u64,
499 a.sl() as u64,
500 )
501 }
502 }
503
504 fn vec_znx_big_negate_inplace<A>(&self, a: &mut A, a_col: usize)
505 where
506 A: VecZnxBigToMut<FFT64>,
507 {
508 let mut a: VecZnxBig<&mut [u8], FFT64> = a.to_mut();
509 #[cfg(debug_assertions)]
510 {
511 assert_eq!(a.n(), self.n());
512 }
513 unsafe {
514 vec_znx::vec_znx_negate(
515 self.ptr,
516 a.at_mut_ptr(a_col, 0),
517 a.size() as u64,
518 a.sl() as u64,
519 a.at_ptr(a_col, 0),
520 a.size() as u64,
521 a.sl() as u64,
522 )
523 }
524 }
525
526 fn vec_znx_big_normalize<R, A>(&self, basek: usize, res: &mut R, res_col: usize, a: &A, a_col: usize, scratch: &mut Scratch)
527 where
528 R: VecZnxToMut,
529 A: VecZnxBigToRef<FFT64>,
530 {
531 let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
532 let mut res: VecZnx<&mut [u8]> = res.to_mut();
533
534 #[cfg(debug_assertions)]
535 {
536 assert_eq!(a.n(), self.n());
537 assert_eq!(res.n(), self.n());
538 //(Jay)Note: This is calling VezZnxOps::vec_znx_normalize_tmp_bytes and not VecZnxBigOps::vec_znx_big_normalize_tmp_bytes.
539 // In the FFT backend the tmp sizes are same but will be different in the NTT backend
540 // assert!(tmp_bytes.len() >= <Self as VecZnxOps<&mut [u8], & [u8]>>::vec_znx_normalize_tmp_bytes(&self));
541 // assert_alignement(tmp_bytes.as_ptr());
542 }
543
544 let (tmp_bytes, _) = scratch.tmp_slice(<Self as VecZnxBigScratch>::vec_znx_big_normalize_tmp_bytes(
545 &self,
546 ));
547 unsafe {
548 vec_znx::vec_znx_normalize_base2k(
549 self.ptr,
550 basek as u64,
551 res.at_mut_ptr(res_col, 0),
552 res.size() as u64,
553 res.sl() as u64,
554 a.at_ptr(a_col, 0),
555 a.size() as u64,
556 a.sl() as u64,
557 tmp_bytes.as_mut_ptr(),
558 );
559 }
560 }
561
562 fn vec_znx_big_automorphism<R, A>(&self, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
563 where
564 R: VecZnxBigToMut<FFT64>,
565 A: VecZnxBigToRef<FFT64>,
566 {
567 let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
568 let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
569
570 #[cfg(debug_assertions)]
571 {
572 assert_eq!(a.n(), self.n());
573 assert_eq!(res.n(), self.n());
574 }
575 unsafe {
576 vec_znx::vec_znx_automorphism(
577 self.ptr,
578 k,
579 res.at_mut_ptr(res_col, 0),
580 res.size() as u64,
581 res.sl() as u64,
582 a.at_ptr(a_col, 0),
583 a.size() as u64,
584 a.sl() as u64,
585 )
586 }
587 }
588
589 fn vec_znx_big_automorphism_inplace<A>(&self, k: i64, a: &mut A, a_col: usize)
590 where
591 A: VecZnxBigToMut<FFT64>,
592 {
593 let mut a: VecZnxBig<&mut [u8], FFT64> = a.to_mut();
594
595 #[cfg(debug_assertions)]
596 {
597 assert_eq!(a.n(), self.n());
598 }
599 unsafe {
600 vec_znx::vec_znx_automorphism(
601 self.ptr,
602 k,
603 a.at_mut_ptr(a_col, 0),
604 a.size() as u64,
605 a.sl() as u64,
606 a.at_ptr(a_col, 0),
607 a.size() as u64,
608 a.sl() as u64,
609 )
610 }
611 }
612}
613
614impl<B: Backend> VecZnxBigScratch for Module<B> {
615 fn vec_znx_big_normalize_tmp_bytes(&self) -> usize {
616 <Self as VecZnxScratch>::vec_znx_normalize_tmp_bytes(self)
617 }
618}