1use super::{HeaplessBigInt, is_zero, zero};
16use crate::MachineWord;
17use const_num_traits::{
18 BorrowingSub, CarryingAdd, CarryingMul, CheckedAdd, CheckedMul, Nct, OverflowingAdd,
19 OverflowingMul, OverflowingSub, Personality, PersonalityTag, WrappingAdd, WrappingMul,
20 WrappingSub,
21};
22use core::marker::PhantomData;
23
24#[inline]
30fn panic_on_overflow_if_nct<P: Personality>(overflow: bool, msg: &'static str) {
31 match P::TAG {
32 PersonalityTag::Nct => assert!(!overflow, "{}", msg),
33 PersonalityTag::Ct => {}
34 }
35}
36
37#[inline]
49pub(crate) fn add_slice<T: MachineWord>(a: &[T], b: &[T], out: &mut [T], n: usize) -> bool {
50 let mut carry = false;
51 for ((&ai, &bi), oi) in a[..n].iter().zip(&b[..n]).zip(&mut out[..n]) {
52 let (sum, c) = <T as CarryingAdd>::carrying_add(ai, bi, carry);
53 *oi = sum;
54 carry = c;
55 }
56 carry
57}
58
59#[inline]
62pub(crate) fn sub_slice<T: MachineWord>(a: &[T], b: &[T], out: &mut [T], n: usize) -> bool {
63 let mut borrow = false;
64 for ((&ai, &bi), oi) in a[..n].iter().zip(&b[..n]).zip(&mut out[..n]) {
65 let (diff, br) = <T as BorrowingSub>::borrowing_sub(ai, bi, borrow);
66 *oi = diff;
67 borrow = br;
68 }
69 borrow
70}
71
72#[inline]
82pub(crate) fn mul_slice<T: MachineWord + CarryingMul<Unsigned = T, Output = T>>(
83 a: &[T],
84 a_n: usize,
85 b: &[T],
86 b_n: usize,
87 out: &mut [T],
88 out_n: usize,
89) {
90 let a = &a[..a_n];
94 let b = &b[..b_n];
95 let out = &mut out[..out_n];
96 let mut i = 0;
97 while i < a_n {
98 let mut carry = zero::<T>();
99 let mut j = 0;
100 while j < b_n {
101 let pos = i + j;
102 if pos < out_n {
103 let (lo, hi) = <T as CarryingMul>::carrying_mul(a[i], b[j], carry);
104 let (sum, c1) = <T as CarryingAdd>::carrying_add(out[pos], lo, false);
105 out[pos] = sum;
106 let (new_carry, _) = <T as CarryingAdd>::carrying_add(hi, zero::<T>(), c1);
107 carry = new_carry;
108 }
109 j += 1;
110 }
111 let tail = i + b_n;
112 if tail < out_n {
113 let (sum, _) = <T as CarryingAdd>::carrying_add(out[tail], carry, false);
114 out[tail] = sum;
115 }
116 i += 1;
117 }
118}
119
120impl<T: MachineWord, const CAP: usize, P: Personality> HeaplessBigInt<T, CAP, P> {
123 pub fn wrapping_add(&self, other: &Self) -> Self {
126 let out_len = core::cmp::max(self.len as usize, other.len as usize);
127 let mut out = Self::new_zero_with_len(out_len as u16);
128 let _carry = add_slice(&self.limbs, &other.limbs, &mut out.limbs, out_len);
129 debug_assert!(zero_tail_ok(&out.limbs, out_len));
130 out
131 }
132
133 pub fn overflowing_add(&self, other: &Self) -> (Self, bool) {
139 let out_len = core::cmp::max(self.len as usize, other.len as usize);
140 let mut out = Self::new_zero_with_len(out_len as u16);
141 let carry = add_slice(&self.limbs, &other.limbs, &mut out.limbs, out_len);
142 (out, carry)
143 }
144
145 pub fn checked_add(&self, other: &Self) -> Option<Self> {
147 let (res, overflow) = self.overflowing_add(other);
148 if overflow { None } else { Some(res) }
149 }
150
151 pub fn wrapping_sub(&self, other: &Self) -> Self {
155 let out_len = core::cmp::max(self.len as usize, other.len as usize);
156 let mut out = Self::new_zero_with_len(out_len as u16);
157 let _borrow = sub_slice(&self.limbs, &other.limbs, &mut out.limbs, out_len);
158 debug_assert!(zero_tail_ok(&out.limbs, out_len));
159 out
160 }
161
162 pub fn overflowing_sub(&self, other: &Self) -> (Self, bool) {
166 let out_len = core::cmp::max(self.len as usize, other.len as usize);
167 let mut out = Self::new_zero_with_len(out_len as u16);
168 let borrow = sub_slice(&self.limbs, &other.limbs, &mut out.limbs, out_len);
169 (out, borrow)
170 }
171
172 pub fn checked_sub(&self, other: &Self) -> Option<Self> {
174 let (res, borrow) = self.overflowing_sub(other);
175 if borrow { None } else { Some(res) }
176 }
177}
178
179impl<T: MachineWord + CarryingMul<Unsigned = T, Output = T>, const CAP: usize, P: Personality>
183 HeaplessBigInt<T, CAP, P>
184{
185 pub fn wrapping_mul(&self, other: &Self) -> Self {
190 let out_len = core::cmp::max(self.len as usize, other.len as usize);
191 let mut out = Self::new_zero_with_len(out_len as u16);
192 mul_slice(
193 &self.limbs,
194 self.len as usize,
195 &other.limbs,
196 other.len as usize,
197 &mut out.limbs,
198 out_len,
199 );
200 debug_assert!(zero_tail_ok(&out.limbs, out_len));
201 out
202 }
203
204 pub fn overflowing_mul(&self, other: &Self) -> (Self, bool) {
211 let zero_v = <Self as const_num_traits::Zero>::zero();
212 let (lo, hi) = <Self as CarryingMul>::carrying_mul(*self, *other, zero_v);
213 (lo, !<Self as const_num_traits::Zero>::is_zero(&hi))
214 }
215
216 pub fn checked_mul(&self, other: &Self) -> Option<Self> {
220 let (res, overflow) = self.overflowing_mul(other);
221 if overflow { None } else { Some(res) }
222 }
223}
224
225impl<T, const CAP: usize> CheckedAdd for HeaplessBigInt<T, CAP, Nct>
235where
236 T: MachineWord,
237{
238 type Output = Self;
239 fn checked_add(self, v: Self) -> Option<Self> {
240 Self::checked_add(&self, &v)
241 }
242}
243
244impl<T, const CAP: usize> CheckedMul for HeaplessBigInt<T, CAP, Nct>
245where
246 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
247{
248 type Output = Self;
249 fn checked_mul(self, v: Self) -> Option<Self> {
250 Self::checked_mul(&self, &v)
251 }
252}
253
254fn trim_content<T: MachineWord, const CAP: usize, P: Personality>(
259 mut v: HeaplessBigInt<T, CAP, P>,
260) -> HeaplessBigInt<T, CAP, P> {
261 let mut new_len: u16 = 0;
264 let mut i = 0;
265 while i < v.len as usize {
266 if !is_zero(&v.limbs[i]) {
267 new_len = (i + 1) as u16;
268 }
269 i += 1;
270 }
271 v.len = new_len;
272 v
273}
274
275impl<T: MachineWord, const CAP: usize> HeaplessBigInt<T, CAP, Nct> {
280 #[inline]
283 pub fn trim(self) -> Self {
284 trim_content(self)
285 }
286}
287
288impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Add<&HeaplessBigInt<T, CAP, P>>
295 for &HeaplessBigInt<T, CAP, P>
296{
297 type Output = HeaplessBigInt<T, CAP, P>;
298 fn add(self, other: &HeaplessBigInt<T, CAP, P>) -> Self::Output {
299 let (res, overflow) = self.overflowing_add(other);
300 panic_on_overflow_if_nct::<P>(overflow, "HeaplessBigInt::add overflow");
301 res
302 }
303}
304
305impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Sub<&HeaplessBigInt<T, CAP, P>>
306 for &HeaplessBigInt<T, CAP, P>
307{
308 type Output = HeaplessBigInt<T, CAP, P>;
309 fn sub(self, other: &HeaplessBigInt<T, CAP, P>) -> Self::Output {
310 let (res, borrow) = self.overflowing_sub(other);
311 panic_on_overflow_if_nct::<P>(borrow, "HeaplessBigInt::sub underflow");
312 res
313 }
314}
315
316impl<T: MachineWord + CarryingMul<Unsigned = T, Output = T>, const CAP: usize, P: Personality>
317 core::ops::Mul<&HeaplessBigInt<T, CAP, P>> for &HeaplessBigInt<T, CAP, P>
318{
319 type Output = HeaplessBigInt<T, CAP, P>;
320 fn mul(self, other: &HeaplessBigInt<T, CAP, P>) -> Self::Output {
321 let (res, overflow) = self.overflowing_mul(other);
322 panic_on_overflow_if_nct::<P>(overflow, "HeaplessBigInt::mul overflow");
323 res
324 }
325}
326
327impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Add
333 for HeaplessBigInt<T, CAP, P>
334{
335 type Output = Self;
336 fn add(self, other: Self) -> Self {
337 (&self).add(&other)
338 }
339}
340
341impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Add<&HeaplessBigInt<T, CAP, P>>
342 for HeaplessBigInt<T, CAP, P>
343{
344 type Output = Self;
345 fn add(self, other: &Self) -> Self {
346 (&self).add(other)
347 }
348}
349
350impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Add<HeaplessBigInt<T, CAP, P>>
351 for &HeaplessBigInt<T, CAP, P>
352{
353 type Output = HeaplessBigInt<T, CAP, P>;
354 fn add(self, other: HeaplessBigInt<T, CAP, P>) -> Self::Output {
355 self.add(&other)
356 }
357}
358
359impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Sub
360 for HeaplessBigInt<T, CAP, P>
361{
362 type Output = Self;
363 fn sub(self, other: Self) -> Self {
364 (&self).sub(&other)
365 }
366}
367
368impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Sub<&HeaplessBigInt<T, CAP, P>>
369 for HeaplessBigInt<T, CAP, P>
370{
371 type Output = Self;
372 fn sub(self, other: &Self) -> Self {
373 (&self).sub(other)
374 }
375}
376
377impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Sub<HeaplessBigInt<T, CAP, P>>
378 for &HeaplessBigInt<T, CAP, P>
379{
380 type Output = HeaplessBigInt<T, CAP, P>;
381 fn sub(self, other: HeaplessBigInt<T, CAP, P>) -> Self::Output {
382 self.sub(&other)
383 }
384}
385
386impl<T: MachineWord + CarryingMul<Unsigned = T, Output = T>, const CAP: usize, P: Personality>
387 core::ops::Mul for HeaplessBigInt<T, CAP, P>
388{
389 type Output = Self;
390 fn mul(self, other: Self) -> Self {
391 (&self).mul(&other)
392 }
393}
394
395impl<T: MachineWord + CarryingMul<Unsigned = T, Output = T>, const CAP: usize, P: Personality>
396 core::ops::Mul<&HeaplessBigInt<T, CAP, P>> for HeaplessBigInt<T, CAP, P>
397{
398 type Output = Self;
399 fn mul(self, other: &Self) -> Self {
400 (&self).mul(other)
401 }
402}
403
404impl<T: MachineWord + CarryingMul<Unsigned = T, Output = T>, const CAP: usize, P: Personality>
405 core::ops::Mul<HeaplessBigInt<T, CAP, P>> for &HeaplessBigInt<T, CAP, P>
406{
407 type Output = HeaplessBigInt<T, CAP, P>;
408 fn mul(self, other: HeaplessBigInt<T, CAP, P>) -> Self::Output {
409 self.mul(&other)
410 }
411}
412
413impl<T: MachineWord, const CAP: usize, P: Personality> WrappingAdd for HeaplessBigInt<T, CAP, P> {
420 type Output = Self;
421 fn wrapping_add(self, v: Self) -> Self::Output {
422 Self::wrapping_add(&self, &v)
423 }
424}
425
426impl<T: MachineWord, const CAP: usize, P: Personality> WrappingSub for HeaplessBigInt<T, CAP, P> {
427 type Output = Self;
428 fn wrapping_sub(self, v: Self) -> Self::Output {
429 Self::wrapping_sub(&self, &v)
430 }
431}
432
433impl<T: MachineWord, const CAP: usize, P: Personality> OverflowingAdd
434 for HeaplessBigInt<T, CAP, P>
435{
436 type Output = Self;
437 fn overflowing_add(self, v: Self) -> (Self::Output, bool) {
438 Self::overflowing_add(&self, &v)
439 }
440}
441
442impl<T: MachineWord, const CAP: usize, P: Personality> OverflowingSub
443 for HeaplessBigInt<T, CAP, P>
444{
445 type Output = Self;
446 fn overflowing_sub(self, v: Self) -> (Self::Output, bool) {
447 Self::overflowing_sub(&self, &v)
448 }
449}
450
451impl<T: MachineWord, const CAP: usize, P: Personality> WrappingAdd for &HeaplessBigInt<T, CAP, P> {
455 type Output = HeaplessBigInt<T, CAP, P>;
456 fn wrapping_add(self, v: Self) -> Self::Output {
457 HeaplessBigInt::wrapping_add(self, v)
458 }
459}
460
461impl<T: MachineWord, const CAP: usize, P: Personality> WrappingSub for &HeaplessBigInt<T, CAP, P> {
462 type Output = HeaplessBigInt<T, CAP, P>;
463 fn wrapping_sub(self, v: Self) -> Self::Output {
464 HeaplessBigInt::wrapping_sub(self, v)
465 }
466}
467
468impl<T: MachineWord, const CAP: usize, P: Personality> OverflowingAdd
469 for &HeaplessBigInt<T, CAP, P>
470{
471 type Output = HeaplessBigInt<T, CAP, P>;
472 fn overflowing_add(self, v: Self) -> (Self::Output, bool) {
473 HeaplessBigInt::overflowing_add(self, v)
474 }
475}
476
477impl<T: MachineWord, const CAP: usize, P: Personality> OverflowingSub
478 for &HeaplessBigInt<T, CAP, P>
479{
480 type Output = HeaplessBigInt<T, CAP, P>;
481 fn overflowing_sub(self, v: Self) -> (Self::Output, bool) {
482 HeaplessBigInt::overflowing_sub(self, v)
483 }
484}
485
486impl<T, const CAP: usize, P: Personality> WrappingMul for HeaplessBigInt<T, CAP, P>
490where
491 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
492{
493 type Output = Self;
494 fn wrapping_mul(self, v: Self) -> Self::Output {
495 Self::wrapping_mul(&self, &v)
496 }
497}
498
499impl<T, const CAP: usize, P: Personality> WrappingMul for &HeaplessBigInt<T, CAP, P>
500where
501 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
502{
503 type Output = HeaplessBigInt<T, CAP, P>;
504 fn wrapping_mul(self, v: Self) -> Self::Output {
505 HeaplessBigInt::wrapping_mul(self, v)
506 }
507}
508
509impl<T, const CAP: usize, P: Personality> OverflowingMul for HeaplessBigInt<T, CAP, P>
512where
513 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
514{
515 type Output = Self;
516 fn overflowing_mul(self, v: Self) -> (Self::Output, bool) {
517 Self::overflowing_mul(&self, &v)
518 }
519}
520
521impl<T, const CAP: usize, P: Personality> OverflowingMul for &HeaplessBigInt<T, CAP, P>
522where
523 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
524{
525 type Output = HeaplessBigInt<T, CAP, P>;
526 fn overflowing_mul(self, v: Self) -> (Self::Output, bool) {
527 HeaplessBigInt::overflowing_mul(self, v)
528 }
529}
530
531impl<T, const CAP: usize, P: Personality> CarryingAdd for HeaplessBigInt<T, CAP, P>
541where
542 T: MachineWord,
543{
544 type Output = Self;
545 fn carrying_add(self, rhs: Self, carry_in: bool) -> (Self::Output, bool) {
546 let out_len = core::cmp::max(self.len as usize, rhs.len as usize);
547 let mut out_limbs = [zero::<T>(); CAP];
548 let mut carry = carry_in;
549 let mut i = 0;
550 while i < out_len {
551 let (sum, c) = <T as CarryingAdd>::carrying_add(self.limbs[i], rhs.limbs[i], carry);
552 out_limbs[i] = sum;
553 carry = c;
554 i += 1;
555 }
556 (
557 HeaplessBigInt {
558 limbs: out_limbs,
559 len: out_len as u16,
560 _p: PhantomData,
561 },
562 carry,
563 )
564 }
565}
566
567impl<T, const CAP: usize, P: Personality> BorrowingSub for HeaplessBigInt<T, CAP, P>
572where
573 T: MachineWord,
574{
575 type Output = Self;
576 fn borrowing_sub(self, rhs: Self, borrow_in: bool) -> (Self::Output, bool) {
577 let out_len = core::cmp::max(self.len as usize, rhs.len as usize);
578 let mut out_limbs = [zero::<T>(); CAP];
579 let mut borrow = borrow_in;
580 let mut i = 0;
581 while i < out_len {
582 let (diff, br) =
583 <T as BorrowingSub>::borrowing_sub(self.limbs[i], rhs.limbs[i], borrow);
584 out_limbs[i] = diff;
585 borrow = br;
586 i += 1;
587 }
588 (
589 HeaplessBigInt {
590 limbs: out_limbs,
591 len: out_len as u16,
592 _p: PhantomData,
593 },
594 borrow,
595 )
596 }
597}
598
599impl<T, const CAP: usize, P: Personality> CarryingMul for HeaplessBigInt<T, CAP, P>
617where
618 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
619{
620 type Unsigned = Self;
621 type Output = Self;
622
623 fn carrying_mul(self, rhs: Self, carry: Self) -> (Self::Unsigned, Self::Output) {
624 let zero_v = <Self as const_num_traits::Zero>::zero();
625 self.carrying_mul_add(rhs, carry, zero_v)
626 }
627
628 fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (Self::Unsigned, Self::Output) {
629 let w = core::cmp::max(
632 core::cmp::max(self.len as usize, rhs.len as usize),
633 core::cmp::max(carry.len as usize, add.len as usize),
634 );
635 let mut lo_limbs = [zero::<T>(); CAP];
636 let mut hi_limbs = [zero::<T>(); CAP];
637
638 let a_n = self.len as usize;
642 let b_n = rhs.len as usize;
643 let mut i = 0;
644 while i < a_n {
645 let mut c = zero::<T>();
646 let mut j = 0;
647 while j < b_n {
648 let pos = i + j;
649 let (t_lo, t_hi) = <T as CarryingMul>::carrying_mul(self.limbs[i], rhs.limbs[j], c);
650 let existing = if pos < w {
651 lo_limbs[pos]
652 } else {
653 hi_limbs[pos - w]
654 };
655 let (sum, c1) = <T as CarryingAdd>::carrying_add(existing, t_lo, false);
656 if pos < w {
657 lo_limbs[pos] = sum;
658 } else {
659 hi_limbs[pos - w] = sum;
660 }
661 let (new_c, _) = <T as CarryingAdd>::carrying_add(t_hi, zero::<T>(), c1);
662 c = new_c;
663 j += 1;
664 }
665 let tail = i + b_n;
667 if tail < w {
668 let (sum, _) = <T as CarryingAdd>::carrying_add(lo_limbs[tail], c, false);
669 lo_limbs[tail] = sum;
670 } else {
671 let (sum, _) = <T as CarryingAdd>::carrying_add(hi_limbs[tail - w], c, false);
672 hi_limbs[tail - w] = sum;
673 }
674 i += 1;
675 }
676
677 for src in [&carry, &add] {
679 let mut cin = false;
680 let mut i = 0;
681 while i < w {
682 let (sum, c) = <T as CarryingAdd>::carrying_add(lo_limbs[i], src.limbs[i], cin);
683 lo_limbs[i] = sum;
684 cin = c;
685 i += 1;
686 }
687 let mut i = 0;
688 while cin && i < w {
689 let (sum, c) = <T as CarryingAdd>::carrying_add(hi_limbs[i], zero::<T>(), true);
690 hi_limbs[i] = sum;
691 cin = c;
692 i += 1;
693 }
694 }
695
696 let lo = HeaplessBigInt {
697 limbs: lo_limbs,
698 len: w as u16,
699 _p: PhantomData,
700 };
701 let hi = HeaplessBigInt {
702 limbs: hi_limbs,
703 len: w as u16,
704 _p: PhantomData,
705 };
706 (lo, hi)
707 }
708}
709
710#[inline]
711pub(crate) fn zero_tail_ok<T: MachineWord>(limbs: &[T], used: usize) -> bool {
712 let mut i = used;
713 while i < limbs.len() {
714 if !is_zero(&limbs[i]) {
715 return false;
716 }
717 i += 1;
718 }
719 true
720}