Skip to content

Commit

Permalink
Add a RemMixed trait and impl for Uints
Browse files Browse the repository at this point in the history
  • Loading branch information
dvdplm committed Jan 20, 2025
1 parent dc6bbbb commit 7689789
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 2 deletions.
6 changes: 6 additions & 0 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,12 @@ pub trait DivRemLimb: Sized {
fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb);
}

/// Support for calculating the remainder of two differently sized integers.
pub trait RemMixed<Reductor, Tail>: Sized {
/// Calculate the remainder of `self` by the `reductor`.
fn rem_mixed(&self, reductor: &NonZero<Reductor>) -> Reductor;
}

/// Support for optimized division by a single limb.
pub trait RemLimb: Sized {
/// Computes `self % rhs` using a pre-made reciprocal.
Expand Down
2 changes: 1 addition & 1 deletion src/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ impl_uint_concat_split_even! {
U16384,
}

// Implement mixed concat and split for combinations not implemented by
// Implement mixed concat, split and reduce for combinations not implemented by
// impl_uint_concat_split_even. The numbers represent the size of each
// component Uint in multiple of 64 bits. For example,
// (U256, [1, 3]) will allow splitting U256 into (U64, U192) as well as
Expand Down
47 changes: 46 additions & 1 deletion src/uint/div.rs
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,11 @@ impl<const LIMBS: usize> RemLimb for Uint<LIMBS> {

#[cfg(test)]
mod tests {
use crate::{Limb, NonZero, Uint, Word, U128, U256, U64};
use core::marker::PhantomData;

use crate::{
ConcatMixed, Limb, NonZero, RemMixed, Uint, Word, Zero, U1024, U128, U256, U64, U896,
};

#[cfg(feature = "rand")]
use {
Expand Down Expand Up @@ -1145,4 +1149,45 @@ mod tests {
assert_eq!(&a % b, c);
assert_eq!(&a % &b, c);
}

#[test]
fn rem_mixed() {
let x= U1024::from_be_hex("3740C11DB8F260753BC6B97DD2B8746D3E2694412772AC6ABD975119EE0A6190F27F6F0969BCA069D8D151031AF83EE2283CC2E3E4FADBBDB9EEDBF0B8F4C1FD51912C0D329FDC37D49176DB0A1A2D17E5E6D4F9F6B217FE9412EAA2F881F7027A831C1B06D31D3618D218D6E667DBD85BFC7B6B6B93422D52516989376AA29A");
let y = U128::from_u64(1234567890987654321);
let rem = x.rem_mixed(&y.to_nz().unwrap());

let y2: U1024 = U128::concat_mixed(&y, &U896::ZERO);
let rem_control = x.rem(&NonZero::new(y2).unwrap());

assert_eq!(rem.bits(), rem_control.bits());
assert_eq!(rem.as_words(), &rem_control.as_words()[0..2]);
assert!(rem_control.as_words()[2..].iter().all(|w| *w == 0u64));
}

#[test]
fn rem_mixed_through_traits() {
struct A<T, U, V> {
t: T,
u: U,
_phantom: PhantomData<V>,
}
impl<T, U, V> A<T, U, V>
where
T: RemMixed<U, V>,
U: Clone + Zero,
U: ConcatMixed<V>,
{
fn reduce_t_by_u(&self) -> U {
let rhs = &NonZero::new(self.u.clone()).unwrap();
self.t.rem_mixed(rhs)
}
}

let a = A {
t: U1024::from(1234567890u64),
u: U128::from(456u64),
_phantom: PhantomData,
};
assert_eq!(a.reduce_t_by_u(), U128::from(330u64));
}
}
7 changes: 7 additions & 0 deletions src/uint/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ macro_rules! impl_uint_concat_split_mixed {
self.split_mixed()
}
}

impl $crate::traits::RemMixed<Uint<{ U64::LIMBS * $size }>, Uint<{ <$name>::LIMBS - U64::LIMBS * $size }>> for $name
{
fn rem_mixed(&self, reductor: &NonZero<Uint<{ U64::LIMBS * $size }>>) -> Uint<{ U64::LIMBS * $size }> {
self.div_rem_vartime(reductor).1
}
}
};
($name:ident, [ $($size:literal),+ ]) => {
$(
Expand Down

0 comments on commit 7689789

Please sign in to comment.