poulpy/base2k/src/vec_znx_ops.rs
base2k/src/vec_znx_ops.rsRaw
1use crate::ffi::vec_znx;
2use crate::{
3 Backend, Module, ScalarZnxToRef, Scratch, VecZnx, VecZnxOwned, VecZnxToMut, VecZnxToRef, ZnxInfos, ZnxSliceSize, ZnxView,
4 ZnxViewMut, ZnxZero,
5};
6use itertools::izip;
7use std::cmp::min;
8
9pub trait VecZnxAlloc {
10 /// Allocates a new [VecZnx].
11 ///
12 /// # Arguments
13 ///
14 /// * `cols`: the number of polynomials.
15 /// * `size`: the number small polynomials per column.
16 fn new_vec_znx(&self, cols: usize, size: usize) -> VecZnxOwned;
17
18 /// Instantiates a new [VecZnx] from a slice of bytes.
19 /// The returned [VecZnx] takes ownership of the slice of bytes.
20 ///
21 /// # Arguments
22 ///
23 /// * `cols`: the number of polynomials.
24 /// * `size`: the number small polynomials per column.
25 ///
26 /// # Panic
27 /// Requires the slice of bytes to be equal to [VecZnxOps::bytes_of_vec_znx].
28 fn new_vec_znx_from_bytes(&self, cols: usize, size: usize, bytes: Vec<u8>) -> VecZnxOwned;
29
30 /// Returns the number of bytes necessary to allocate
31 /// a new [VecZnx] through [VecZnxOps::new_vec_znx_from_bytes]
32 /// or [VecZnxOps::new_vec_znx_from_bytes_borrow].
33 fn bytes_of_vec_znx(&self, cols: usize, size: usize) -> usize;
34}
35
36pub trait VecZnxOps {
37 /// Normalizes the selected column of `a` and stores the result into the selected column of `res`.
38 fn vec_znx_normalize<R, A>(&self, log_base2k: usize, res: &mut R, res_col: usize, a: &A, a_col: usize, scratch: &mut Scratch)
39 where
40 R: VecZnxToMut,
41 A: VecZnxToRef;
42
43 /// Normalizes the selected column of `a`.
44 fn vec_znx_normalize_inplace<A>(&self, log_base2k: usize, a: &mut A, a_col: usize, scratch: &mut Scratch)
45 where
46 A: VecZnxToMut;
47
48 /// Adds the selected column of `a` to the selected column of `b` and writes the result on the selected column of `res`.
49 fn vec_znx_add<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
50 where
51 R: VecZnxToMut,
52 A: VecZnxToRef,
53 B: VecZnxToRef;
54
55 /// Adds the selected column of `a` to the selected column of `res` and writes the result on the selected column of `res`.
56 fn vec_znx_add_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
57 where
58 R: VecZnxToMut,
59 A: VecZnxToRef;
60
61 /// Adds the selected column of `a` on the selected column and limb of `res`.
62 fn vec_znx_add_scalar_inplace<R, A>(&self, res: &mut R, res_col: usize, res_limb: usize, a: &A, b_col: usize)
63 where
64 R: VecZnxToMut,
65 A: ScalarZnxToRef;
66
67 /// Subtracts the selected column of `b` from the selected column of `a` and writes the result on the selected column of `res`.
68 fn vec_znx_sub<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
69 where
70 R: VecZnxToMut,
71 A: VecZnxToRef,
72 B: VecZnxToRef;
73
74 /// Subtracts the selected column of `a` from the selected column of `res` inplace.
75 ///
76 /// res[res_col] -= a[a_col]
77 fn vec_znx_sub_ab_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
78 where
79 R: VecZnxToMut,
80 A: VecZnxToRef;
81
82 /// Subtracts the selected column of `res` from the selected column of `a` and inplace mutates `res`
83 ///
84 /// res[res_col] = a[a_col] - res[res_col]
85 fn vec_znx_sub_ba_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
86 where
87 R: VecZnxToMut,
88 A: VecZnxToRef;
89
90 /// Subtracts the selected column of `a` on the selected column and limb of `res`.
91 fn vec_znx_sub_scalar_inplace<R, A>(&self, res: &mut R, res_col: usize, res_limb: usize, a: &A, b_col: usize)
92 where
93 R: VecZnxToMut,
94 A: ScalarZnxToRef;
95
96 // Negates the selected column of `a` and stores the result in `res_col` of `res`.
97 fn vec_znx_negate<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
98 where
99 R: VecZnxToMut,
100 A: VecZnxToRef;
101
102 /// Negates the selected column of `a`.
103 fn vec_znx_negate_inplace<A>(&self, a: &mut A, a_col: usize)
104 where
105 A: VecZnxToMut;
106
107 /// Multiplies the selected column of `a` by X^k and stores the result in `res_col` of `res`.
108 fn vec_znx_rotate<R, A>(&self, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
109 where
110 R: VecZnxToMut,
111 A: VecZnxToRef;
112
113 /// Multiplies the selected column of `a` by X^k.
114 fn vec_znx_rotate_inplace<A>(&self, k: i64, a: &mut A, a_col: usize)
115 where
116 A: VecZnxToMut;
117
118 /// Applies the automorphism X^i -> X^ik on the selected column of `a` and stores the result in `res_col` column of `res`.
119 fn vec_znx_automorphism<R, A>(&self, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
120 where
121 R: VecZnxToMut,
122 A: VecZnxToRef;
123
124 /// Applies the automorphism X^i -> X^ik on the selected column of `a`.
125 fn vec_znx_automorphism_inplace<A>(&self, k: i64, a: &mut A, a_col: usize)
126 where
127 A: VecZnxToMut;
128
129 /// Splits the selected columns of `b` into subrings and copies them them into the selected column of `res`.
130 ///
131 /// # Panics
132 ///
133 /// This method requires that all [VecZnx] of b have the same ring degree
134 /// and that b.n() * b.len() <= a.n()
135 fn vec_znx_split<R, A>(&self, res: &mut Vec<R>, res_col: usize, a: &A, a_col: usize, scratch: &mut Scratch)
136 where
137 R: VecZnxToMut,
138 A: VecZnxToRef;
139
140 /// Merges the subrings of the selected column of `a` into the selected column of `res`.
141 ///
142 /// # Panics
143 ///
144 /// This method requires that all [VecZnx] of a have the same ring degree
145 /// and that a.n() * a.len() <= b.n()
146 fn vec_znx_merge<R, A>(&self, res: &mut R, res_col: usize, a: Vec<A>, a_col: usize)
147 where
148 R: VecZnxToMut,
149 A: VecZnxToRef;
150
151 fn switch_degree<R, A>(&self, r: &mut R, col_b: usize, a: &A, col_a: usize)
152 where
153 R: VecZnxToMut,
154 A: VecZnxToRef;
155}
156
157pub trait VecZnxScratch {
158 /// Returns the minimum number of bytes necessary for normalization.
159 fn vec_znx_normalize_tmp_bytes(&self) -> usize;
160}
161
162impl<B: Backend> VecZnxAlloc for Module<B> {
163 fn new_vec_znx(&self, cols: usize, size: usize) -> VecZnxOwned {
164 VecZnxOwned::new::<i64>(self.n(), cols, size)
165 }
166
167 fn bytes_of_vec_znx(&self, cols: usize, size: usize) -> usize {
168 VecZnxOwned::bytes_of::<i64>(self.n(), cols, size)
169 }
170
171 fn new_vec_znx_from_bytes(&self, cols: usize, size: usize, bytes: Vec<u8>) -> VecZnxOwned {
172 VecZnxOwned::new_from_bytes::<i64>(self.n(), cols, size, bytes)
173 }
174}
175
176impl<BACKEND: Backend> VecZnxOps for Module<BACKEND> {
177 fn vec_znx_normalize<R, A>(&self, log_base2k: usize, res: &mut R, res_col: usize, a: &A, a_col: usize, scratch: &mut Scratch)
178 where
179 R: VecZnxToMut,
180 A: VecZnxToRef,
181 {
182 let a: VecZnx<&[u8]> = a.to_ref();
183 let mut res: VecZnx<&mut [u8]> = res.to_mut();
184
185 #[cfg(debug_assertions)]
186 {
187 assert_eq!(a.n(), self.n());
188 assert_eq!(res.n(), self.n());
189 }
190
191 let (tmp_bytes, _) = scratch.tmp_slice(self.vec_znx_normalize_tmp_bytes());
192
193 unsafe {
194 vec_znx::vec_znx_normalize_base2k(
195 self.ptr,
196 log_base2k as u64,
197 res.at_mut_ptr(res_col, 0),
198 res.size() as u64,
199 res.sl() as u64,
200 a.at_ptr(a_col, 0),
201 a.size() as u64,
202 a.sl() as u64,
203 tmp_bytes.as_mut_ptr(),
204 );
205 }
206 }
207
208 fn vec_znx_normalize_inplace<A>(&self, log_base2k: usize, a: &mut A, a_col: usize, scratch: &mut Scratch)
209 where
210 A: VecZnxToMut,
211 {
212 let mut a: VecZnx<&mut [u8]> = a.to_mut();
213
214 #[cfg(debug_assertions)]
215 {
216 assert_eq!(a.n(), self.n());
217 }
218
219 let (tmp_bytes, _) = scratch.tmp_slice(self.vec_znx_normalize_tmp_bytes());
220
221 unsafe {
222 vec_znx::vec_znx_normalize_base2k(
223 self.ptr,
224 log_base2k as u64,
225 a.at_mut_ptr(a_col, 0),
226 a.size() as u64,
227 a.sl() as u64,
228 a.at_ptr(a_col, 0),
229 a.size() as u64,
230 a.sl() as u64,
231 tmp_bytes.as_mut_ptr(),
232 );
233 }
234 }
235
236 fn vec_znx_add<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
237 where
238 R: VecZnxToMut,
239 A: VecZnxToRef,
240 B: VecZnxToRef,
241 {
242 let a: VecZnx<&[u8]> = a.to_ref();
243 let b: VecZnx<&[u8]> = b.to_ref();
244 let mut res: VecZnx<&mut [u8]> = res.to_mut();
245
246 #[cfg(debug_assertions)]
247 {
248 assert_eq!(a.n(), self.n());
249 assert_eq!(b.n(), self.n());
250 assert_eq!(res.n(), self.n());
251 assert_ne!(a.as_ptr(), b.as_ptr());
252 }
253 unsafe {
254 vec_znx::vec_znx_add(
255 self.ptr,
256 res.at_mut_ptr(res_col, 0),
257 res.size() as u64,
258 res.sl() as u64,
259 a.at_ptr(a_col, 0),
260 a.size() as u64,
261 a.sl() as u64,
262 b.at_ptr(b_col, 0),
263 b.size() as u64,
264 b.sl() as u64,
265 )
266 }
267 }
268
269 fn vec_znx_add_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
270 where
271 R: VecZnxToMut,
272 A: VecZnxToRef,
273 {
274 let a: VecZnx<&[u8]> = a.to_ref();
275 let mut res: VecZnx<&mut [u8]> = res.to_mut();
276
277 #[cfg(debug_assertions)]
278 {
279 assert_eq!(a.n(), self.n());
280 assert_eq!(res.n(), self.n());
281 }
282 unsafe {
283 vec_znx::vec_znx_add(
284 self.ptr,
285 res.at_mut_ptr(res_col, 0),
286 res.size() as u64,
287 res.sl() as u64,
288 a.at_ptr(a_col, 0),
289 a.size() as u64,
290 a.sl() as u64,
291 res.at_ptr(res_col, 0),
292 res.size() as u64,
293 res.sl() as u64,
294 )
295 }
296 }
297
298 fn vec_znx_add_scalar_inplace<R, A>(&self, res: &mut R, res_col: usize, res_limb: usize, a: &A, a_col: usize)
299 where
300 R: VecZnxToMut,
301 A: ScalarZnxToRef,
302 {
303 let mut res: VecZnx<&mut [u8]> = res.to_mut();
304 let a: crate::ScalarZnx<&[u8]> = a.to_ref();
305
306 #[cfg(debug_assertions)]
307 {
308 assert_eq!(a.n(), self.n());
309 assert_eq!(res.n(), self.n());
310 }
311
312 unsafe {
313 vec_znx::vec_znx_add(
314 self.ptr,
315 res.at_mut_ptr(res_col, res_limb),
316 1 as u64,
317 res.sl() as u64,
318 a.at_ptr(a_col, 0),
319 a.size() as u64,
320 a.sl() as u64,
321 res.at_ptr(res_col, res_limb),
322 1 as u64,
323 res.sl() as u64,
324 )
325 }
326 }
327
328 fn vec_znx_sub<R, A, B>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &B, b_col: usize)
329 where
330 R: VecZnxToMut,
331 A: VecZnxToRef,
332 B: VecZnxToRef,
333 {
334 let a: VecZnx<&[u8]> = a.to_ref();
335 let b: VecZnx<&[u8]> = b.to_ref();
336 let mut res: VecZnx<&mut [u8]> = res.to_mut();
337
338 #[cfg(debug_assertions)]
339 {
340 assert_eq!(a.n(), self.n());
341 assert_eq!(b.n(), self.n());
342 assert_eq!(res.n(), self.n());
343 assert_ne!(a.as_ptr(), b.as_ptr());
344 }
345 unsafe {
346 vec_znx::vec_znx_sub(
347 self.ptr,
348 res.at_mut_ptr(res_col, 0),
349 res.size() as u64,
350 res.sl() as u64,
351 a.at_ptr(a_col, 0),
352 a.size() as u64,
353 a.sl() as u64,
354 b.at_ptr(b_col, 0),
355 b.size() as u64,
356 b.sl() as u64,
357 )
358 }
359 }
360
361 fn vec_znx_sub_scalar_inplace<R, A>(&self, res: &mut R, res_col: usize, res_limb: usize, a: &A, a_col: usize)
362 where
363 R: VecZnxToMut,
364 A: ScalarZnxToRef,
365 {
366 let mut res: VecZnx<&mut [u8]> = res.to_mut();
367 let a: crate::ScalarZnx<&[u8]> = a.to_ref();
368
369 #[cfg(debug_assertions)]
370 {
371 assert_eq!(a.n(), self.n());
372 assert_eq!(res.n(), self.n());
373 }
374
375 unsafe {
376 vec_znx::vec_znx_sub(
377 self.ptr,
378 res.at_mut_ptr(res_col, res_limb),
379 1 as u64,
380 res.sl() as u64,
381 a.at_ptr(a_col, 0),
382 a.size() as u64,
383 a.sl() as u64,
384 res.at_ptr(res_col, res_limb),
385 1 as u64,
386 res.sl() as u64,
387 )
388 }
389 }
390
391 fn vec_znx_sub_ab_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
392 where
393 R: VecZnxToMut,
394 A: VecZnxToRef,
395 {
396 let a: VecZnx<&[u8]> = a.to_ref();
397 let mut res: VecZnx<&mut [u8]> = res.to_mut();
398 #[cfg(debug_assertions)]
399 {
400 assert_eq!(a.n(), self.n());
401 assert_eq!(res.n(), self.n());
402 }
403 unsafe {
404 vec_znx::vec_znx_sub(
405 self.ptr,
406 res.at_mut_ptr(res_col, 0),
407 res.size() as u64,
408 res.sl() as u64,
409 res.at_ptr(res_col, 0),
410 res.size() as u64,
411 res.sl() as u64,
412 a.at_ptr(a_col, 0),
413 a.size() as u64,
414 a.sl() as u64,
415 )
416 }
417 }
418
419 fn vec_znx_sub_ba_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
420 where
421 R: VecZnxToMut,
422 A: VecZnxToRef,
423 {
424 let a: VecZnx<&[u8]> = a.to_ref();
425 let mut res: VecZnx<&mut [u8]> = res.to_mut();
426 #[cfg(debug_assertions)]
427 {
428 assert_eq!(a.n(), self.n());
429 assert_eq!(res.n(), self.n());
430 }
431 unsafe {
432 vec_znx::vec_znx_sub(
433 self.ptr,
434 res.at_mut_ptr(res_col, 0),
435 res.size() as u64,
436 res.sl() as u64,
437 a.at_ptr(a_col, 0),
438 a.size() as u64,
439 a.sl() as u64,
440 res.at_ptr(res_col, 0),
441 res.size() as u64,
442 res.sl() as u64,
443 )
444 }
445 }
446
447 fn vec_znx_negate<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
448 where
449 R: VecZnxToMut,
450 A: VecZnxToRef,
451 {
452 let a: VecZnx<&[u8]> = a.to_ref();
453 let mut res: VecZnx<&mut [u8]> = res.to_mut();
454 #[cfg(debug_assertions)]
455 {
456 assert_eq!(a.n(), self.n());
457 assert_eq!(res.n(), self.n());
458 }
459 unsafe {
460 vec_znx::vec_znx_negate(
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 )
469 }
470 }
471
472 fn vec_znx_negate_inplace<A>(&self, a: &mut A, a_col: usize)
473 where
474 A: VecZnxToMut,
475 {
476 let mut a: VecZnx<&mut [u8]> = a.to_mut();
477 #[cfg(debug_assertions)]
478 {
479 assert_eq!(a.n(), self.n());
480 }
481 unsafe {
482 vec_znx::vec_znx_negate(
483 self.ptr,
484 a.at_mut_ptr(a_col, 0),
485 a.size() as u64,
486 a.sl() as u64,
487 a.at_ptr(a_col, 0),
488 a.size() as u64,
489 a.sl() as u64,
490 )
491 }
492 }
493
494 fn vec_znx_rotate<R, A>(&self, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
495 where
496 R: VecZnxToMut,
497 A: VecZnxToRef,
498 {
499 let a: VecZnx<&[u8]> = a.to_ref();
500 let mut res: VecZnx<&mut [u8]> = res.to_mut();
501 #[cfg(debug_assertions)]
502 {
503 assert_eq!(a.n(), self.n());
504 assert_eq!(res.n(), self.n());
505 }
506 unsafe {
507 vec_znx::vec_znx_rotate(
508 self.ptr,
509 k,
510 res.at_mut_ptr(res_col, 0),
511 res.size() as u64,
512 res.sl() as u64,
513 a.at_ptr(a_col, 0),
514 a.size() as u64,
515 a.sl() as u64,
516 )
517 }
518 }
519
520 fn vec_znx_rotate_inplace<A>(&self, k: i64, a: &mut A, a_col: usize)
521 where
522 A: VecZnxToMut,
523 {
524 let mut a: VecZnx<&mut [u8]> = a.to_mut();
525 #[cfg(debug_assertions)]
526 {
527 assert_eq!(a.n(), self.n());
528 }
529 unsafe {
530 vec_znx::vec_znx_rotate(
531 self.ptr,
532 k,
533 a.at_mut_ptr(a_col, 0),
534 a.size() as u64,
535 a.sl() as u64,
536 a.at_ptr(a_col, 0),
537 a.size() as u64,
538 a.sl() as u64,
539 )
540 }
541 }
542
543 fn vec_znx_automorphism<R, A>(&self, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
544 where
545 R: VecZnxToMut,
546 A: VecZnxToRef,
547 {
548 let a: VecZnx<&[u8]> = a.to_ref();
549 let mut res: VecZnx<&mut [u8]> = res.to_mut();
550 #[cfg(debug_assertions)]
551 {
552 assert_eq!(a.n(), self.n());
553 assert_eq!(res.n(), self.n());
554 }
555 unsafe {
556 vec_znx::vec_znx_automorphism(
557 self.ptr,
558 k,
559 res.at_mut_ptr(res_col, 0),
560 res.size() as u64,
561 res.sl() as u64,
562 a.at_ptr(a_col, 0),
563 a.size() as u64,
564 a.sl() as u64,
565 )
566 }
567 }
568
569 fn vec_znx_automorphism_inplace<A>(&self, k: i64, a: &mut A, a_col: usize)
570 where
571 A: VecZnxToMut,
572 {
573 let mut a: VecZnx<&mut [u8]> = a.to_mut();
574 #[cfg(debug_assertions)]
575 {
576 assert_eq!(a.n(), self.n());
577 assert!(
578 k & 1 != 0,
579 "invalid galois element: must be odd but is {}",
580 k
581 );
582 }
583 unsafe {
584 vec_znx::vec_znx_automorphism(
585 self.ptr,
586 k,
587 a.at_mut_ptr(a_col, 0),
588 a.size() as u64,
589 a.sl() as u64,
590 a.at_ptr(a_col, 0),
591 a.size() as u64,
592 a.sl() as u64,
593 )
594 }
595 }
596
597 fn vec_znx_split<R, A>(&self, res: &mut Vec<R>, res_col: usize, a: &A, a_col: usize, scratch: &mut Scratch)
598 where
599 R: VecZnxToMut,
600 A: VecZnxToRef,
601 {
602 let a: VecZnx<&[u8]> = a.to_ref();
603
604 let (n_in, n_out) = (a.n(), res[0].to_mut().n());
605
606 let (mut buf, _) = scratch.tmp_vec_znx(self, 1, a.size());
607
608 debug_assert!(
609 n_out < n_in,
610 "invalid a: output ring degree should be smaller"
611 );
612 res[1..].iter_mut().for_each(|bi| {
613 debug_assert_eq!(
614 bi.to_mut().n(),
615 n_out,
616 "invalid input a: all VecZnx must have the same degree"
617 )
618 });
619
620 res.iter_mut().enumerate().for_each(|(i, bi)| {
621 if i == 0 {
622 self.switch_degree(bi, res_col, &a, a_col);
623 self.vec_znx_rotate(-1, &mut buf, 0, &a, a_col);
624 } else {
625 self.switch_degree(bi, res_col, &mut buf, a_col);
626 self.vec_znx_rotate_inplace(-1, &mut buf, a_col);
627 }
628 })
629 }
630
631 fn vec_znx_merge<R, A>(&self, res: &mut R, res_col: usize, a: Vec<A>, a_col: usize)
632 where
633 R: VecZnxToMut,
634 A: VecZnxToRef,
635 {
636 let mut res: VecZnx<&mut [u8]> = res.to_mut();
637
638 let (n_in, n_out) = (res.n(), a[0].to_ref().n());
639
640 debug_assert!(
641 n_out < n_in,
642 "invalid a: output ring degree should be smaller"
643 );
644 a[1..].iter().for_each(|ai| {
645 debug_assert_eq!(
646 ai.to_ref().n(),
647 n_out,
648 "invalid input a: all VecZnx must have the same degree"
649 )
650 });
651
652 a.iter().enumerate().for_each(|(_, ai)| {
653 self.switch_degree(&mut res, res_col, ai, a_col);
654 self.vec_znx_rotate_inplace(-1, &mut res, res_col);
655 });
656
657 self.vec_znx_rotate_inplace(a.len() as i64, &mut res, res_col);
658 }
659
660 fn switch_degree<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
661 where
662 R: VecZnxToMut,
663 A: VecZnxToRef,
664 {
665 let a: VecZnx<&[u8]> = a.to_ref();
666 let mut res: VecZnx<&mut [u8]> = res.to_mut();
667
668 let (n_in, n_out) = (a.n(), res.n());
669 let (gap_in, gap_out): (usize, usize);
670
671 if n_in > n_out {
672 (gap_in, gap_out) = (n_in / n_out, 1)
673 } else {
674 (gap_in, gap_out) = (1, n_out / n_in);
675 res.zero();
676 }
677
678 let size: usize = min(a.size(), res.size());
679
680 (0..size).for_each(|i| {
681 izip!(
682 a.at(a_col, i).iter().step_by(gap_in),
683 res.at_mut(res_col, i).iter_mut().step_by(gap_out)
684 )
685 .for_each(|(x_in, x_out)| *x_out = *x_in);
686 });
687 }
688}
689
690impl<B: Backend> VecZnxScratch for Module<B> {
691 fn vec_znx_normalize_tmp_bytes(&self) -> usize {
692 unsafe { vec_znx::vec_znx_normalize_base2k_tmp_bytes(self.ptr) as usize }
693 }
694}