use crate::{
uint::boxed, BoxedUint, CheckedDiv, ConstantTimeSelect, DivRemLimb, Limb, NonZero, Reciprocal,
RemLimb, Wrapping,
};
use core::ops::{Div, DivAssign, Rem, RemAssign};
use subtle::{Choice, ConstantTimeEq, ConstantTimeLess, CtOption};
impl BoxedUint {
pub fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
boxed::div_limb::div_rem_limb_with_reciprocal(self, reciprocal)
}
pub fn div_rem_limb(&self, rhs: NonZero<Limb>) -> (Self, Limb) {
boxed::div_limb::div_rem_limb_with_reciprocal(self, &Reciprocal::new(rhs))
}
#[inline(always)]
pub fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
boxed::div_limb::rem_limb_with_reciprocal(self, reciprocal)
}
#[inline(always)]
pub fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
boxed::div_limb::rem_limb_with_reciprocal(self, &Reciprocal::new(rhs))
}
pub fn div_rem(&self, rhs: &NonZero<Self>) -> (Self, Self) {
self.div_rem_unchecked(rhs.as_ref())
}
pub fn rem(&self, rhs: &NonZero<Self>) -> Self {
self.div_rem(rhs).1
}
pub fn div_rem_vartime(&self, rhs: &NonZero<Self>) -> (Self, Self) {
self.div_rem_vartime_unchecked(rhs.as_ref())
}
pub fn rem_vartime(&self, rhs: &NonZero<Self>) -> Self {
debug_assert_eq!(self.bits_precision(), rhs.bits_precision());
let mb = rhs.bits();
let mut bd = self.bits_precision() - mb;
let mut rem = self.clone();
let mut c = rhs.shl_vartime(bd).expect("shift within range");
loop {
let (r, borrow) = rem.sbb(&c, Limb::ZERO);
rem = Self::ct_select(&r, &rem, !borrow.ct_eq(&Limb::ZERO));
if bd == 0 {
break rem;
}
bd -= 1;
c.shr1_assign();
}
}
pub fn wrapping_div(&self, rhs: &NonZero<Self>) -> Self {
self.div_rem(rhs).0
}
pub fn wrapping_div_vartime(&self, rhs: &NonZero<Self>) -> Self {
self.div_rem_vartime(rhs).0
}
pub fn checked_div(&self, rhs: &Self) -> CtOption<Self> {
let q = self.div_rem_unchecked(rhs).0;
CtOption::new(q, !rhs.is_zero())
}
fn div_rem_unchecked(&self, rhs: &Self) -> (Self, Self) {
debug_assert_eq!(self.bits_precision(), rhs.bits_precision());
let mb = rhs.bits();
let bits_precision = self.bits_precision();
let mut rem = self.clone();
let mut quo = Self::zero_with_precision(bits_precision);
let (mut c, _overflow) = rhs.overflowing_shl(bits_precision - mb);
let mut i = bits_precision;
let mut done = Choice::from(0u8);
loop {
let (mut r, borrow) = rem.sbb(&c, Limb::ZERO);
rem.ct_assign(&r, !(Choice::from((borrow.0 & 1) as u8) | done));
r = quo.bitor(&Self::one());
quo.ct_assign(&r, !(Choice::from((borrow.0 & 1) as u8) | done));
if i == 0 {
break;
}
i -= 1;
done = i.ct_lt(&mb);
c.shr1_assign();
quo.ct_assign(&quo.shl1(), !done);
}
(quo, rem)
}
fn div_rem_vartime_unchecked(&self, rhs: &Self) -> (Self, Self) {
debug_assert_eq!(self.bits_precision(), rhs.bits_precision());
let mb = rhs.bits_vartime();
let mut bd = self.bits_precision() - mb;
let mut remainder = self.clone();
let mut quotient = Self::zero_with_precision(self.bits_precision());
let mut c = rhs.shl_vartime(bd).expect("shift within range");
loop {
let (mut r, borrow) = remainder.sbb(&c, Limb::ZERO);
let borrow = Choice::from(borrow.0 as u8 & 1);
remainder = Self::ct_select(&r, &remainder, borrow);
r = "ient | Self::one();
quotient = Self::ct_select(&r, "ient, borrow);
if bd == 0 {
break;
}
bd -= 1;
c.shr1_assign();
quotient.shl1_assign();
}
(quotient, remainder)
}
}
impl CheckedDiv for BoxedUint {
fn checked_div(&self, rhs: &BoxedUint) -> CtOption<Self> {
self.checked_div(rhs)
}
}
impl Div<&NonZero<BoxedUint>> for &BoxedUint {
type Output = BoxedUint;
fn div(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
self.wrapping_div(rhs)
}
}
impl Div<&NonZero<BoxedUint>> for BoxedUint {
type Output = BoxedUint;
fn div(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
self.wrapping_div(rhs)
}
}
impl Div<NonZero<BoxedUint>> for &BoxedUint {
type Output = BoxedUint;
fn div(self, rhs: NonZero<BoxedUint>) -> Self::Output {
self.wrapping_div(&rhs)
}
}
impl Div<NonZero<BoxedUint>> for BoxedUint {
type Output = BoxedUint;
fn div(self, rhs: NonZero<BoxedUint>) -> Self::Output {
self.div_rem(&rhs).0
}
}
impl DivAssign<&NonZero<BoxedUint>> for BoxedUint {
fn div_assign(&mut self, rhs: &NonZero<BoxedUint>) {
*self = self.wrapping_div(rhs);
}
}
impl DivAssign<NonZero<BoxedUint>> for BoxedUint {
fn div_assign(&mut self, rhs: NonZero<BoxedUint>) {
*self = self.wrapping_div(&rhs);
}
}
impl Div<NonZero<BoxedUint>> for Wrapping<BoxedUint> {
type Output = Wrapping<BoxedUint>;
fn div(self, rhs: NonZero<BoxedUint>) -> Self::Output {
Wrapping(self.0 / rhs)
}
}
impl Div<NonZero<BoxedUint>> for &Wrapping<BoxedUint> {
type Output = Wrapping<BoxedUint>;
fn div(self, rhs: NonZero<BoxedUint>) -> Self::Output {
Wrapping(self.0.wrapping_div(&rhs))
}
}
impl Div<&NonZero<BoxedUint>> for &Wrapping<BoxedUint> {
type Output = Wrapping<BoxedUint>;
fn div(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
Wrapping(self.0.wrapping_div(rhs))
}
}
impl Div<&NonZero<BoxedUint>> for Wrapping<BoxedUint> {
type Output = Wrapping<BoxedUint>;
fn div(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
Wrapping(self.0.wrapping_div(rhs))
}
}
impl DivAssign<&NonZero<BoxedUint>> for Wrapping<BoxedUint> {
fn div_assign(&mut self, rhs: &NonZero<BoxedUint>) {
*self = Wrapping(&self.0 / rhs);
}
}
impl DivAssign<NonZero<BoxedUint>> for Wrapping<BoxedUint> {
fn div_assign(&mut self, rhs: NonZero<BoxedUint>) {
*self /= &rhs;
}
}
impl Rem<&NonZero<BoxedUint>> for &BoxedUint {
type Output = BoxedUint;
#[inline]
fn rem(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
self.rem(rhs)
}
}
impl Rem<&NonZero<BoxedUint>> for BoxedUint {
type Output = BoxedUint;
#[inline]
fn rem(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
Self::rem(&self, rhs)
}
}
impl Rem<NonZero<BoxedUint>> for &BoxedUint {
type Output = BoxedUint;
#[inline]
fn rem(self, rhs: NonZero<BoxedUint>) -> Self::Output {
self.rem(&rhs)
}
}
impl Rem<NonZero<BoxedUint>> for BoxedUint {
type Output = BoxedUint;
#[inline]
fn rem(self, rhs: NonZero<BoxedUint>) -> Self::Output {
self.rem(&rhs)
}
}
impl RemAssign<&NonZero<BoxedUint>> for BoxedUint {
fn rem_assign(&mut self, rhs: &NonZero<BoxedUint>) {
*self = Self::rem(self, rhs)
}
}
impl RemAssign<NonZero<BoxedUint>> for BoxedUint {
fn rem_assign(&mut self, rhs: NonZero<BoxedUint>) {
*self = Self::rem(self, &rhs)
}
}
impl DivRemLimb for BoxedUint {
fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
Self::div_rem_limb_with_reciprocal(self, reciprocal)
}
}
impl RemLimb for BoxedUint {
fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
Self::rem_limb_with_reciprocal(self, reciprocal)
}
}
#[cfg(test)]
mod tests {
use super::{BoxedUint, NonZero};
#[test]
fn rem() {
let n = BoxedUint::from(0xFFEECCBBAA99887766u128);
let p = NonZero::new(BoxedUint::from(997u128)).unwrap();
assert_eq!(BoxedUint::from(648u128), n.rem(&p));
}
#[test]
fn rem_vartime() {
let n = BoxedUint::from(0xFFEECCBBAA99887766u128);
let p = NonZero::new(BoxedUint::from(997u128)).unwrap();
assert_eq!(BoxedUint::from(648u128), n.rem_vartime(&p));
}
}