arnaucube
arnaucube/poulpyPublic Self-hosted repository
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}