Skip to main content

poulpy_hal/api/
vec_znx.rs

1use crate::{
2    layouts::{
3        Backend, NoiseInfos, ScalarZnxBackendMut, ScalarZnxBackendRef, ScratchArena, VecZnxBackendMut, VecZnxBackendRef,
4        VecZnxBigBackendMut,
5    },
6    source::Source,
7};
8
9pub trait VecZnxNormalizeTmpBytes {
10    /// Returns the minimum number of bytes necessary for normalization.
11    fn vec_znx_normalize_tmp_bytes(&self) -> usize;
12}
13
14pub trait VecZnxZeroBackend<B: Backend> {
15    fn vec_znx_zero_backend(&self, res: &mut VecZnxBackendMut<'_, B>, res_col: usize);
16}
17
18pub trait VecZnxCopyRangeBackend<B: Backend> {
19    #[allow(clippy::too_many_arguments)]
20    fn vec_znx_copy_range_backend(
21        &self,
22        res: &mut VecZnxBackendMut<'_, B>,
23        res_col: usize,
24        res_limb: usize,
25        res_offset: usize,
26        a: &VecZnxBackendRef<'_, B>,
27        a_col: usize,
28        a_limb: usize,
29        a_offset: usize,
30        len: usize,
31    );
32}
33
34pub trait VecZnxExtractCoeffBackend<B: Backend> {
35    fn vec_znx_extract_coeff_backend(
36        &self,
37        res: &mut VecZnxBackendMut<'_, B>,
38        res_col: usize,
39        a: &VecZnxBackendRef<'_, B>,
40        a_col: usize,
41        a_coeff: usize,
42    );
43}
44
45/// Coefficient form of [`VecZnxNormalize`], with the same input and radix bounds.
46pub trait VecZnxNormalizeCoeffBackend<B: Backend> {
47    #[allow(clippy::too_many_arguments)]
48    /// Normalizes the selected coefficient of `a` across its limbs into a 1-coeff destination column.
49    fn vec_znx_normalize_coeff_backend(
50        &self,
51        res: &mut VecZnxBackendMut<'_, B>,
52        res_base2k: usize,
53        res_offset: i64,
54        res_col: usize,
55        a: &VecZnxBackendRef<'_, B>,
56        a_base2k: usize,
57        a_col: usize,
58        a_coeff: usize,
59        scratch: &mut ScratchArena<'_, B>,
60    );
61}
62
63pub trait VecZnxHadamardProductScalarZnxBackend<B: Backend> {
64    fn vec_znx_hadamard_product_scalar_znx_backend(
65        &self,
66        res: &mut VecZnxBigBackendMut<'_, B>,
67        res_col: usize,
68        a: &VecZnxBackendRef<'_, B>,
69        a_col: usize,
70        b: &ScalarZnxBackendRef<'_, B>,
71        b_col: usize,
72    );
73}
74
75/// Converts a column to centered digits, rounding once at the destination precision.
76///
77/// For i64 backends, each input limb coefficient must lie in `[-2^62, 2^62]`,
78/// and both radix widths must lie in `1..=62`. These bounds leave room for
79/// shifted digits and propagated carries. They are caller preconditions;
80/// normalization does not scan the input to validate them.
81pub trait VecZnxNormalize<B: Backend> {
82    #[allow(clippy::too_many_arguments)]
83    /// Normalizes the selected column of `a` at `res_k` bits into `res`.
84    fn vec_znx_normalize(
85        &self,
86        res: &mut VecZnxBackendMut<'_, B>,
87        res_base2k: usize,
88        res_k: usize,
89        res_offset: i64,
90        res_col: usize,
91        a: &VecZnxBackendRef<'_, B>,
92        a_base2k: usize,
93        a_col: usize,
94        scratch: &mut ScratchArena<'_, B>,
95    );
96}
97
98/// In-place normalization with the input and radix bounds of [`VecZnxNormalize`].
99pub trait VecZnxNormalizeAssignBackend<B: Backend> {
100    fn vec_znx_normalize_assign_backend(
101        &self,
102        base2k: usize,
103        k: usize,
104        a: &mut VecZnxBackendMut<'_, B>,
105        a_col: usize,
106        scratch: &mut ScratchArena<'_, B>,
107    );
108}
109
110/// In-place coefficient normalization with the bounds of [`VecZnxNormalize`].
111pub trait VecZnxNormalizeCoeffAssignBackend<B: Backend> {
112    fn vec_znx_normalize_coeff_assign_backend(
113        &self,
114        base2k: usize,
115        a: &mut VecZnxBackendMut<'_, B>,
116        a_col: usize,
117        a_coeff: usize,
118        scratch: &mut ScratchArena<'_, B>,
119    );
120}
121
122pub trait VecZnxAddIntoBackend<B: Backend> {
123    /// Adds the selected backend-native column of `a` to the selected backend-native column of `b`.
124    fn vec_znx_add_into_backend(
125        &self,
126        res: &mut VecZnxBackendMut<'_, B>,
127        res_col: usize,
128        a: &VecZnxBackendRef<'_, B>,
129        a_col: usize,
130        b: &VecZnxBackendRef<'_, B>,
131        b_col: usize,
132    );
133}
134
135pub trait VecZnxAddAssignBackend<B: Backend> {
136    fn vec_znx_add_assign_backend(
137        &self,
138        res: &mut VecZnxBackendMut<'_, B>,
139        res_col: usize,
140        a: &VecZnxBackendRef<'_, B>,
141        a_col: usize,
142    );
143}
144
145pub trait VecZnxAddConstIntoBackend<B: Backend> {
146    #[allow(clippy::too_many_arguments)]
147    fn vec_znx_add_const_into_backend(
148        &self,
149        res: &mut VecZnxBackendMut<'_, B>,
150        res_col: usize,
151        a: &VecZnxBackendRef<'_, B>,
152        a_col: usize,
153        cnst: &VecZnxBackendRef<'_, B>,
154        cnst_col: usize,
155        cnst_coeff: usize,
156        res_limb: usize,
157        res_coeff: usize,
158    );
159}
160
161pub trait VecZnxAddConstAssignBackend<B: Backend> {
162    #[allow(clippy::too_many_arguments)]
163    fn vec_znx_add_const_assign_backend(
164        &self,
165        res: &mut VecZnxBackendMut<'_, B>,
166        res_col: usize,
167        cnst: &VecZnxBackendRef<'_, B>,
168        cnst_col: usize,
169        cnst_coeff: usize,
170        res_limb: usize,
171        res_coeff: usize,
172    );
173}
174
175pub trait VecZnxAddScalarIntoBackend<B: Backend> {
176    #[allow(clippy::too_many_arguments)]
177    fn vec_znx_add_scalar_into_backend(
178        &self,
179        res: &mut VecZnxBackendMut<'_, B>,
180        res_col: usize,
181        a: &ScalarZnxBackendRef<'_, B>,
182        a_col: usize,
183        b: &VecZnxBackendRef<'_, B>,
184        b_col: usize,
185        b_limb: usize,
186    );
187}
188
189pub trait VecZnxAddScalarAssignBackend<B: Backend> {
190    fn vec_znx_add_scalar_assign_backend(
191        &self,
192        res: &mut VecZnxBackendMut<'_, B>,
193        res_col: usize,
194        res_limb: usize,
195        a: &ScalarZnxBackendRef<'_, B>,
196        a_col: usize,
197    );
198}
199
200pub trait VecZnxSubBackend<B: Backend> {
201    fn vec_znx_sub_backend(
202        &self,
203        res: &mut VecZnxBackendMut<'_, B>,
204        res_col: usize,
205        a: &VecZnxBackendRef<'_, B>,
206        a_col: usize,
207        b: &VecZnxBackendRef<'_, B>,
208        b_col: usize,
209    );
210}
211
212pub trait VecZnxSubAssignBackend<B: Backend> {
213    fn vec_znx_sub_assign_backend(
214        &self,
215        res: &mut VecZnxBackendMut<'_, B>,
216        res_col: usize,
217        a: &VecZnxBackendRef<'_, B>,
218        a_col: usize,
219    );
220}
221
222pub trait VecZnxSubNegateAssignBackend<B: Backend> {
223    fn vec_znx_sub_negate_assign_backend(
224        &self,
225        res: &mut VecZnxBackendMut<'_, B>,
226        res_col: usize,
227        a: &VecZnxBackendRef<'_, B>,
228        a_col: usize,
229    );
230}
231
232pub trait VecZnxSubScalarBackend<B: Backend> {
233    #[allow(clippy::too_many_arguments)]
234    fn vec_znx_sub_scalar_backend(
235        &self,
236        res: &mut VecZnxBackendMut<'_, B>,
237        res_col: usize,
238        a: &ScalarZnxBackendRef<'_, B>,
239        a_col: usize,
240        b: &VecZnxBackendRef<'_, B>,
241        b_col: usize,
242        b_limb: usize,
243    );
244}
245
246pub trait VecZnxSubScalarAssignBackend<B: Backend> {
247    fn vec_znx_sub_scalar_assign_backend(
248        &self,
249        res: &mut VecZnxBackendMut<'_, B>,
250        res_col: usize,
251        res_limb: usize,
252        a: &ScalarZnxBackendRef<'_, B>,
253        a_col: usize,
254    );
255}
256
257pub trait VecZnxNegateBackend<B: Backend> {
258    fn vec_znx_negate_backend(
259        &self,
260        res: &mut VecZnxBackendMut<'_, B>,
261        res_col: usize,
262        a: &VecZnxBackendRef<'_, B>,
263        a_col: usize,
264    );
265}
266
267pub trait VecZnxNegateAssignBackend<B: Backend> {
268    fn vec_znx_negate_assign_backend(&self, a: &mut VecZnxBackendMut<'_, B>, a_col: usize);
269}
270
271/// Returns scratch bytes required for left-shift operations.
272pub trait VecZnxLshTmpBytes {
273    fn vec_znx_lsh_tmp_bytes(&self) -> usize;
274}
275
276pub trait VecZnxLshBackend<B: Backend> {
277    /// Left shift by k bits all columns of `a`.
278    #[allow(clippy::too_many_arguments)]
279    fn vec_znx_lsh_backend(
280        &self,
281        base2k: usize,
282        k: usize,
283        res: &mut VecZnxBackendMut<'_, B>,
284        res_col: usize,
285        a: &VecZnxBackendRef<'_, B>,
286        a_col: usize,
287        scratch: &mut ScratchArena<'_, B>,
288    );
289}
290
291pub trait VecZnxLshCoeffBackend<B: Backend> {
292    #[allow(clippy::too_many_arguments)]
293    fn vec_znx_lsh_coeff_backend(
294        &self,
295        base2k: usize,
296        k: usize,
297        res: &mut VecZnxBackendMut<'_, B>,
298        res_col: usize,
299        a: &VecZnxBackendRef<'_, B>,
300        a_col: usize,
301        a_coeff: usize,
302        scratch: &mut ScratchArena<'_, B>,
303    );
304}
305
306pub trait VecZnxLshAddIntoBackend<B: Backend> {
307    /// Adds `a` left-shifted by `k` bits into `res`: `res += a << k`, column-wise.
308    ///
309    /// Normalization contract: the shifted operand `a` is normalized on the fly
310    /// (its own inter-limb carries are propagated), so the addend is in the
311    /// canonical `base2k` digit range. The addition into `res` is **not**
312    /// re-normalized: adding a normalized digit onto an already-normalized `res`
313    /// limb can leave that limb one bit beyond the `base2k` range. Callers that
314    /// require a normalized `res` afterwards must normalize it themselves; this
315    /// op alone does not restore the digit contract on `res`.
316    #[allow(clippy::too_many_arguments)]
317    fn vec_znx_lsh_add_into_backend(
318        &self,
319        base2k: usize,
320        k: usize,
321        res: &mut VecZnxBackendMut<'_, B>,
322        res_col: usize,
323        a: &VecZnxBackendRef<'_, B>,
324        a_col: usize,
325        scratch: &mut ScratchArena<'_, B>,
326    );
327}
328
329pub trait VecZnxLshAddCoeffIntoBackend<B: Backend> {
330    #[allow(clippy::too_many_arguments)]
331    fn vec_znx_lsh_add_coeff_into_backend(
332        &self,
333        base2k: usize,
334        k: usize,
335        res: &mut VecZnxBackendMut<'_, B>,
336        res_col: usize,
337        a: &VecZnxBackendRef<'_, B>,
338        a_col: usize,
339        a_coeff: usize,
340        scratch: &mut ScratchArena<'_, B>,
341    );
342}
343
344pub trait VecZnxLshAddCoeffToCoeffBackend<B: Backend> {
345    #[allow(clippy::too_many_arguments)]
346    fn vec_znx_lsh_add_coeff_to_coeff_backend(
347        &self,
348        base2k: usize,
349        k: usize,
350        res: &mut VecZnxBackendMut<'_, B>,
351        res_col: usize,
352        a: &VecZnxBackendRef<'_, B>,
353        a_col: usize,
354        a_coeff: usize,
355        res_coeff: usize,
356        scratch: &mut ScratchArena<'_, B>,
357    );
358}
359
360pub trait VecZnxLshSubCoeffToCoeffBackend<B: Backend> {
361    #[allow(clippy::too_many_arguments)]
362    fn vec_znx_lsh_sub_coeff_to_coeff_backend(
363        &self,
364        base2k: usize,
365        k: usize,
366        res: &mut VecZnxBackendMut<'_, B>,
367        res_col: usize,
368        a: &VecZnxBackendRef<'_, B>,
369        a_col: usize,
370        a_coeff: usize,
371        res_coeff: usize,
372        scratch: &mut ScratchArena<'_, B>,
373    );
374}
375
376/// Returns scratch bytes required for right-shift operations.
377pub trait VecZnxRshTmpBytes {
378    fn vec_znx_rsh_tmp_bytes(&self) -> usize;
379}
380
381pub trait VecZnxRshBackend<B: Backend> {
382    /// Right shift by k bits all columns of `a`.
383    #[allow(clippy::too_many_arguments)]
384    fn vec_znx_rsh_backend(
385        &self,
386        base2k: usize,
387        k: usize,
388        res: &mut VecZnxBackendMut<'_, B>,
389        res_col: usize,
390        a: &VecZnxBackendRef<'_, B>,
391        a_col: usize,
392        scratch: &mut ScratchArena<'_, B>,
393    );
394}
395
396pub trait VecZnxRshCoeffBackend<B: Backend> {
397    #[allow(clippy::too_many_arguments)]
398    fn vec_znx_rsh_coeff_backend(
399        &self,
400        base2k: usize,
401        k: usize,
402        res: &mut VecZnxBackendMut<'_, B>,
403        res_col: usize,
404        a: &VecZnxBackendRef<'_, B>,
405        a_col: usize,
406        a_coeff: usize,
407        scratch: &mut ScratchArena<'_, B>,
408    );
409}
410
411pub trait VecZnxRshAddIntoBackend<B: Backend> {
412    /// Adds `a` right-shifted by `k` bits into `res`: `res += a >> k`, column-wise.
413    ///
414    /// Normalization contract: the shifted operand `a` is normalized on the fly
415    /// (its own inter-limb carries are propagated), so the addend is in the
416    /// canonical `base2k` digit range. The addition into `res` is **not**
417    /// re-normalized: adding a normalized digit onto an already-normalized `res`
418    /// limb can leave that limb one bit beyond the `base2k` range. Callers that
419    /// require a normalized `res` afterwards must normalize it themselves; this
420    /// op alone does not restore the digit contract on `res`.
421    #[allow(clippy::too_many_arguments)]
422    fn vec_znx_rsh_add_into_backend(
423        &self,
424        base2k: usize,
425        k: usize,
426        res: &mut VecZnxBackendMut<'_, B>,
427        res_col: usize,
428        a: &VecZnxBackendRef<'_, B>,
429        a_col: usize,
430        scratch: &mut ScratchArena<'_, B>,
431    );
432}
433
434pub trait VecZnxRshAddCoeffIntoBackend<B: Backend> {
435    #[allow(clippy::too_many_arguments)]
436    fn vec_znx_rsh_add_coeff_into_backend(
437        &self,
438        base2k: usize,
439        k: usize,
440        res: &mut VecZnxBackendMut<'_, B>,
441        res_col: usize,
442        a: &VecZnxBackendRef<'_, B>,
443        a_col: usize,
444        a_coeff: usize,
445        res_coeff: usize,
446        scratch: &mut ScratchArena<'_, B>,
447    );
448}
449
450pub trait VecZnxRshSubCoeffIntoBackend<B: Backend> {
451    #[allow(clippy::too_many_arguments)]
452    fn vec_znx_rsh_sub_coeff_into_backend(
453        &self,
454        base2k: usize,
455        k: usize,
456        res: &mut VecZnxBackendMut<'_, B>,
457        res_col: usize,
458        a: &VecZnxBackendRef<'_, B>,
459        a_col: usize,
460        a_coeff: usize,
461        res_coeff: usize,
462        scratch: &mut ScratchArena<'_, B>,
463    );
464}
465
466pub trait VecZnxLshSubBackend<B: Backend> {
467    /// Left shift by k bits and subtract from destination.
468    #[allow(clippy::too_many_arguments)]
469    fn vec_znx_lsh_sub_backend(
470        &self,
471        base2k: usize,
472        k: usize,
473        res: &mut VecZnxBackendMut<'_, B>,
474        res_col: usize,
475        a: &VecZnxBackendRef<'_, B>,
476        a_col: usize,
477        scratch: &mut ScratchArena<'_, B>,
478    );
479}
480
481pub trait VecZnxRshSubBackend<B: Backend> {
482    /// Right shift by k bits and subtract from destination.
483    #[allow(clippy::too_many_arguments)]
484    fn vec_znx_rsh_sub_backend(
485        &self,
486        base2k: usize,
487        k: usize,
488        res: &mut VecZnxBackendMut<'_, B>,
489        res_col: usize,
490        a: &VecZnxBackendRef<'_, B>,
491        a_col: usize,
492        scratch: &mut ScratchArena<'_, B>,
493    );
494}
495
496pub trait VecZnxLshAssignBackend<B: Backend> {
497    /// Left shift by k bits all columns of `a`.
498    fn vec_znx_lsh_assign_backend(
499        &self,
500        base2k: usize,
501        k: usize,
502        a: &mut VecZnxBackendMut<'_, B>,
503        a_col: usize,
504        scratch: &mut ScratchArena<'_, B>,
505    );
506}
507
508pub trait VecZnxRshAssignBackend<B: Backend> {
509    /// Right shift by k bits all columns of `a`.
510    fn vec_znx_rsh_assign_backend(
511        &self,
512        base2k: usize,
513        k: usize,
514        a: &mut VecZnxBackendMut<'_, B>,
515        a_col: usize,
516        scratch: &mut ScratchArena<'_, B>,
517    );
518}
519
520pub trait VecZnxRotateBackend<B: Backend> {
521    /// Multiplies the selected column of `a` by X^k and stores the result in `res_col` of `res`.
522    fn vec_znx_rotate_backend(
523        &self,
524        p: i64,
525        res: &mut VecZnxBackendMut<'_, B>,
526        res_col: usize,
527        a: &VecZnxBackendRef<'_, B>,
528        a_col: usize,
529    );
530}
531
532pub trait VecZnxRotateAssignTmpBytes {
533    fn vec_znx_rotate_assign_tmp_bytes(&self) -> usize;
534}
535
536pub trait VecZnxRotateAssignBackend<B: Backend> {
537    /// Multiplies the selected column of `a` by X^k.
538    fn vec_znx_rotate_assign_backend(
539        &self,
540        p: i64,
541        a: &mut VecZnxBackendMut<'_, B>,
542        a_col: usize,
543        scratch: &mut ScratchArena<'_, B>,
544    );
545}
546
547pub trait VecZnxAutomorphismBackend<B: Backend> {
548    /// Applies the automorphism X^i -> X^ik on the selected column of `a` and stores the result in `res_col` column of `res`.
549    fn vec_znx_automorphism_backend(
550        &self,
551        k: i64,
552        res: &mut VecZnxBackendMut<'_, B>,
553        res_col: usize,
554        a: &VecZnxBackendRef<'_, B>,
555        a_col: usize,
556    );
557}
558
559pub trait VecZnxAutomorphismAssignTmpBytes {
560    fn vec_znx_automorphism_assign_tmp_bytes(&self) -> usize;
561}
562
563pub trait VecZnxAutomorphismAssignBackend<B: Backend> {
564    /// Applies the automorphism X^i -> X^ik on the selected column of `a`.
565    fn vec_znx_automorphism_assign_backend(
566        &self,
567        k: i64,
568        res: &mut VecZnxBackendMut<'_, B>,
569        res_col: usize,
570        scratch: &mut ScratchArena<'_, B>,
571    );
572}
573
574pub trait VecZnxAutomorphismRotateBackend<B: Backend> {
575    /// Fused automorphism + rotation: computes `res = X^k * auto(p, a)` on the
576    /// selected column of `a` and stores it in `res_col` of `res`. Equivalent to
577    /// an automorphism with `p` followed by a rotation by `k`, in a single pass.
578    #[allow(clippy::too_many_arguments)]
579    fn vec_znx_automorphism_rotate_backend(
580        &self,
581        p: i64,
582        k: i64,
583        res: &mut VecZnxBackendMut<'_, B>,
584        res_col: usize,
585        a: &VecZnxBackendRef<'_, B>,
586        a_col: usize,
587    );
588}
589
590pub trait ScalarZnxAutomorphismBackend<B: Backend> {
591    /// Applies the automorphism X^i -> X^ik on the selected column of `a` and stores the result in `res_col` column of `res`.
592    fn scalar_znx_automorphism_backend(
593        &self,
594        k: i64,
595        res: &mut ScalarZnxBackendMut<'_, B>,
596        res_col: usize,
597        a: &ScalarZnxBackendRef<'_, B>,
598        a_col: usize,
599    );
600}
601
602pub trait ScalarZnxAutomorphismAssignTmpBytes {
603    fn scalar_znx_automorphism_assign_tmp_bytes(&self) -> usize;
604}
605
606pub trait ScalarZnxAutomorphismAssignBackend<B: Backend> {
607    /// Applies the automorphism X^i -> X^ik on the selected column of `a`.
608    fn scalar_znx_automorphism_assign_backend(
609        &self,
610        k: i64,
611        res: &mut ScalarZnxBackendMut<'_, B>,
612        res_col: usize,
613        scratch: &mut ScratchArena<'_, B>,
614    );
615}
616
617/// Multiplies the selected column by `(X^p - 1)` in `Z[X]/(X^N + 1)`.
618pub trait VecZnxMulXpMinusOneBackend<B: Backend> {
619    fn vec_znx_mul_xp_minus_one_backend(
620        &self,
621        p: i64,
622        res: &mut VecZnxBackendMut<'_, B>,
623        res_col: usize,
624        a: &VecZnxBackendRef<'_, B>,
625        a_col: usize,
626    );
627}
628
629pub trait VecZnxMulXpMinusOneAssignTmpBytes {
630    fn vec_znx_mul_xp_minus_one_assign_tmp_bytes(&self) -> usize;
631}
632
633pub trait VecZnxMulXpMinusOneAssignBackend<B: Backend> {
634    fn vec_znx_mul_xp_minus_one_assign_backend(
635        &self,
636        p: i64,
637        res: &mut VecZnxBackendMut<'_, B>,
638        res_col: usize,
639        scratch: &mut ScratchArena<'_, B>,
640    );
641}
642
643pub trait VecZnxSplitRingTmpBytes {
644    fn vec_znx_split_ring_tmp_bytes(&self) -> usize;
645}
646
647pub trait VecZnxSplitRingBackend<B: Backend> {
648    /// Splits the selected columns of `b` into subrings and copies them them into the selected column of `res`.
649    ///
650    /// # Panics
651    ///
652    /// This method requires that all [crate::layouts::VecZnx] of b have the same ring degree
653    /// and that b.n() * b.len() <= a.n()
654    fn vec_znx_split_ring_backend(
655        &self,
656        res: &mut [VecZnxBackendMut<'_, B>],
657        res_col: usize,
658        a: &VecZnxBackendRef<'_, B>,
659        a_col: usize,
660        scratch: &mut ScratchArena<'_, B>,
661    );
662}
663
664pub trait VecZnxMergeRingsTmpBytes {
665    fn vec_znx_merge_rings_tmp_bytes(&self) -> usize;
666}
667
668pub trait VecZnxMergeRingsBackend<B: Backend> {
669    /// Merges the subrings of the selected column of `a` into the selected column of `res`.
670    ///
671    /// # Panics
672    ///
673    /// This method requires that all [crate::layouts::VecZnx] of a have the same ring degree
674    /// and that a.n() * a.len() <= b.n()
675    fn vec_znx_merge_rings_backend(
676        &self,
677        res: &mut VecZnxBackendMut<'_, B>,
678        res_col: usize,
679        a: &[VecZnxBackendRef<'_, B>],
680        a_col: usize,
681        scratch: &mut ScratchArena<'_, B>,
682    );
683}
684
685/// Switches ring degree between `a` and `res` by truncation or zero-padding.
686pub trait VecZnxSwitchRingBackend<B: Backend> {
687    fn vec_znx_switch_ring_backend(
688        &self,
689        res: &mut VecZnxBackendMut<'_, B>,
690        res_col: usize,
691        a: &VecZnxBackendRef<'_, B>,
692        a_col: usize,
693    );
694}
695
696pub trait VecZnxCopyBackend<B: Backend> {
697    fn vec_znx_copy_backend(&self, res: &mut VecZnxBackendMut<'_, B>, res_col: usize, a: &VecZnxBackendRef<'_, B>, a_col: usize);
698}
699
700/// Per-limb square transpose of a `VecZnx`.
701///
702/// For each limb `j`, sets `res.at(c, j)[k] = a.at(k, j)[c]`.
703///
704/// # Panics
705///
706/// Requires `res.n() == a.cols()` and `res.cols() == a.n()`.
707pub trait VecZnxTransposeBackend<B: Backend> {
708    fn vec_znx_transpose_backend(&self, res: &mut VecZnxBackendMut<'_, B>, a: &VecZnxBackendRef<'_, B>);
709}
710
711pub trait ScalarZnxFillTernaryHwSourceBackend<B: Backend> {
712    fn scalar_znx_fill_ternary_hw_source_backend(
713        &self,
714        res: &mut ScalarZnxBackendMut<'_, B>,
715        res_col: usize,
716        hw: usize,
717        source: &mut Source,
718    );
719}
720
721pub trait ScalarZnxFillTernaryHwBackend<B: Backend> {
722    fn scalar_znx_fill_ternary_hw_backend(&self, res: &mut ScalarZnxBackendMut<'_, B>, res_col: usize, hw: usize, seed: [u8; 32]);
723}
724
725pub trait ScalarZnxFillTernaryProbSourceBackend<B: Backend> {
726    fn scalar_znx_fill_ternary_prob_source_backend(
727        &self,
728        res: &mut ScalarZnxBackendMut<'_, B>,
729        res_col: usize,
730        prob: f64,
731        source: &mut Source,
732    );
733}
734
735pub trait ScalarZnxFillTernaryProbBackend<B: Backend> {
736    fn scalar_znx_fill_ternary_prob_backend(
737        &self,
738        res: &mut ScalarZnxBackendMut<'_, B>,
739        res_col: usize,
740        prob: f64,
741        seed: [u8; 32],
742    );
743}
744
745pub trait ScalarZnxFillBinaryHwSourceBackend<B: Backend> {
746    fn scalar_znx_fill_binary_hw_source_backend(
747        &self,
748        res: &mut ScalarZnxBackendMut<'_, B>,
749        res_col: usize,
750        hw: usize,
751        source: &mut Source,
752    );
753}
754
755pub trait ScalarZnxFillBinaryHwBackend<B: Backend> {
756    fn scalar_znx_fill_binary_hw_backend(&self, res: &mut ScalarZnxBackendMut<'_, B>, res_col: usize, hw: usize, seed: [u8; 32]);
757}
758
759pub trait ScalarZnxFillBinaryProbSourceBackend<B: Backend> {
760    fn scalar_znx_fill_binary_prob_source_backend(
761        &self,
762        res: &mut ScalarZnxBackendMut<'_, B>,
763        res_col: usize,
764        prob: f64,
765        source: &mut Source,
766    );
767}
768
769pub trait ScalarZnxFillBinaryProbBackend<B: Backend> {
770    fn scalar_znx_fill_binary_prob_backend(
771        &self,
772        res: &mut ScalarZnxBackendMut<'_, B>,
773        res_col: usize,
774        prob: f64,
775        seed: [u8; 32],
776    );
777}
778
779pub trait ScalarZnxFillBinaryBlockSourceBackend<B: Backend> {
780    fn scalar_znx_fill_binary_block_source_backend(
781        &self,
782        res: &mut ScalarZnxBackendMut<'_, B>,
783        res_col: usize,
784        block_size: usize,
785        source: &mut Source,
786    );
787}
788
789pub trait ScalarZnxFillBinaryBlockBackend<B: Backend> {
790    fn scalar_znx_fill_binary_block_backend(
791        &self,
792        res: &mut ScalarZnxBackendMut<'_, B>,
793        res_col: usize,
794        block_size: usize,
795        seed: [u8; 32],
796    );
797}
798
799pub trait VecZnxFillUniformSourceBackend<B: Backend> {
800    /// Fills a column with a uniform `k`-bit torus value in base `2^base2k`.
801    ///
802    /// Unused low bits in the last live limb and limbs above `k` are zeroed.
803    fn vec_znx_fill_uniform_source_backend(
804        &self,
805        base2k: usize,
806        k: usize,
807        res: &mut VecZnxBackendMut<'_, B>,
808        res_col: usize,
809        source: &mut Source,
810    );
811}
812
813pub trait VecZnxFillUniformBackend<B: Backend> {
814    /// Seeded counterpart of [`VecZnxFillUniformSourceBackend`].
815    fn vec_znx_fill_uniform_backend(
816        &self,
817        base2k: usize,
818        k: usize,
819        res: &mut VecZnxBackendMut<'_, B>,
820        res_col: usize,
821        seed: [u8; 32],
822    );
823}
824
825#[allow(clippy::too_many_arguments)]
826/// Fills the selected column with a discrete Gaussian noise vector
827/// scaled by `2^{-k}` with standard deviation `sigma`, bounded to `[-bound, bound]`.
828pub trait VecZnxFillNormalSourceBackend<B: Backend> {
829    fn vec_znx_fill_normal_source_backend(
830        &self,
831        base2k: usize,
832        res: &mut VecZnxBackendMut<'_, B>,
833        res_col: usize,
834        noise_infos: NoiseInfos,
835        source_xe: &mut Source,
836    );
837}
838
839#[allow(clippy::too_many_arguments)]
840pub trait VecZnxFillNormalBackend<B: Backend> {
841    /// Fills the selected backend-native column from a backend-defined normal sampler seeded by `seed`.
842    fn vec_znx_fill_normal_backend(
843        &self,
844        base2k: usize,
845        res: &mut VecZnxBackendMut<'_, B>,
846        res_col: usize,
847        noise_infos: NoiseInfos,
848        seed: [u8; 32],
849    );
850}
851
852#[allow(clippy::too_many_arguments)]
853pub trait VecZnxAddNormalSourceBackend<B: Backend> {
854    /// Adds a discrete normal vector scaled by 2^{-k} with the provided standard deviation and bounded to \[-bound, bound\].
855    fn vec_znx_add_normal_source_backend(
856        &self,
857        base2k: usize,
858        res: &mut VecZnxBackendMut<'_, B>,
859        res_col: usize,
860        noise_infos: NoiseInfos,
861        source_xe: &mut Source,
862    );
863}
864
865#[allow(clippy::too_many_arguments)]
866pub trait VecZnxAddNormalBackend<B: Backend> {
867    /// Adds backend-defined normal noise to the selected backend-native column using `seed`.
868    fn vec_znx_add_normal_backend(
869        &self,
870        base2k: usize,
871        res: &mut VecZnxBackendMut<'_, B>,
872        res_col: usize,
873        noise_infos: NoiseInfos,
874        seed: [u8; 32],
875    );
876}