Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Int - vartime division operations #725

Closed
wants to merge 13 commits into from
2 changes: 1 addition & 1 deletion src/const_choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ impl<const LIMBS: usize> ConstCtOption<Uint<LIMBS>> {
/// Returns the contained value, interpreting the underlying [`Uint`] value as an [`Int`].
#[inline]
pub const fn as_int(&self) -> ConstCtOption<Int<LIMBS>> {
ConstCtOption::new(Int::from_bits(self.value), self.is_some)
ConstCtOption::new(self.value.as_int(), self.is_some)
}
}

Expand Down
257 changes: 185 additions & 72 deletions src/int/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ impl<const LIMBS: usize> Int<LIMBS> {
ConstCtOption::new(value, overflow.not())
}

/// Perform `self + rhs`, returns the result, as well as a flag indicating whether the
/// addition overflowed.
/// Perform addition, raising the `overflow` flag on overflow.
pub const fn overflowing_add(&self, rhs: &Self) -> (Self, ConstChoice) {
// Step 1. add operands
let res = Self(self.0.wrapping_add(&rhs.0));
Expand All @@ -31,6 +30,7 @@ impl<const LIMBS: usize> Int<LIMBS> {
.eq(rhs.is_negative())
.and(self_msb.ne(res.is_negative()));

// Step 3. Construct result
(res, overflow)
}

Expand Down Expand Up @@ -106,107 +106,220 @@ impl<const LIMBS: usize> WrappingAdd for Int<LIMBS> {

#[cfg(test)]
mod tests {
use crate::{ConstChoice, I128, U128};

#[cfg(test)]
mod tests {
use crate::{I128, U128};
#[test]
fn checked_add() {
let min_plus_one = I128 {
0: I128::MIN.0.wrapping_add(&I128::ONE.0),
};
let max_minus_one = I128 {
0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
};
let two = I128 {
0: U128::from(2u32),
};

#[test]
fn checked_add() {
let min_plus_one = I128 {
0: I128::MIN.0.wrapping_add(&I128::ONE.0),
};
let max_minus_one = I128 {
0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
};
let two = I128 {
0: U128::from(2u32),
};
// lhs = MIN

// lhs = MIN
let result = I128::MIN.checked_add(&I128::MIN);
assert!(bool::from(result.is_none()));

let result = I128::MIN.checked_add(&I128::MIN);
assert!(bool::from(result.is_none()));
let result = I128::MIN.checked_add(&I128::MINUS_ONE);
assert!(bool::from(result.is_none()));

let result = I128::MIN.checked_add(&I128::MINUS_ONE);
assert!(bool::from(result.is_none()));
let result = I128::MIN.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MIN);

let result = I128::MIN.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MIN);
let result = I128::MIN.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), min_plus_one);

let result = I128::MIN.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), min_plus_one);
let result = I128::MIN.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), I128::MINUS_ONE);

let result = I128::MIN.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), I128::MINUS_ONE);
// lhs = -1

// lhs = -1
let result = I128::MINUS_ONE.checked_add(&I128::MIN);
assert!(bool::from(result.is_none()));

let result = I128::MINUS_ONE.checked_add(&I128::MIN);
assert!(bool::from(result.is_none()));
let result = I128::MINUS_ONE.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), two.checked_neg().unwrap());

let result = I128::MINUS_ONE.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), two.checked_neg().unwrap());
let result = I128::MINUS_ONE.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MINUS_ONE);

let result = I128::MINUS_ONE.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MINUS_ONE);
let result = I128::MINUS_ONE.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), I128::ZERO);

let result = I128::MINUS_ONE.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::MINUS_ONE.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), max_minus_one);

let result = I128::MINUS_ONE.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), max_minus_one);
// lhs = 0

// lhs = 0
let result = I128::ZERO.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), I128::MIN);

let result = I128::ZERO.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), I128::MIN);
let result = I128::ZERO.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), I128::MINUS_ONE);

let result = I128::ZERO.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), I128::MINUS_ONE);
let result = I128::ZERO.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::ZERO);

let result = I128::ZERO.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::ZERO.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), I128::ONE);

let result = I128::ZERO.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), I128::ONE);
let result = I128::ZERO.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), I128::MAX);

let result = I128::ZERO.checked_add(&I128::MAX);
assert_eq!(result.unwrap(), I128::MAX);
// lhs = 1

// lhs = 1
let result = I128::ONE.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), min_plus_one);

let result = I128::ONE.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), min_plus_one);
let result = I128::ONE.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), I128::ZERO);

let result = I128::ONE.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), I128::ZERO);
let result = I128::ONE.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::ONE);

let result = I128::ONE.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::ONE);
let result = I128::ONE.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), two);

let result = I128::ONE.checked_add(&I128::ONE);
assert_eq!(result.unwrap(), two);
let result = I128::ONE.checked_add(&I128::MAX);
assert!(bool::from(result.is_none()));

let result = I128::ONE.checked_add(&I128::MAX);
assert!(bool::from(result.is_none()));
// lhs = MAX

// lhs = MAX
let result = I128::MAX.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), I128::MINUS_ONE);

let result = I128::MAX.checked_add(&I128::MIN);
assert_eq!(result.unwrap(), I128::MINUS_ONE);
let result = I128::MAX.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), max_minus_one);

let result = I128::MAX.checked_add(&I128::MINUS_ONE);
assert_eq!(result.unwrap(), max_minus_one);
let result = I128::MAX.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MAX);

let result = I128::MAX.checked_add(&I128::ZERO);
assert_eq!(result.unwrap(), I128::MAX);
let result = I128::MAX.checked_add(&I128::ONE);
assert!(bool::from(result.is_none()));

let result = I128::MAX.checked_add(&I128::ONE);
assert!(bool::from(result.is_none()));
let result = I128::MAX.checked_add(&I128::MAX);
assert!(bool::from(result.is_none()));
}

#[test]
fn overflowing_add() {
let min_plus_one = I128 {
0: I128::MIN.0.wrapping_add(&I128::ONE.0),
};
let max_minus_one = I128 {
0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
};
let two = I128 {
0: U128::from(2u32),
};

// lhs = MIN

let (_val, overflow) = I128::MIN.overflowing_add(&I128::MIN);
assert_eq!(overflow, ConstChoice::TRUE);

let (_val, overflow) = I128::MIN.overflowing_add(&I128::MINUS_ONE);
assert_eq!(overflow, ConstChoice::TRUE);

let (val, overflow) = I128::MIN.overflowing_add(&I128::ZERO);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MIN);

let (val, overflow) = I128::MIN.overflowing_add(&I128::ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, min_plus_one);

let (val, overflow) = I128::MIN.overflowing_add(&I128::MAX);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MINUS_ONE);

// lhs = -1

let (_val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::MIN);
assert_eq!(overflow, ConstChoice::TRUE);

let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::MINUS_ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, two.wrapping_neg());

let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::ZERO);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MINUS_ONE);

let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::ZERO);

let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::MAX);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, max_minus_one);

// lhs = 0

let (val, overflow) = I128::ZERO.overflowing_add(&I128::MIN);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MIN);

let (val, overflow) = I128::ZERO.overflowing_add(&I128::MINUS_ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MINUS_ONE);

let (val, overflow) = I128::ZERO.overflowing_add(&I128::ZERO);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::ZERO);

let (val, overflow) = I128::ZERO.overflowing_add(&I128::ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::ONE);

let (val, overflow) = I128::ZERO.overflowing_add(&I128::MAX);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MAX);

// lhs = 1

let (val, overflow) = I128::ONE.overflowing_add(&I128::MIN);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, min_plus_one);

let (val, overflow) = I128::ONE.overflowing_add(&I128::MINUS_ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::ZERO);

let (val, overflow) = I128::ONE.overflowing_add(&I128::ZERO);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::ONE);

let (val, overflow) = I128::ONE.overflowing_add(&I128::ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, two);

let (_val, overflow) = I128::ONE.overflowing_add(&I128::MAX);
assert_eq!(overflow, ConstChoice::TRUE);

// lhs = MAX

let (val, overflow) = I128::MAX.overflowing_add(&I128::MIN);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MINUS_ONE);

let (val, overflow) = I128::MAX.overflowing_add(&I128::MINUS_ONE);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, max_minus_one);

let (val, overflow) = I128::MAX.overflowing_add(&I128::ZERO);
assert_eq!(overflow, ConstChoice::FALSE);
assert_eq!(val, I128::MAX);

let (_val, overflow) = I128::MAX.overflowing_add(&I128::ONE);
assert_eq!(overflow, ConstChoice::TRUE);

let result = I128::MAX.checked_add(&I128::MAX);
assert!(bool::from(result.is_none()));
}
let (_val, overflow) = I128::MAX.overflowing_add(&I128::MAX);
assert_eq!(overflow, ConstChoice::TRUE);
}
}
6 changes: 5 additions & 1 deletion src/int/bit_and.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,14 @@ mod tests {
#[test]
fn checked_and_ok() {
assert_eq!(I128::ZERO.checked_and(&I128::ONE).unwrap(), I128::ZERO);
assert_eq!(I128::ONE.checked_and(&I128::ONE).unwrap(), I128::ONE);
assert_eq!(I128::MAX.checked_and(&I128::ONE).unwrap(), I128::ONE);
}

#[test]
fn overlapping_and_ok() {
fn wrapping_and_ok() {
assert_eq!(I128::ZERO.wrapping_and(&I128::ONE), I128::ZERO);
assert_eq!(I128::ONE.wrapping_and(&I128::ONE), I128::ONE);
assert_eq!(I128::MAX.wrapping_and(&I128::ONE), I128::ONE);
}
}
6 changes: 5 additions & 1 deletion src/int/bit_or.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,14 @@ mod tests {
#[test]
fn checked_or_ok() {
assert_eq!(I128::ZERO.checked_or(&I128::ONE).unwrap(), I128::ONE);
assert_eq!(I128::ONE.checked_or(&I128::ONE).unwrap(), I128::ONE);
assert_eq!(I128::MAX.checked_or(&I128::ONE).unwrap(), I128::MAX);
}

#[test]
fn overlapping_or_ok() {
fn wrapping_or_ok() {
assert_eq!(I128::ZERO.wrapping_or(&I128::ONE), I128::ONE);
assert_eq!(I128::ONE.wrapping_or(&I128::ONE), I128::ONE);
assert_eq!(I128::MAX.wrapping_or(&I128::ONE), I128::MAX);
}
}
9 changes: 8 additions & 1 deletion src/int/bit_xor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,17 @@ mod tests {
#[test]
fn checked_xor_ok() {
assert_eq!(I128::ZERO.checked_xor(&I128::ONE).unwrap(), I128::ONE);
assert_eq!(I128::ONE.checked_xor(&I128::ONE).unwrap(), I128::ZERO);
assert_eq!(
I128::MAX.checked_xor(&I128::ONE).unwrap(),
I128::MAX - I128::ONE
);
}

#[test]
fn overlapping_xor_ok() {
fn wrapping_xor_ok() {
assert_eq!(I128::ZERO.wrapping_xor(&I128::ONE), I128::ONE);
assert_eq!(I128::ONE.wrapping_xor(&I128::ONE), I128::ZERO);
assert_eq!(I128::MAX.wrapping_xor(&I128::ONE), I128::MAX - I128::ONE);
}
}
Loading
Loading