use core::ops::{Neg, Sub, SubAssign};
use ref_cast::RefCast;
#[cfg(feature = "ct-maybe")]
use subtle::{Choice, ConditionallySelectable};
use crate::{Digit, Modular, Montgomery, PrimeModular, SignedDoubleDigit, Unsigned, Wrapping};
use crate::numbers::{Array, Bits, Number};
#[inline]
pub fn sbb(a: Digit, b: Digit, acc: &mut SignedDoubleDigit) -> Digit {
*acc += a as SignedDoubleDigit;
*acc -= b as SignedDoubleDigit;
let lo = *acc as Digit;
*acc >>= Digit::BITS;
lo
}
pub fn sub_assign_borrow(a: &mut [Digit], b: &[Digit]) -> Digit {
debug_assert!(a.len() >= b.len());
let mut borrow = 0;
let (a_lo, a_hi) = a.split_at_mut(b.len());
for (a, b) in a_lo.iter_mut().zip(b) {
*a = sbb(*a, *b, &mut borrow);
}
if borrow != 0 {
for a in a_hi {
*a = sbb(*a, 0, &mut borrow);
#[cfg(not(feature = "ct-maybe"))] {
if borrow == 0 {
break;
}
}
}
}
borrow as Digit
}
impl<T, const D: usize, const E: usize> SubAssign<&T> for Wrapping<Unsigned<D, E>>
where
T: Number,
{
fn sub_assign(&mut self, subtrahend: &T) {
sub_assign_borrow(&mut self.0, subtrahend);
}
}
impl<const D: usize, const E: usize> Sub for &Wrapping<Unsigned<D, E>>
{
type Output = Wrapping<Unsigned<D, E>>;
fn sub(self, subtrahend: Self) -> Self::Output {
let mut difference = self.clone();
difference -= subtrahend;
difference
}
}
impl<const D: usize, const E: usize> Neg for &Wrapping<Unsigned<D, E>> {
type Output = Wrapping<Unsigned<D, E>>;
fn neg(self) -> Self::Output {
&Self::Output::zero() - self
}
}
impl<const D: usize, const E: usize> Unsigned<D, E> {
pub fn wrapping_neg(&self) -> Self {
Wrapping::ref_cast(self).neg().0
}
pub fn checked_sub(&self, subtrahend: &Self) -> Option<Self> {
let mut difference = self.clone();
let borrow = sub_assign_borrow(&mut difference, subtrahend);
(borrow != 0).then(|| difference)
}
pub fn wrapping_sub_assign<T: Number>(&mut self, subtrahend: &T) {
*Wrapping::ref_cast_mut(self) -= Wrapping::ref_cast(subtrahend);
}
pub fn wrapping_sub(&self, subtrahend: &Self) -> Self {
let mut difference = self.clone();
difference.wrapping_sub_assign(subtrahend);
difference
}
}
impl<T, const D: usize, const E: usize, const L: usize> SubAssign<&T> for Wrapping<Array<D, E, L>>
where
T: Number,
{
fn sub_assign(&mut self, other: &T) {
debug_assert!(self.len() >= other.len());
sub_assign_borrow(&mut self.0, other);
}
}
impl<const D: usize, const E: usize, const L: usize> Sub for &Wrapping<Array<D, E, L>>
{
type Output = Wrapping<Array<D, E, L>>;
fn sub(self, other: Self) -> Self::Output {
let mut difference = self.clone();
difference -= other;
difference
}
}
impl<const D: usize, const E: usize, const L: usize> Array<D, E, L> {
pub fn wrapping_sub_assign<T: Number>(&mut self, subtrahend: &T) {
*Wrapping::ref_cast_mut(self) -= Wrapping::ref_cast(subtrahend);
}
}
impl<'a, 'n, const D: usize, const E: usize> SubAssign<&'a Self> for Modular<'n, D, E> {
fn sub_assign(&mut self, subtrahend: &'a Self) {
debug_assert_eq!(**self.n, **subtrahend.n);
#[allow(non_snake_case)]
let G = self.n.wrapping_add(&self.n);
let borrow = sub_assign_borrow(&mut self.x, &subtrahend.x) as u8;
#[cfg(not(feature = "ct-maybe"))]
if borrow != 0 {
self.x.wrapping_add(&G);
}
#[cfg(feature = "ct-maybe")] {
self.x = Unsigned::conditional_select(
&self.x,
&self.x.wrapping_add(&G),
Choice::from(borrow)
)
}
}
}
impl<'a, 'n, const D: usize, const E: usize> Sub for &'a Modular<'n, D, E> {
type Output = Modular<'n, D, E>;
fn sub(self, subtrahend: Self) -> Self::Output {
let mut difference = self.clone();
difference -= subtrahend;
difference
}
}
impl<'a, 'p, const D: usize, const E: usize> Sub for &'a PrimeModular<'p, D, E> {
type Output = PrimeModular<'p, D, E>;
fn sub(self, subtrahend: Self) -> Self::Output {
let mut difference = self.clone();
*difference.as_modular_mut() -= subtrahend.as_modular();
difference
}
}
impl<'n, const D: usize, const E: usize> Neg for &Modular<'n, D, E> {
type Output = Modular<'n, D, E>;
fn neg(self) -> Self::Output {
&Self::Output::zero(&self.n) - self
}
}
impl<'p, const D: usize, const E: usize> Neg for &PrimeModular<'p, D, E> {
type Output = PrimeModular<'p, D, E>;
fn neg(self) -> Self::Output {
&Self::Output::zero(&self.p) - self
}
}
impl<'a, 'b, const D: usize, const E: usize, const F: usize, const G: usize> SubAssign<&'b Unsigned<F, G>> for Modular<'a, D, E> {
fn sub_assign(&mut self, subtrahend: &'b Unsigned<F, G>) {
*self -= &Modular { x: subtrahend.reduce(self.n), n: self.n }
}
}
impl<'a, 'b, const D: usize, const E: usize, const F: usize, const G: usize> Sub<&'b Unsigned<F, G>> for Modular<'a, D, E> {
type Output = Self;
fn sub(self, subtrahend: &'b Unsigned<F, G>) -> Self::Output {
let mut difference = self.clone();
difference -= subtrahend;
difference
}
}
impl<'a, 'n, const D: usize, const E: usize> SubAssign<&'a Self> for Montgomery<'n, D, E> {
fn sub_assign(&mut self, subtrahend: &'a Self) {
debug_assert_eq!(**self.n, **subtrahend.n);
#[allow(non_snake_case)]
let G = self.n.wrapping_add(&self.n);
let borrow = sub_assign_borrow(&mut self.y, &subtrahend.y) as u8;
#[cfg(not(feature = "ct-maybe"))]
if borrow != 0 {
self.y.wrapping_add(&G);
}
#[cfg(feature = "ct-maybe")] {
self.y = Unsigned::conditional_select(
&self.y,
&self.y.wrapping_add(&G),
Choice::from(borrow)
)
}
}
}
impl<'a, 'n, const D: usize, const E: usize> Sub for &'a Montgomery<'n, D, E> {
type Output = Montgomery<'n, D, E>;
fn sub(self, subtrahend: Self) -> Self::Output {
let mut difference = self.clone();
difference -= subtrahend;
difference
}
}
#[cfg(test)]
mod test {
use crate::fixtures::*;
#[test]
fn sub_assign() {
let f4 = crate::F4::PRIME.into_convenient();
let one = Short64::one().modulo(&f4);
assert_eq!(crate::F4::DIGIT - one.residue().digit(), 65536);
let x = Short64::from(19900).modulo(&f4);
let minus_x = crate::F4::DIGIT - x.residue().digit();
assert_eq!(minus_x, 45637);
}
}