poulpy/math/src/modulus/impl_u64/operations.rs
math/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}