use super::{HeaplessBigInt, is_zero, zero};
use crate::MachineWord;
use const_num_traits::{
BorrowingSub, CarryingAdd, CarryingMul, CheckedAdd, CheckedMul, Nct, OverflowingAdd,
OverflowingMul, OverflowingSub, Personality, PersonalityTag, WrappingAdd, WrappingMul,
WrappingSub,
};
use core::marker::PhantomData;
#[inline]
fn panic_on_overflow_if_nct<P: Personality>(overflow: bool, msg: &'static str) {
match P::TAG {
PersonalityTag::Nct => assert!(!overflow, "{}", msg),
PersonalityTag::Ct => {}
}
}
#[inline]
pub(crate) fn add_slice<T: MachineWord>(a: &[T], b: &[T], out: &mut [T], n: usize) -> bool {
let mut carry = false;
for ((&ai, &bi), oi) in a[..n].iter().zip(&b[..n]).zip(&mut out[..n]) {
let (sum, c) = <T as CarryingAdd>::carrying_add(ai, bi, carry);
*oi = sum;
carry = c;
}
carry
}
#[inline]
pub(crate) fn sub_slice<T: MachineWord>(a: &[T], b: &[T], out: &mut [T], n: usize) -> bool {
let mut borrow = false;
for ((&ai, &bi), oi) in a[..n].iter().zip(&b[..n]).zip(&mut out[..n]) {
let (diff, br) = <T as BorrowingSub>::borrowing_sub(ai, bi, borrow);
*oi = diff;
borrow = br;
}
borrow
}
#[inline]
pub(crate) fn mul_slice<T: MachineWord + CarryingMul<Unsigned = T, Output = T>>(
a: &[T],
a_n: usize,
b: &[T],
b_n: usize,
out: &mut [T],
out_n: usize,
) {
let a = &a[..a_n];
let b = &b[..b_n];
let out = &mut out[..out_n];
let mut i = 0;
while i < a_n {
let mut carry = zero::<T>();
let mut j = 0;
while j < b_n {
let pos = i + j;
if pos < out_n {
let (lo, hi) = <T as CarryingMul>::carrying_mul(a[i], b[j], carry);
let (sum, c1) = <T as CarryingAdd>::carrying_add(out[pos], lo, false);
out[pos] = sum;
let (new_carry, _) = <T as CarryingAdd>::carrying_add(hi, zero::<T>(), c1);
carry = new_carry;
}
j += 1;
}
let tail = i + b_n;
if tail < out_n {
let (sum, _) = <T as CarryingAdd>::carrying_add(out[tail], carry, false);
out[tail] = sum;
}
i += 1;
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> HeaplessBigInt<T, CAP, P> {
pub fn wrapping_add(&self, other: &Self) -> Self {
let out_len = core::cmp::max(self.len as usize, other.len as usize);
let mut out = Self::new_zero_with_len(out_len as u16);
let _carry = add_slice(&self.limbs, &other.limbs, &mut out.limbs, out_len);
debug_assert!(zero_tail_ok(&out.limbs, out_len));
out
}
pub fn overflowing_add(&self, other: &Self) -> (Self, bool) {
let out_len = core::cmp::max(self.len as usize, other.len as usize);
let mut out = Self::new_zero_with_len(out_len as u16);
let carry = add_slice(&self.limbs, &other.limbs, &mut out.limbs, out_len);
(out, carry)
}
pub fn checked_add(&self, other: &Self) -> Option<Self> {
let (res, overflow) = self.overflowing_add(other);
if overflow { None } else { Some(res) }
}
pub fn wrapping_sub(&self, other: &Self) -> Self {
let out_len = core::cmp::max(self.len as usize, other.len as usize);
let mut out = Self::new_zero_with_len(out_len as u16);
let _borrow = sub_slice(&self.limbs, &other.limbs, &mut out.limbs, out_len);
debug_assert!(zero_tail_ok(&out.limbs, out_len));
out
}
pub fn overflowing_sub(&self, other: &Self) -> (Self, bool) {
let out_len = core::cmp::max(self.len as usize, other.len as usize);
let mut out = Self::new_zero_with_len(out_len as u16);
let borrow = sub_slice(&self.limbs, &other.limbs, &mut out.limbs, out_len);
(out, borrow)
}
pub fn checked_sub(&self, other: &Self) -> Option<Self> {
let (res, borrow) = self.overflowing_sub(other);
if borrow { None } else { Some(res) }
}
}
impl<T: MachineWord + CarryingMul<Unsigned = T, Output = T>, const CAP: usize, P: Personality>
HeaplessBigInt<T, CAP, P>
{
pub fn wrapping_mul(&self, other: &Self) -> Self {
let out_len = core::cmp::max(self.len as usize, other.len as usize);
let mut out = Self::new_zero_with_len(out_len as u16);
mul_slice(
&self.limbs,
self.len as usize,
&other.limbs,
other.len as usize,
&mut out.limbs,
out_len,
);
debug_assert!(zero_tail_ok(&out.limbs, out_len));
out
}
pub fn overflowing_mul(&self, other: &Self) -> (Self, bool) {
let zero_v = <Self as const_num_traits::Zero>::zero();
let (lo, hi) = <Self as CarryingMul>::carrying_mul(*self, *other, zero_v);
(lo, !<Self as const_num_traits::Zero>::is_zero(&hi))
}
pub fn checked_mul(&self, other: &Self) -> Option<Self> {
let (res, overflow) = self.overflowing_mul(other);
if overflow { None } else { Some(res) }
}
}
impl<T, const CAP: usize> CheckedAdd for HeaplessBigInt<T, CAP, Nct>
where
T: MachineWord,
{
type Output = Self;
fn checked_add(self, v: Self) -> Option<Self> {
Self::checked_add(&self, &v)
}
}
impl<T, const CAP: usize> CheckedMul for HeaplessBigInt<T, CAP, Nct>
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
type Output = Self;
fn checked_mul(self, v: Self) -> Option<Self> {
Self::checked_mul(&self, &v)
}
}
fn trim_content<T: MachineWord, const CAP: usize, P: Personality>(
mut v: HeaplessBigInt<T, CAP, P>,
) -> HeaplessBigInt<T, CAP, P> {
let mut new_len: u16 = 0;
let mut i = 0;
while i < v.len as usize {
if !is_zero(&v.limbs[i]) {
new_len = (i + 1) as u16;
}
i += 1;
}
v.len = new_len;
v
}
impl<T: MachineWord, const CAP: usize> HeaplessBigInt<T, CAP, Nct> {
#[inline]
pub fn trim(self) -> Self {
trim_content(self)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Add<&HeaplessBigInt<T, CAP, P>>
for &HeaplessBigInt<T, CAP, P>
{
type Output = HeaplessBigInt<T, CAP, P>;
fn add(self, other: &HeaplessBigInt<T, CAP, P>) -> Self::Output {
let (res, overflow) = self.overflowing_add(other);
panic_on_overflow_if_nct::<P>(overflow, "HeaplessBigInt::add overflow");
res
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Sub<&HeaplessBigInt<T, CAP, P>>
for &HeaplessBigInt<T, CAP, P>
{
type Output = HeaplessBigInt<T, CAP, P>;
fn sub(self, other: &HeaplessBigInt<T, CAP, P>) -> Self::Output {
let (res, borrow) = self.overflowing_sub(other);
panic_on_overflow_if_nct::<P>(borrow, "HeaplessBigInt::sub underflow");
res
}
}
impl<T: MachineWord + CarryingMul<Unsigned = T, Output = T>, const CAP: usize, P: Personality>
core::ops::Mul<&HeaplessBigInt<T, CAP, P>> for &HeaplessBigInt<T, CAP, P>
{
type Output = HeaplessBigInt<T, CAP, P>;
fn mul(self, other: &HeaplessBigInt<T, CAP, P>) -> Self::Output {
let (res, overflow) = self.overflowing_mul(other);
panic_on_overflow_if_nct::<P>(overflow, "HeaplessBigInt::mul overflow");
res
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Add
for HeaplessBigInt<T, CAP, P>
{
type Output = Self;
fn add(self, other: Self) -> Self {
(&self).add(&other)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Add<&HeaplessBigInt<T, CAP, P>>
for HeaplessBigInt<T, CAP, P>
{
type Output = Self;
fn add(self, other: &Self) -> Self {
(&self).add(other)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Add<HeaplessBigInt<T, CAP, P>>
for &HeaplessBigInt<T, CAP, P>
{
type Output = HeaplessBigInt<T, CAP, P>;
fn add(self, other: HeaplessBigInt<T, CAP, P>) -> Self::Output {
self.add(&other)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Sub
for HeaplessBigInt<T, CAP, P>
{
type Output = Self;
fn sub(self, other: Self) -> Self {
(&self).sub(&other)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Sub<&HeaplessBigInt<T, CAP, P>>
for HeaplessBigInt<T, CAP, P>
{
type Output = Self;
fn sub(self, other: &Self) -> Self {
(&self).sub(other)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> core::ops::Sub<HeaplessBigInt<T, CAP, P>>
for &HeaplessBigInt<T, CAP, P>
{
type Output = HeaplessBigInt<T, CAP, P>;
fn sub(self, other: HeaplessBigInt<T, CAP, P>) -> Self::Output {
self.sub(&other)
}
}
impl<T: MachineWord + CarryingMul<Unsigned = T, Output = T>, const CAP: usize, P: Personality>
core::ops::Mul for HeaplessBigInt<T, CAP, P>
{
type Output = Self;
fn mul(self, other: Self) -> Self {
(&self).mul(&other)
}
}
impl<T: MachineWord + CarryingMul<Unsigned = T, Output = T>, const CAP: usize, P: Personality>
core::ops::Mul<&HeaplessBigInt<T, CAP, P>> for HeaplessBigInt<T, CAP, P>
{
type Output = Self;
fn mul(self, other: &Self) -> Self {
(&self).mul(other)
}
}
impl<T: MachineWord + CarryingMul<Unsigned = T, Output = T>, const CAP: usize, P: Personality>
core::ops::Mul<HeaplessBigInt<T, CAP, P>> for &HeaplessBigInt<T, CAP, P>
{
type Output = HeaplessBigInt<T, CAP, P>;
fn mul(self, other: HeaplessBigInt<T, CAP, P>) -> Self::Output {
self.mul(&other)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> WrappingAdd for HeaplessBigInt<T, CAP, P> {
type Output = Self;
fn wrapping_add(self, v: Self) -> Self::Output {
Self::wrapping_add(&self, &v)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> WrappingSub for HeaplessBigInt<T, CAP, P> {
type Output = Self;
fn wrapping_sub(self, v: Self) -> Self::Output {
Self::wrapping_sub(&self, &v)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> OverflowingAdd
for HeaplessBigInt<T, CAP, P>
{
type Output = Self;
fn overflowing_add(self, v: Self) -> (Self::Output, bool) {
Self::overflowing_add(&self, &v)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> OverflowingSub
for HeaplessBigInt<T, CAP, P>
{
type Output = Self;
fn overflowing_sub(self, v: Self) -> (Self::Output, bool) {
Self::overflowing_sub(&self, &v)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> WrappingAdd for &HeaplessBigInt<T, CAP, P> {
type Output = HeaplessBigInt<T, CAP, P>;
fn wrapping_add(self, v: Self) -> Self::Output {
HeaplessBigInt::wrapping_add(self, v)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> WrappingSub for &HeaplessBigInt<T, CAP, P> {
type Output = HeaplessBigInt<T, CAP, P>;
fn wrapping_sub(self, v: Self) -> Self::Output {
HeaplessBigInt::wrapping_sub(self, v)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> OverflowingAdd
for &HeaplessBigInt<T, CAP, P>
{
type Output = HeaplessBigInt<T, CAP, P>;
fn overflowing_add(self, v: Self) -> (Self::Output, bool) {
HeaplessBigInt::overflowing_add(self, v)
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> OverflowingSub
for &HeaplessBigInt<T, CAP, P>
{
type Output = HeaplessBigInt<T, CAP, P>;
fn overflowing_sub(self, v: Self) -> (Self::Output, bool) {
HeaplessBigInt::overflowing_sub(self, v)
}
}
impl<T, const CAP: usize, P: Personality> WrappingMul for HeaplessBigInt<T, CAP, P>
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
type Output = Self;
fn wrapping_mul(self, v: Self) -> Self::Output {
Self::wrapping_mul(&self, &v)
}
}
impl<T, const CAP: usize, P: Personality> WrappingMul for &HeaplessBigInt<T, CAP, P>
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
type Output = HeaplessBigInt<T, CAP, P>;
fn wrapping_mul(self, v: Self) -> Self::Output {
HeaplessBigInt::wrapping_mul(self, v)
}
}
impl<T, const CAP: usize, P: Personality> OverflowingMul for HeaplessBigInt<T, CAP, P>
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
type Output = Self;
fn overflowing_mul(self, v: Self) -> (Self::Output, bool) {
Self::overflowing_mul(&self, &v)
}
}
impl<T, const CAP: usize, P: Personality> OverflowingMul for &HeaplessBigInt<T, CAP, P>
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
type Output = HeaplessBigInt<T, CAP, P>;
fn overflowing_mul(self, v: Self) -> (Self::Output, bool) {
HeaplessBigInt::overflowing_mul(self, v)
}
}
impl<T, const CAP: usize, P: Personality> CarryingAdd for HeaplessBigInt<T, CAP, P>
where
T: MachineWord,
{
type Output = Self;
fn carrying_add(self, rhs: Self, carry_in: bool) -> (Self::Output, bool) {
let out_len = core::cmp::max(self.len as usize, rhs.len as usize);
let mut out_limbs = [zero::<T>(); CAP];
let mut carry = carry_in;
let mut i = 0;
while i < out_len {
let (sum, c) = <T as CarryingAdd>::carrying_add(self.limbs[i], rhs.limbs[i], carry);
out_limbs[i] = sum;
carry = c;
i += 1;
}
(
HeaplessBigInt {
limbs: out_limbs,
len: out_len as u16,
_p: PhantomData,
},
carry,
)
}
}
impl<T, const CAP: usize, P: Personality> BorrowingSub for HeaplessBigInt<T, CAP, P>
where
T: MachineWord,
{
type Output = Self;
fn borrowing_sub(self, rhs: Self, borrow_in: bool) -> (Self::Output, bool) {
let out_len = core::cmp::max(self.len as usize, rhs.len as usize);
let mut out_limbs = [zero::<T>(); CAP];
let mut borrow = borrow_in;
let mut i = 0;
while i < out_len {
let (diff, br) =
<T as BorrowingSub>::borrowing_sub(self.limbs[i], rhs.limbs[i], borrow);
out_limbs[i] = diff;
borrow = br;
i += 1;
}
(
HeaplessBigInt {
limbs: out_limbs,
len: out_len as u16,
_p: PhantomData,
},
borrow,
)
}
}
impl<T, const CAP: usize, P: Personality> CarryingMul for HeaplessBigInt<T, CAP, P>
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
type Unsigned = Self;
type Output = Self;
fn carrying_mul(self, rhs: Self, carry: Self) -> (Self::Unsigned, Self::Output) {
let zero_v = <Self as const_num_traits::Zero>::zero();
self.carrying_mul_add(rhs, carry, zero_v)
}
fn carrying_mul_add(self, rhs: Self, carry: Self, add: Self) -> (Self::Unsigned, Self::Output) {
let w = core::cmp::max(
core::cmp::max(self.len as usize, rhs.len as usize),
core::cmp::max(carry.len as usize, add.len as usize),
);
let mut lo_limbs = [zero::<T>(); CAP];
let mut hi_limbs = [zero::<T>(); CAP];
let a_n = self.len as usize;
let b_n = rhs.len as usize;
let mut i = 0;
while i < a_n {
let mut c = zero::<T>();
let mut j = 0;
while j < b_n {
let pos = i + j;
let (t_lo, t_hi) = <T as CarryingMul>::carrying_mul(self.limbs[i], rhs.limbs[j], c);
let existing = if pos < w {
lo_limbs[pos]
} else {
hi_limbs[pos - w]
};
let (sum, c1) = <T as CarryingAdd>::carrying_add(existing, t_lo, false);
if pos < w {
lo_limbs[pos] = sum;
} else {
hi_limbs[pos - w] = sum;
}
let (new_c, _) = <T as CarryingAdd>::carrying_add(t_hi, zero::<T>(), c1);
c = new_c;
j += 1;
}
let tail = i + b_n;
if tail < w {
let (sum, _) = <T as CarryingAdd>::carrying_add(lo_limbs[tail], c, false);
lo_limbs[tail] = sum;
} else {
let (sum, _) = <T as CarryingAdd>::carrying_add(hi_limbs[tail - w], c, false);
hi_limbs[tail - w] = sum;
}
i += 1;
}
for src in [&carry, &add] {
let mut cin = false;
let mut i = 0;
while i < w {
let (sum, c) = <T as CarryingAdd>::carrying_add(lo_limbs[i], src.limbs[i], cin);
lo_limbs[i] = sum;
cin = c;
i += 1;
}
let mut i = 0;
while cin && i < w {
let (sum, c) = <T as CarryingAdd>::carrying_add(hi_limbs[i], zero::<T>(), true);
hi_limbs[i] = sum;
cin = c;
i += 1;
}
}
let lo = HeaplessBigInt {
limbs: lo_limbs,
len: w as u16,
_p: PhantomData,
};
let hi = HeaplessBigInt {
limbs: hi_limbs,
len: w as u16,
_p: PhantomData,
};
(lo, hi)
}
}
#[inline]
pub(crate) fn zero_tail_ok<T: MachineWord>(limbs: &[T], used: usize) -> bool {
let mut i = used;
while i < limbs.len() {
if !is_zero(&limbs[i]) {
return false;
}
i += 1;
}
true
}