arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/rns/src/modulus/impl_u64/operations.rs
rns/src/modulus/impl_u64/operations.rsRaw
  1use crate::modulus::barrett::Barrett;
  2use crate::modulus::montgomery::Montgomery;
  3use crate::modulus::prime::Prime;
  4use crate::modulus::{ScalarOperations, VectorOperations};
  5use crate::modulus::{NONE, REDUCEMOD};
  6use crate::{
  7    apply_ssv, apply_sv, apply_v, apply_vsssvv, apply_vssv, apply_vsv, apply_vv, apply_vvssv,
  8    apply_vvsv, apply_vvv,
  9};
 10use itertools::izip;
 11
 12impl ScalarOperations<u64> for Prime<u64> {
 13    /// Applies a modular reduction on x based on REDUCE:
 14    /// - LAZY: no modular reduction.
 15    /// - ONCE: subtracts q if x >= q.
 16    /// - TWO: subtracts 2q if x >= 2q.
 17    /// - FOUR: subtracts 4q if x >= 4q.
 18    /// - BARRETT: maps x to x mod q using Barrett reduction.
 19    /// - BARRETTLAZY: maps x to x mod q using Barrett reduction with values in [0, 2q-1].
 20    #[inline(always)]
 21    fn sa_reduce_into_sa<const REDUCE: REDUCEMOD>(&self, a: &mut u64) {
 22        self.montgomery.reduce_assign::<REDUCE>(a);
 23    }
 24
 25    #[inline(always)]
 26    fn sa_add_sb_into_sc<const REDUCE: REDUCEMOD>(&self, a: &u64, b: &u64, c: &mut u64) {
 27        *c = a.wrapping_add(*b);
 28        self.sa_reduce_into_sa::<REDUCE>(c);
 29    }
 30
 31    #[inline(always)]
 32    fn sa_add_sb_into_sb<const REDUCE: REDUCEMOD>(&self, a: &u64, b: &mut u64) {
 33        *b = a.wrapping_add(*b);
 34        self.sa_reduce_into_sa::<REDUCE>(b);
 35    }
 36
 37    #[inline(always)]
 38    fn sa_sub_sb_into_sc<const SBRANGE: u8, const REDUCE: REDUCEMOD>(
 39        &self,
 40        a: &u64,
 41        b: &u64,
 42        c: &mut u64,
 43    ) {
 44        match SBRANGE {
 45            1 => *c = *a + self.q - *b,
 46            2 => *c = *a + self.two_q - *b,
 47            4 => *c = *a + self.four_q - *b,
 48            _ => unreachable!("invalid SBRANGE argument"),
 49        }
 50        self.sa_reduce_into_sa::<REDUCE>(c)
 51    }
 52
 53    #[inline(always)]
 54    fn sa_sub_sb_into_sa<const SBRANGE: u8, const REDUCE: REDUCEMOD>(&self, b: &u64, a: &mut u64) {
 55        match SBRANGE {
 56            1 => *a = *a + self.q - *b,
 57            2 => *a = *a + self.two_q - *b,
 58            4 => *a = *a + self.four_q - *b,
 59            _ => unreachable!("invalid SBRANGE argument"),
 60        }
 61        self.sa_reduce_into_sa::<REDUCE>(a)
 62    }
 63
 64    #[inline(always)]
 65    fn sa_sub_sb_into_sb<const SBRANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &u64, b: &mut u64) {
 66        match SBRANGE {
 67            1 => *b = *a + self.q - *b,
 68            2 => *b = *a + self.two_q - *b,
 69            4 => *b = *a + self.four_q - *b,
 70            _ => unreachable!("invalid SBRANGE argument"),
 71        }
 72        self.sa_reduce_into_sa::<REDUCE>(b)
 73    }
 74
 75    #[inline(always)]
 76    fn sa_neg_into_sa<const SBRANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &mut u64) {
 77        match SBRANGE {
 78            1 => *a = self.q - *a,
 79            2 => *a = self.two_q - *a,
 80            4 => *a = self.four_q - *a,
 81            _ => unreachable!("invalid SBRANGE argument"),
 82        }
 83        self.sa_reduce_into_sa::<REDUCE>(a)
 84    }
 85
 86    #[inline(always)]
 87    fn sa_neg_into_sb<const SBRANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &u64, b: &mut u64) {
 88        match SBRANGE {
 89            1 => *b = self.q - *a,
 90            2 => *b = self.two_q - *a,
 91            4 => *b = self.four_q - *a,
 92            _ => unreachable!("invalid SBRANGE argument"),
 93        }
 94        self.sa_reduce_into_sa::<REDUCE>(b)
 95    }
 96
 97    #[inline(always)]
 98    fn sa_prepare_montgomery_into_sa<const REDUCE: REDUCEMOD>(&self, a: &mut Montgomery<u64>) {
 99        *a = self.montgomery.prepare::<REDUCE>(*a);
100    }
101
102    #[inline(always)]
103    fn sa_prepare_montgomery_into_sb<const REDUCE: REDUCEMOD>(
104        &self,
105        a: &u64,
106        b: &mut Montgomery<u64>,
107    ) {
108        self.montgomery.prepare_assign::<REDUCE>(*a, b);
109    }
110
111    #[inline(always)]
112    fn sa_mul_sb_montgomery_into_sc<const REDUCE: REDUCEMOD>(
113        &self,
114        a: &u64,
115        b: &Montgomery<u64>,
116        c: &mut u64,
117    ) {
118        *c = self.montgomery.mul_external::<REDUCE>(*a, *b);
119    }
120
121    #[inline(always)]
122    fn sa_mul_sb_montgomery_add_sc_into_sc<const REDUCE1: REDUCEMOD, const REDUCE2: REDUCEMOD>(
123        &self,
124        a: &u64,
125        b: &Montgomery<u64>,
126        c: &mut u64,
127    ) {
128        *c += self.montgomery.mul_external::<REDUCE1>(*a, *b);
129        self.sa_reduce_into_sa::<REDUCE2>(c);
130    }
131
132    #[inline(always)]
133    fn sa_mul_sb_montgomery_into_sa<const REDUCE: REDUCEMOD>(
134        &self,
135        b: &Montgomery<u64>,
136        a: &mut u64,
137    ) {
138        self.montgomery.mul_external_assign::<REDUCE>(*b, a);
139    }
140
141    #[inline(always)]
142    fn sa_mul_sb_barrett_into_sc<const REDUCE: REDUCEMOD>(
143        &self,
144        a: &u64,
145        b: &Barrett<u64>,
146        c: &mut u64,
147    ) {
148        *c = self.barrett.mul_external::<REDUCE>(b, a);
149    }
150
151    #[inline(always)]
152    fn sa_mul_sb_barrett_into_sa<const REDUCE: REDUCEMOD>(&self, b: &Barrett<u64>, a: &mut u64) {
153        self.barrett.mul_external_assign::<REDUCE>(b, a);
154    }
155
156    #[inline(always)]
157    fn sa_sub_sb_mul_sc_barrett_into_sd<const VBRANGE: u8, const REDUCE: REDUCEMOD>(
158        &self,
159        a: &u64,
160        b: &u64,
161        c: &Barrett<u64>,
162        d: &mut u64,
163    ) {
164        match VBRANGE {
165            1 => *d = a + self.q - b,
166            2 => *d = a + self.two_q - b,
167            4 => *d = a + self.four_q - b,
168            _ => unreachable!("invalid SBRANGE argument"),
169        }
170        self.barrett.mul_external_assign::<REDUCE>(c, d);
171    }
172
173    #[inline(always)]
174    fn sa_sub_sb_mul_sc_barrett_into_sb<const SBRANGE: u8, const REDUCE: REDUCEMOD>(
175        &self,
176        a: &u64,
177        c: &Barrett<u64>,
178        b: &mut u64,
179    ) {
180        self.sa_sub_sb_into_sb::<SBRANGE, NONE>(a, b);
181        self.barrett.mul_external_assign::<REDUCE>(c, b);
182    }
183
184    #[inline(always)]
185    fn sa_add_sb_mul_sc_barrett_into_sd<const REDUCE: REDUCEMOD>(
186        &self,
187        a: &u64,
188        b: &u64,
189        c: &Barrett<u64>,
190        d: &mut u64,
191    ) {
192        *d = self.barrett.mul_external::<REDUCE>(c, &(*a + b));
193    }
194
195    #[inline(always)]
196    fn sa_add_sb_mul_sc_barrett_into_sa<const REDUCE: REDUCEMOD>(
197        &self,
198        b: &u64,
199        c: &Barrett<u64>,
200        a: &mut u64,
201    ) {
202        *a = self.barrett.mul_external::<REDUCE>(c, &(*a + b));
203    }
204
205    #[inline(always)]
206    fn sb_sub_sa_add_sc_mul_sd_barrett_into_se<const SBRANGE: u8, const REDUCE: REDUCEMOD>(
207        &self,
208        a: &u64,
209        b: &u64,
210        c: &u64,
211        d: &Barrett<u64>,
212        e: &mut u64,
213    ) {
214        self.sa_sub_sb_into_sc::<SBRANGE, NONE>(&(b + c), a, e);
215        self.barrett.mul_external_assign::<REDUCE>(d, e);
216    }
217
218    #[inline(always)]
219    fn sb_sub_sa_add_sc_mul_sd_barrett_into_sa<const SBRANGE: u8, const REDUCE: REDUCEMOD>(
220        &self,
221        b: &u64,
222        c: &u64,
223        d: &Barrett<u64>,
224        a: &mut u64,
225    ) {
226        self.sa_sub_sb_into_sb::<SBRANGE, NONE>(&(b + c), a);
227        self.barrett.mul_external_assign::<REDUCE>(d, a);
228    }
229
230    #[inline(always)]
231    fn sa_rsh_sb_mask_sc_into_sa(&self, b: &usize, c: &u64, a: &mut u64) {
232        *a = (*a >> b) & c
233    }
234
235    #[inline(always)]
236    fn sa_rsh_sb_mask_sc_into_sd(&self, a: &u64, b: &usize, c: &u64, d: &mut u64) {
237        *d = (*a >> b) & c
238    }
239
240    #[inline(always)]
241    fn sa_rsh_sb_mask_sc_add_sd_into_sd(&self, a: &u64, b: &usize, c: &u64, d: &mut u64) {
242        *d += (*a >> b) & c
243    }
244
245    #[inline(always)]
246    fn sa_signed_digit_into_sb<const CARRYOVERWRITE: bool, const BALANCED: bool>(
247        &self,
248        a: &u64,
249        base: &u64,
250        shift: &usize,
251        mask: &u64,
252        carry: &mut u64,
253        b: &mut u64,
254    ) {
255        if CARRYOVERWRITE {
256            self.sa_rsh_sb_mask_sc_into_sd(a, shift, mask, carry);
257        } else {
258            self.sa_rsh_sb_mask_sc_add_sd_into_sd(a, shift, mask, carry);
259        }
260
261        let c: u64 = if BALANCED && *carry == base >> 1 {
262            a & 1
263        } else {
264            ((*carry | (*carry << 1)) >> shift) & 1
265        };
266
267        *b = *carry + (self.q - base) * c;
268        *carry = c;
269    }
270}
271
272impl VectorOperations<u64> for Prime<u64> {
273    /// Applies a modular reduction on x based on REDUCE:
274    /// - LAZY: no modular reduction.
275    /// - ONCE: subtracts q if x >= q.
276    /// - TWO: subtracts 2q if x >= 2q.
277    /// - FOUR: subtracts 4q if x >= 4q.
278    /// - BARRETT: maps x to x mod q using Barrett reduction.
279    /// - BARRETTLAZY: maps x to x mod q using Barrett reduction with values in [0, 2q-1].
280    #[inline(always)]
281    fn va_reduce_into_va<const CHUNK: usize, const REDUCE: REDUCEMOD>(&self, a: &mut [u64]) {
282        apply_v!(self, Self::sa_reduce_into_sa::<REDUCE>, a, CHUNK);
283    }
284
285    #[inline(always)]
286    fn va_add_vb_into_vc<const CHUNK: usize, const REDUCE: REDUCEMOD>(
287        &self,
288        a: &[u64],
289        b: &[u64],
290        c: &mut [u64],
291    ) {
292        apply_vvv!(self, Self::sa_add_sb_into_sc::<REDUCE>, a, b, c, CHUNK);
293    }
294
295    #[inline(always)]
296    fn va_add_vb_into_vb<const CHUNK: usize, const REDUCE: REDUCEMOD>(
297        &self,
298        a: &[u64],
299        b: &mut [u64],
300    ) {
301        apply_vv!(self, Self::sa_add_sb_into_sb::<REDUCE>, a, b, CHUNK);
302    }
303
304    #[inline(always)]
305    fn va_add_sb_into_va<const CHUNK: usize, const REDUCE: REDUCEMOD>(
306        &self,
307        b: &u64,
308        a: &mut [u64],
309    ) {
310        apply_sv!(self, Self::sa_add_sb_into_sb::<REDUCE>, b, a, CHUNK);
311    }
312
313    #[inline(always)]
314    fn va_add_sb_into_vc<const CHUNK: usize, const REDUCE: REDUCEMOD>(
315        &self,
316        a: &[u64],
317        b: &u64,
318        c: &mut [u64],
319    ) {
320        apply_vsv!(self, Self::sa_add_sb_into_sc::<REDUCE>, a, b, c, CHUNK);
321    }
322
323    #[inline(always)]
324    fn va_sub_vb_into_vc<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>(
325        &self,
326        a: &[u64],
327        b: &[u64],
328        c: &mut [u64],
329    ) {
330        apply_vvv!(
331            self,
332            Self::sa_sub_sb_into_sc::<VBRANGE, REDUCE>,
333            a,
334            b,
335            c,
336            CHUNK
337        );
338    }
339
340    #[inline(always)]
341    fn va_sub_vb_into_va<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>(
342        &self,
343        b: &[u64],
344        a: &mut [u64],
345    ) {
346        apply_vv!(
347            self,
348            Self::sa_sub_sb_into_sa::<VBRANGE, REDUCE>,
349            b,
350            a,
351            CHUNK
352        );
353    }
354
355    #[inline(always)]
356    fn va_sub_vb_into_vb<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>(
357        &self,
358        a: &[u64],
359        b: &mut [u64],
360    ) {
361        apply_vv!(
362            self,
363            Self::sa_sub_sb_into_sb::<VBRANGE, REDUCE>,
364            a,
365            b,
366            CHUNK
367        );
368    }
369
370    #[inline(always)]
371    fn va_neg_into_va<const CHUNK: usize, const VARANGE: u8, const REDUCE: REDUCEMOD>(
372        &self,
373        a: &mut [u64],
374    ) {
375        apply_v!(self, Self::sa_neg_into_sa::<VARANGE, REDUCE>, a, CHUNK);
376    }
377
378    #[inline(always)]
379    fn va_neg_into_vb<const CHUNK: usize, const VARANGE: u8, const REDUCE: REDUCEMOD>(
380        &self,
381        a: &[u64],
382        b: &mut [u64],
383    ) {
384        apply_vv!(self, Self::sa_neg_into_sb::<VARANGE, REDUCE>, a, b, CHUNK);
385    }
386
387    #[inline(always)]
388    fn va_prep_mont_into_vb<const CHUNK: usize, const REDUCE: REDUCEMOD>(
389        &self,
390        a: &[u64],
391        b: &mut [Montgomery<u64>],
392    ) {
393        apply_vv!(
394            self,
395            Self::sa_prepare_montgomery_into_sb::<REDUCE>,
396            a,
397            b,
398            CHUNK
399        );
400    }
401
402    #[inline(always)]
403    fn va_prepare_montgomery_into_va<const CHUNK: usize, const REDUCE: REDUCEMOD>(
404        &self,
405        a: &mut [Montgomery<u64>],
406    ) {
407        apply_v!(
408            self,
409            Self::sa_prepare_montgomery_into_sa::<REDUCE>,
410            a,
411            CHUNK
412        );
413    }
414
415    #[inline(always)]
416    fn va_mul_vb_montgomery_into_vc<const CHUNK: usize, const REDUCE: REDUCEMOD>(
417        &self,
418        a: &[Montgomery<u64>],
419        b: &[u64],
420        c: &mut [u64],
421    ) {
422        apply_vvv!(
423            self,
424            Self::sa_mul_sb_montgomery_into_sc::<REDUCE>,
425            a,
426            b,
427            c,
428            CHUNK
429        );
430    }
431
432    #[inline(always)]
433    fn va_mul_vb_montgomery_add_vc_into_vc<
434        const CHUNK: usize,
435        const REDUCE1: REDUCEMOD,
436        const REDUCE2: REDUCEMOD,
437    >(
438        &self,
439        a: &[Montgomery<u64>],
440        b: &[u64],
441        c: &mut [u64],
442    ) {
443        apply_vvv!(
444            self,
445            Self::sa_mul_sb_montgomery_add_sc_into_sc::<REDUCE1, REDUCE2>,
446            a,
447            b,
448            c,
449            CHUNK
450        );
451    }
452
453    #[inline(always)]
454    fn va_mul_vb_montgomery_into_va<const CHUNK: usize, const REDUCE: REDUCEMOD>(
455        &self,
456        b: &[Montgomery<u64>],
457        a: &mut [u64],
458    ) {
459        apply_vv!(
460            self,
461            Self::sa_mul_sb_montgomery_into_sa::<REDUCE>,
462            b,
463            a,
464            CHUNK
465        );
466    }
467
468    #[inline(always)]
469    fn va_mul_sb_barrett_into_vc<const CHUNK: usize, const REDUCE: REDUCEMOD>(
470        &self,
471        a: &[u64],
472        b: &Barrett<u64>,
473        c: &mut [u64],
474    ) {
475        apply_vsv!(
476            self,
477            Self::sa_mul_sb_barrett_into_sc::<REDUCE>,
478            a,
479            b,
480            c,
481            CHUNK
482        );
483    }
484
485    #[inline(always)]
486    fn va_mul_sb_barrett_into_va<const CHUNK: usize, const REDUCE: REDUCEMOD>(
487        &self,
488        b: &Barrett<u64>,
489        a: &mut [u64],
490    ) {
491        apply_sv!(self, Self::sa_mul_sb_barrett_into_sa::<REDUCE>, b, a, CHUNK);
492    }
493
494    fn va_sub_vb_mul_sc_barrett_into_vd<
495        const CHUNK: usize,
496        const VBRANGE: u8,
497        const REDUCE: REDUCEMOD,
498    >(
499        &self,
500        a: &[u64],
501        b: &[u64],
502        c: &Barrett<u64>,
503        d: &mut [u64],
504    ) {
505        apply_vvsv!(
506            self,
507            Self::sa_sub_sb_mul_sc_barrett_into_sd::<VBRANGE, REDUCE>,
508            a,
509            b,
510            c,
511            d,
512            CHUNK
513        );
514    }
515
516    fn va_sub_vb_mul_sc_barrett_into_vb<
517        const CHUNK: usize,
518        const VBRANGE: u8,
519        const REDUCE: REDUCEMOD,
520    >(
521        &self,
522        a: &[u64],
523        b: &Barrett<u64>,
524        c: &mut [u64],
525    ) {
526        apply_vsv!(
527            self,
528            Self::sa_sub_sb_mul_sc_barrett_into_sb::<VBRANGE, REDUCE>,
529            a,
530            b,
531            c,
532            CHUNK
533        );
534    }
535
536    // vec(a) <- (vec(a) + scalar(b)) * scalar(c);
537    fn va_add_sb_mul_sc_barrett_into_va<const CHUNK: usize, const REDUCE: REDUCEMOD>(
538        &self,
539        b: &u64,
540        c: &Barrett<u64>,
541        a: &mut [u64],
542    ) {
543        apply_ssv!(
544            self,
545            Self::sa_add_sb_mul_sc_barrett_into_sa::<REDUCE>,
546            b,
547            c,
548            a,
549            CHUNK
550        );
551    }
552
553    // vec(a) <- (vec(a) + scalar(b)) * scalar(c);
554    fn va_add_sb_mul_sc_barrett_into_vd<const CHUNK: usize, const REDUCE: REDUCEMOD>(
555        &self,
556        a: &[u64],
557        b: &u64,
558        c: &Barrett<u64>,
559        d: &mut [u64],
560    ) {
561        apply_vssv!(
562            self,
563            Self::sa_add_sb_mul_sc_barrett_into_sd::<REDUCE>,
564            a,
565            b,
566            c,
567            d,
568            CHUNK
569        );
570    }
571
572    // vec(e) <- (vec(a) - vec(b) + scalar(c)) * scalar(e).
573    fn vb_sub_va_add_sc_mul_sd_barrett_into_ve<
574        const CHUNK: usize,
575        const VBRANGE: u8,
576        const REDUCE: REDUCEMOD,
577    >(
578        &self,
579        va: &[u64],
580        vb: &[u64],
581        sc: &u64,
582        sd: &Barrett<u64>,
583        ve: &mut [u64],
584    ) {
585        apply_vvssv!(
586            self,
587            Self::sb_sub_sa_add_sc_mul_sd_barrett_into_se::<VBRANGE, REDUCE>,
588            va,
589            vb,
590            sc,
591            sd,
592            ve,
593            CHUNK
594        );
595    }
596
597    // vec(a) <- (vec(b) - vec(a) + scalar(c)) * scalar(e).
598    fn vb_sub_va_add_sc_mul_sd_barrett_into_va<
599        const CHUNK: usize,
600        const VBRANGE: u8,
601        const REDUCE: REDUCEMOD,
602    >(
603        &self,
604        vb: &[u64],
605        sc: &u64,
606        sd: &Barrett<u64>,
607        va: &mut [u64],
608    ) {
609        apply_vssv!(
610            self,
611            Self::sb_sub_sa_add_sc_mul_sd_barrett_into_sa::<VBRANGE, REDUCE>,
612            vb,
613            sc,
614            sd,
615            va,
616            CHUNK
617        );
618    }
619
620    // vec(a) <- (vec(a)>>scalar(b)) & scalar(c).
621    fn va_rsh_sb_mask_sc_into_va<const CHUNK: usize>(&self, sb: &usize, sc: &u64, va: &mut [u64]) {
622        apply_ssv!(self, Self::sa_rsh_sb_mask_sc_into_sa, sb, sc, va, CHUNK);
623    }
624
625    // vec(d) <- (vec(a)>>scalar(b)) & scalar(c).
626    fn va_rsh_sb_mask_sc_into_vd<const CHUNK: usize>(
627        &self,
628        va: &[u64],
629        sb: &usize,
630        sc: &u64,
631        vd: &mut [u64],
632    ) {
633        apply_vssv!(self, Self::sa_rsh_sb_mask_sc_into_sd, va, sb, sc, vd, CHUNK);
634    }
635
636    // vec(d) <- vec(d) + (vec(a)>>scalar(b)) & scalar(c).
637    fn va_rsh_sb_mask_sc_add_vd_into_vd<const CHUNK: usize>(
638        &self,
639        va: &[u64],
640        sb: &usize,
641        sc: &u64,
642        vd: &mut [u64],
643    ) {
644        apply_vssv!(
645            self,
646            Self::sa_rsh_sb_mask_sc_add_sd_into_sd,
647            va,
648            sb,
649            sc,
650            vd,
651            CHUNK
652        );
653    }
654
655    // vec(c) <- i-th unsigned digit base 2^{sb} of vec(a).
656    // vec(c) is ensured to be in the range [0, 2^{sb}-1[ with E[vec(c)] = 2^{sb}-1.
657    fn va_ith_digit_unsigned_base_sb_into_vc<const CHUNK: usize>(
658        &self,
659        i: usize,
660        va: &[u64],
661        sb: &usize,
662        vc: &mut [u64],
663    ) {
664        self.va_rsh_sb_mask_sc_into_vd::<CHUNK>(va, &(i * sb), &((1 << sb) - 1), vc);
665    }
666
667    // vec(c) <- i-th signed digit base 2^{w} of vec(a).
668    // Reads the carry of the i-1-th iteration and write the carry on the i-th iteration on carry.
669    // if i > 0, carry of the i-1th iteration must be provided.
670    // if BALANCED: vec(c) is ensured to be [-2^{sb-1}, 2^{sb-1}[ with E[vec(c)] = 0, else E[vec(c)] = -0.5
671    fn va_ith_digit_signed_base_sb_into_vc<const CHUNK: usize, const BALANCED: bool>(
672        &self,
673        i: usize,
674        va: &[u64],
675        sb: &usize,
676        carry: &mut [u64],
677        vc: &mut [u64],
678    ) {
679        let base: u64 = 1 << sb;
680        let mask: u64 = base - 1;
681        if i == 0 {
682            apply_vsssvv!(
683                self,
684                Self::sa_signed_digit_into_sb::<true, BALANCED>,
685                va,
686                &base,
687                &(i * sb),
688                &mask,
689                carry,
690                vc,
691                CHUNK
692            );
693        } else {
694            apply_vsssvv!(
695                self,
696                Self::sa_signed_digit_into_sb::<false, BALANCED>,
697                va,
698                &base,
699                &(i * sb),
700                &mask,
701                carry,
702                vc,
703                CHUNK
704            );
705        }
706    }
707}