arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/base2k/src/vec_znx_big_ops.rs
base2k/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    /// * `log_base2k`: normalization basis.
127    /// * `tmp_bytes`: scratch space of size at least [VecZnxBigOps::vec_znx_big_normalize].
128    fn vec_znx_big_normalize<R, A>(
129        &self,
130        log_base2k: usize,
131        res: &mut R,
132        res_col: usize,
133        a: &A,
134        a_col: usize,
135        scratch: &mut Scratch,
136    ) where
137        R: VecZnxToMut,
138        A: VecZnxBigToRef<BACKEND>;
139
140    /// Applies the automorphism X^i -> X^ik on `a` and stores the result on `b`.
141    fn vec_znx_big_automorphism<R, A>(&self, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
142    where
143        R: VecZnxBigToMut<BACKEND>,
144        A: VecZnxBigToRef<BACKEND>;
145
146    /// Applies the automorphism X^i -> X^ik on `a` and stores the result on `a`.
147    fn vec_znx_big_automorphism_inplace<A>(&self, k: i64, a: &mut A, a_col: usize)
148    where
149        A: VecZnxBigToMut<BACKEND>;
150
151}
152
153pub trait VecZnxBigScratch {
154    /// Returns the minimum number of bytes to apply [VecZnxBigOps::vec_znx_big_normalize].
155    fn vec_znx_big_normalize_tmp_bytes(&self) -> usize;
156}
157
158impl<B: Backend> VecZnxBigAlloc<B> for Module<B> {
159    fn new_vec_znx_big(&self, cols: usize, size: usize) -> VecZnxBigOwned<B> {
160        VecZnxBig::new(self, cols, size)
161    }
162
163    fn new_vec_znx_big_from_bytes(&self, cols: usize, size: usize, bytes: Vec<u8>) -> VecZnxBigOwned<B> {
164        VecZnxBig::new_from_bytes(self, cols, size, bytes)
165    }
166
167    fn bytes_of_vec_znx_big(&self, cols: usize, size: usize) -> usize {
168        bytes_of_vec_znx_big(self, cols, size)
169    }
170}
171
172impl VecZnxBigOps<FFT64> for Module<FFT64> {
173
174    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)
175    where
176        R: VecZnxBigToMut<FFT64>,
177        A: VecZnxBigToRef<FFT64>,
178        B: VecZnxBigToRef<FFT64>,
179    {
180        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
181        let b: VecZnxBig<&[u8], FFT64> = b.to_ref();
182        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
183
184        #[cfg(debug_assertions)]
185        {
186            assert_eq!(a.n(), self.n());
187            assert_eq!(b.n(), self.n());
188            assert_eq!(res.n(), self.n());
189            assert_ne!(a.as_ptr(), b.as_ptr());
190        }
191        unsafe {
192            vec_znx::vec_znx_add(
193                self.ptr,
194                res.at_mut_ptr(res_col, 0),
195                res.size() as u64,
196                res.sl() as u64,
197                a.at_ptr(a_col, 0),
198                a.size() as u64,
199                a.sl() as u64,
200                b.at_ptr(b_col, 0),
201                b.size() as u64,
202                b.sl() as u64,
203            )
204        }
205    }
206
207    fn vec_znx_big_add_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
208    where
209        R: VecZnxBigToMut<FFT64>,
210        A: VecZnxBigToRef<FFT64>,
211    {
212        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
213        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
214
215        #[cfg(debug_assertions)]
216        {
217            assert_eq!(a.n(), self.n());
218            assert_eq!(res.n(), self.n());
219        }
220        unsafe {
221            vec_znx::vec_znx_add(
222                self.ptr,
223                res.at_mut_ptr(res_col, 0),
224                res.size() as u64,
225                res.sl() as u64,
226                a.at_ptr(a_col, 0),
227                a.size() as u64,
228                a.sl() as u64,
229                res.at_ptr(res_col, 0),
230                res.size() as u64,
231                res.sl() as u64,
232            )
233        }
234    }
235
236    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)
237    where
238        R: VecZnxBigToMut<FFT64>,
239        A: VecZnxBigToRef<FFT64>,
240        B: VecZnxBigToRef<FFT64>,
241    {
242        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
243        let b: VecZnxBig<&[u8], FFT64> = b.to_ref();
244        let mut res: VecZnxBig<&mut [u8], FFT64> = 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_sub(
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_big_sub_ab_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
270    where
271        R: VecZnxBigToMut<FFT64>,
272        A: VecZnxBigToRef<FFT64>,
273    {
274        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
275        let mut res: VecZnxBig<&mut [u8], FFT64> = 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_sub(
284                self.ptr,
285                res.at_mut_ptr(res_col, 0),
286                res.size() as u64,
287                res.sl() as u64,
288                res.at_ptr(res_col, 0),
289                res.size() as u64,
290                res.sl() as u64,
291                a.at_ptr(a_col, 0),
292                a.size() as u64,
293                a.sl() as u64,
294            )
295        }
296    }
297
298    fn vec_znx_big_sub_ba_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
299    where
300        R: VecZnxBigToMut<FFT64>,
301        A: VecZnxBigToRef<FFT64>,
302    {
303        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
304        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
305
306        #[cfg(debug_assertions)]
307        {
308            assert_eq!(a.n(), self.n());
309            assert_eq!(res.n(), self.n());
310        }
311        unsafe {
312            vec_znx::vec_znx_sub(
313                self.ptr,
314                res.at_mut_ptr(res_col, 0),
315                res.size() as u64,
316                res.sl() as u64,
317                a.at_ptr(a_col, 0),
318                a.size() as u64,
319                a.sl() as u64,
320                res.at_ptr(res_col, 0),
321                res.size() as u64,
322                res.sl() as u64,
323            )
324        }
325    }
326
327    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)
328    where
329        R: VecZnxBigToMut<FFT64>,
330        A: VecZnxBigToRef<FFT64>,
331        B: VecZnxToRef,
332    {
333        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
334        let b: VecZnx<&[u8]> = b.to_ref();
335        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
336
337        #[cfg(debug_assertions)]
338        {
339            assert_eq!(a.n(), self.n());
340            assert_eq!(b.n(), self.n());
341            assert_eq!(res.n(), self.n());
342            assert_ne!(a.as_ptr(), b.as_ptr());
343        }
344        unsafe {
345            vec_znx::vec_znx_sub(
346                self.ptr,
347                res.at_mut_ptr(res_col, 0),
348                res.size() as u64,
349                res.sl() as u64,
350                a.at_ptr(a_col, 0),
351                a.size() as u64,
352                a.sl() as u64,
353                b.at_ptr(b_col, 0),
354                b.size() as u64,
355                b.sl() as u64,
356            )
357        }
358    }
359
360    fn vec_znx_big_sub_small_b_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
361    where
362        R: VecZnxBigToMut<FFT64>,
363        A: VecZnxToRef,
364    {
365        let a: VecZnx<&[u8]> = a.to_ref();
366        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
367
368        #[cfg(debug_assertions)]
369        {
370            assert_eq!(a.n(), self.n());
371            assert_eq!(res.n(), self.n());
372        }
373        unsafe {
374            vec_znx::vec_znx_sub(
375                self.ptr,
376                res.at_mut_ptr(res_col, 0),
377                res.size() as u64,
378                res.sl() as u64,
379                a.at_ptr(a_col, 0),
380                a.size() as u64,
381                a.sl() as u64,
382                res.at_ptr(res_col, 0),
383                res.size() as u64,
384                res.sl() as u64,
385            )
386        }
387    }
388
389    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)
390    where
391        R: VecZnxBigToMut<FFT64>,
392        A: VecZnxToRef,
393        B: VecZnxBigToRef<FFT64>,
394    {
395        let a: VecZnx<&[u8]> = a.to_ref();
396        let b: VecZnxBig<&[u8], FFT64> = b.to_ref();
397        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
398
399        #[cfg(debug_assertions)]
400        {
401            assert_eq!(a.n(), self.n());
402            assert_eq!(b.n(), self.n());
403            assert_eq!(res.n(), self.n());
404            assert_ne!(a.as_ptr(), b.as_ptr());
405        }
406        unsafe {
407            vec_znx::vec_znx_sub(
408                self.ptr,
409                res.at_mut_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                b.at_ptr(b_col, 0),
416                b.size() as u64,
417                b.sl() as u64,
418            )
419        }
420    }
421
422    fn vec_znx_big_sub_small_a_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
423    where
424        R: VecZnxBigToMut<FFT64>,
425        A: VecZnxToRef,
426    {
427        let a: VecZnx<&[u8]> = a.to_ref();
428        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
429
430        #[cfg(debug_assertions)]
431        {
432            assert_eq!(a.n(), self.n());
433            assert_eq!(res.n(), self.n());
434        }
435        unsafe {
436            vec_znx::vec_znx_sub(
437                self.ptr,
438                res.at_mut_ptr(res_col, 0),
439                res.size() as u64,
440                res.sl() as u64,
441                res.at_ptr(res_col, 0),
442                res.size() as u64,
443                res.sl() as u64,
444                a.at_ptr(a_col, 0),
445                a.size() as u64,
446                a.sl() as u64,
447            )
448        }
449    }
450
451    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)
452    where
453        R: VecZnxBigToMut<FFT64>,
454        A: VecZnxBigToRef<FFT64>,
455        B: VecZnxToRef,
456    {
457        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
458        let b: VecZnx<&[u8]> = b.to_ref();
459        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
460
461        #[cfg(debug_assertions)]
462        {
463            assert_eq!(a.n(), self.n());
464            assert_eq!(b.n(), self.n());
465            assert_eq!(res.n(), self.n());
466            assert_ne!(a.as_ptr(), b.as_ptr());
467        }
468        unsafe {
469            vec_znx::vec_znx_add(
470                self.ptr,
471                res.at_mut_ptr(res_col, 0),
472                res.size() as u64,
473                res.sl() as u64,
474                a.at_ptr(a_col, 0),
475                a.size() as u64,
476                a.sl() as u64,
477                b.at_ptr(b_col, 0),
478                b.size() as u64,
479                b.sl() as u64,
480            )
481        }
482    }
483
484    fn vec_znx_big_add_small_inplace<R, A>(&self, res: &mut R, res_col: usize, a: &A, a_col: usize)
485    where
486        R: VecZnxBigToMut<FFT64>,
487        A: VecZnxToRef,
488    {
489        let a: VecZnx<&[u8]> = a.to_ref();
490        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
491
492        #[cfg(debug_assertions)]
493        {
494            assert_eq!(a.n(), self.n());
495            assert_eq!(res.n(), self.n());
496        }
497        unsafe {
498            vec_znx::vec_znx_add(
499                self.ptr,
500                res.at_mut_ptr(res_col, 0),
501                res.size() as u64,
502                res.sl() as u64,
503                res.at_ptr(res_col, 0),
504                res.size() as u64,
505                res.sl() as u64,
506                a.at_ptr(a_col, 0),
507                a.size() as u64,
508                a.sl() as u64,
509            )
510        }
511    }
512
513    fn vec_znx_big_negate_inplace<A>(&self, a: &mut A, res_col: usize)
514    where
515        A: VecZnxBigToMut<FFT64>,
516    {
517        let mut a: VecZnxBig<&mut [u8], FFT64> = a.to_mut();
518        #[cfg(debug_assertions)]
519        {
520            assert_eq!(a.n(), self.n());
521        }
522        unsafe {
523            vec_znx::vec_znx_negate(
524                self.ptr,
525                a.at_mut_ptr(res_col, 0),
526                a.size() as u64,
527                a.sl() as u64,
528                a.at_ptr(res_col, 0),
529                a.size() as u64,
530                a.sl() as u64,
531            )
532        }
533    }
534
535    fn vec_znx_big_normalize<R, A>(
536        &self,
537        log_base2k: usize,
538        res: &mut R,
539        res_col: usize,
540        a: &A,
541        a_col: usize,
542        scratch: &mut Scratch,
543    ) where
544        R: VecZnxToMut,
545        A: VecZnxBigToRef<FFT64>,
546    {
547        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
548        let mut res: VecZnx<&mut [u8]> = res.to_mut();
549
550        #[cfg(debug_assertions)]
551        {
552            assert_eq!(a.n(), self.n());
553            assert_eq!(res.n(), self.n());
554            //(Jay)Note: This is calling VezZnxOps::vec_znx_normalize_tmp_bytes and not VecZnxBigOps::vec_znx_big_normalize_tmp_bytes.
555            // In the FFT backend the tmp sizes are same but will be different in the NTT backend
556            // assert!(tmp_bytes.len() >= <Self as VecZnxOps<&mut [u8], & [u8]>>::vec_znx_normalize_tmp_bytes(&self));
557            // assert_alignement(tmp_bytes.as_ptr());
558        }
559
560        let (tmp_bytes, _) = scratch.tmp_slice(<Self as VecZnxBigScratch>::vec_znx_big_normalize_tmp_bytes(
561            &self,
562        ));
563        unsafe {
564            vec_znx::vec_znx_normalize_base2k(
565                self.ptr,
566                log_base2k as u64,
567                res.at_mut_ptr(res_col, 0),
568                res.size() as u64,
569                res.sl() as u64,
570                a.at_ptr(a_col, 0),
571                a.size() as u64,
572                a.sl() as u64,
573                tmp_bytes.as_mut_ptr(),
574            );
575        }
576    }
577
578    fn vec_znx_big_automorphism<R, A>(&self, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
579    where
580        R: VecZnxBigToMut<FFT64>,
581        A: VecZnxBigToRef<FFT64>,
582    {
583        let a: VecZnxBig<&[u8], FFT64> = a.to_ref();
584        let mut res: VecZnxBig<&mut [u8], FFT64> = res.to_mut();
585
586        #[cfg(debug_assertions)]
587        {
588            assert_eq!(a.n(), self.n());
589            assert_eq!(res.n(), self.n());
590        }
591        unsafe {
592            vec_znx::vec_znx_automorphism(
593                self.ptr,
594                k,
595                res.at_mut_ptr(res_col, 0),
596                res.size() as u64,
597                res.sl() as u64,
598                a.at_ptr(a_col, 0),
599                a.size() as u64,
600                a.sl() as u64,
601            )
602        }
603    }
604
605    fn vec_znx_big_automorphism_inplace<A>(&self, k: i64, a: &mut A, a_col: usize)
606    where
607        A: VecZnxBigToMut<FFT64>,
608    {
609        let mut a: VecZnxBig<&mut [u8], FFT64> = a.to_mut();
610
611        #[cfg(debug_assertions)]
612        {
613            assert_eq!(a.n(), self.n());
614        }
615        unsafe {
616            vec_znx::vec_znx_automorphism(
617                self.ptr,
618                k,
619                a.at_mut_ptr(a_col, 0),
620                a.size() as u64,
621                a.sl() as u64,
622                a.at_ptr(a_col, 0),
623                a.size() as u64,
624                a.sl() as u64,
625            )
626        }
627    }
628}
629
630impl<B: Backend> VecZnxBigScratch for Module<B> {
631    fn vec_znx_big_normalize_tmp_bytes(&self) -> usize {
632        <Self as VecZnxScratch>::vec_znx_normalize_tmp_bytes(self)
633    }
634}