Skip to content

Commit

Permalink
Reverse Concat(Mixed)/Split(Mixed) argument ordering (#526)
Browse files Browse the repository at this point in the history
Changes to a "little endian" `lo, hi` convention for the ordering of
arguments to concatenation methods and the ordering of the returned
2-tuple from split methods.

This is more consistent with the rest of the crate, and the
`Uint { limbs }` array which uses a little endian ordering.

Closes #519
  • Loading branch information
tarcieri authored Dec 28, 2023
1 parent 49b54aa commit dc64fb4
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 53 deletions.
8 changes: 4 additions & 4 deletions src/modular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ mod tests {
#[test]
fn test_reducing_r2_wide() {
// Divide the value ONE^2 by R, which should equal ONE
let (hi, lo) = Modulus2::ONE.square().split();
let (lo, hi) = Modulus2::ONE.square().split();
assert_eq!(
montgomery_reduction::<{ Modulus2::LIMBS }>(
&(lo, hi),
Expand Down Expand Up @@ -157,9 +157,9 @@ mod tests {

// Computing xR mod modulus without Montgomery reduction
let (lo, hi) = x.split_mul(&Modulus2::ONE);
let c = hi.concat(&lo);
let red = c.rem_vartime(&NonZero::new(U256::ZERO.concat(&Modulus2::MODULUS)).unwrap());
let (hi, lo) = red.split();
let c = lo.concat(&hi);
let red = c.rem_vartime(&NonZero::new(Modulus2::MODULUS.0.concat(&U256::ZERO)).unwrap());
let (lo, hi) = red.split();
assert_eq!(hi, Uint::ZERO);

assert_eq!(
Expand Down
4 changes: 2 additions & 2 deletions src/modular/monty_form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ impl<const LIMBS: usize> MontyParams<LIMBS> {
// `R^2 mod modulus`, used to convert integers to Montgomery form.
let r2 = one
.square()
.rem(&NonZero(Uint::<LIMBS>::ZERO.concat(&modulus.0)))
.rem(&NonZero(modulus.0.concat(&Uint::ZERO)))
.split()
.1;
.0;

// The modular inverse should always exist, because it was ensured odd above, which also ensures it's non-zero
let inv_mod = modulus
Expand Down
45 changes: 21 additions & 24 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,49 +467,46 @@ pub trait CheckedSub<Rhs = Self>: Sized {
fn checked_sub(&self, rhs: &Rhs) -> CtOption<Self>;
}

/// Concatenate two numbers into a "wide" double-width value, using the `lo`
/// value as the least significant value.
/// Concatenate two numbers into a "wide" double-width value, using the `hi` value as the most
/// significant portion of the resulting value.
pub trait Concat: ConcatMixed<Self, MixedOutput = Self::Output> {
/// Concatenated output: twice the width of `Self`.
type Output: Integer;

/// Concatenate the two halves, with `self` as most significant and `lo`
/// as the least significant.
fn concat(&self, lo: &Self) -> Self::Output {
self.concat_mixed(lo)
/// Concatenate the two halves, with `self` as least significant and `hi` as the least
/// significant.
fn concat(&self, hi: &Self) -> Self::Output {
self.concat_mixed(hi)
}
}

/// Concatenate two numbers into a "wide" combined-width value, using the `lo`
/// value as the least significant value.
pub trait ConcatMixed<Lo: ?Sized = Self> {
/// Concatenated output: combination of `Lo` and `Self`.
/// Concatenate two numbers into a "wide" combined-width value, using the `hi` value as the most
/// significant value.
pub trait ConcatMixed<Hi: ?Sized = Self> {
/// Concatenated output: combination of `Self` and `Hi`.
type MixedOutput: Integer;

/// Concatenate the two values, with `self` as most significant and `lo`
/// as the least significant.
fn concat_mixed(&self, lo: &Lo) -> Self::MixedOutput;
/// Concatenate the two values, with `self` as least significant and `hi` as the most
/// significant.
fn concat_mixed(&self, hi: &Hi) -> Self::MixedOutput;
}

/// Split a number in half, returning the most significant half followed by
/// the least significant.
/// Split a number in half, returning the least significant half followed by the most significant.
pub trait Split: SplitMixed<Self::Output, Self::Output> {
/// Split output: high/low components of the value.
/// Split output: low/high components of the value.
type Output;

/// Split this number in half, returning its high and low components
/// respectively.
/// Split this number in half, returning its low and high components respectively.
fn split(&self) -> (Self::Output, Self::Output) {
self.split_mixed()
}
}

/// Split a number into parts, returning the most significant part followed by
/// the least significant.
pub trait SplitMixed<Hi, Lo> {
/// Split this number into parts, returning its high and low components
/// respectively.
fn split_mixed(&self) -> (Hi, Lo);
/// Split a number into parts, returning the least significant part followed by the most
/// significant.
pub trait SplitMixed<Lo, Hi> {
/// Split this number into parts, returning its low and high components respectively.
fn split_mixed(&self) -> (Lo, Hi);
}

/// Encoding support.
Expand Down
10 changes: 5 additions & 5 deletions src/uint/concat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,21 @@ mod tests {
let hi = U64::from_u64(0x0011223344556677);
let lo = U64::from_u64(0x8899aabbccddeeff);
assert_eq!(
hi.concat(&lo),
lo.concat(&hi),
U128::from_be_hex("00112233445566778899aabbccddeeff")
);
}

#[test]
fn concat_mixed() {
let a = U64::from_u64(0x0011223344556677);
let b = U128::from_u128(0x8899aabbccddeeff_8899aabbccddeeff);
let hi = U64::from_u64(0x0011223344556677);
let lo = U128::from_u128(0x8899aabbccddeeff_8899aabbccddeeff);
assert_eq!(
a.concat_mixed(&b),
lo.concat_mixed(&hi),
U192::from_be_hex("00112233445566778899aabbccddeeff8899aabbccddeeff")
);
assert_eq!(
b.concat_mixed(&a),
hi.concat_mixed(&lo),
U192::from_be_hex("8899aabbccddeeff8899aabbccddeeff0011223344556677")
);
}
Expand Down
8 changes: 4 additions & 4 deletions src/uint/from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,19 +198,19 @@ impl<const LIMBS: usize> From<Limb> for Uint<LIMBS> {

impl<const L: usize, const H: usize, const LIMBS: usize> From<(Uint<L>, Uint<H>)> for Uint<LIMBS>
where
Uint<H>: ConcatMixed<Uint<L>, MixedOutput = Uint<LIMBS>>,
Uint<L>: ConcatMixed<Uint<H>, MixedOutput = Uint<LIMBS>>,
{
fn from(nums: (Uint<L>, Uint<H>)) -> Uint<LIMBS> {
nums.1.concat_mixed(&nums.0)
nums.0.concat_mixed(&nums.1)
}
}

impl<const L: usize, const H: usize, const LIMBS: usize> From<&(Uint<L>, Uint<H>)> for Uint<LIMBS>
where
Uint<H>: ConcatMixed<Uint<L>, MixedOutput = Uint<LIMBS>>,
Uint<L>: ConcatMixed<Uint<H>, MixedOutput = Uint<LIMBS>>,
{
fn from(nums: &(Uint<L>, Uint<H>)) -> Uint<LIMBS> {
nums.1.concat_mixed(&nums.0)
nums.0.concat_mixed(&nums.1)
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/uint/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ macro_rules! impl_uint_concat_split_mixed {
{
type MixedOutput = $name;

fn concat_mixed(&self, lo: &Uint<{ U64::LIMBS * $size }>) -> Self::MixedOutput {
$crate::uint::concat::concat_mixed(lo, self)
fn concat_mixed(&self, hi: &Uint<{ U64::LIMBS * $size }>) -> Self::MixedOutput {
$crate::uint::concat::concat_mixed(self, hi)
}
}

Expand Down Expand Up @@ -107,16 +107,16 @@ macro_rules! impl_uint_concat_split_even {
{
type MixedOutput = $name;

fn concat_mixed(&self, lo: &Uint<{ <$name>::LIMBS / 2 }>) -> Self::MixedOutput {
$crate::uint::concat::concat_mixed(lo, self)
fn concat_mixed(&self, hi: &Uint<{ <$name>::LIMBS / 2 }>) -> Self::MixedOutput {
$crate::uint::concat::concat_mixed(self, hi)
}
}

impl Uint<{ <$name>::LIMBS / 2 }> {
/// Concatenate the two values, with `self` as most significant and `rhs`
/// as the least significant.
pub const fn concat(&self, lo: &Uint<{ <$name>::LIMBS / 2 }>) -> $name {
$crate::uint::concat::concat_mixed(lo, self)
pub const fn concat(&self, hi: &Uint<{ <$name>::LIMBS / 2 }>) -> $name {
$crate::uint::concat::concat_mixed(self, hi)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/uint/mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,15 +358,15 @@ mod tests {
#[test]
fn square() {
let n = U64::from_u64(0xffff_ffff_ffff_ffff);
let (hi, lo) = n.square().split();
let (lo, hi) = n.square().split();
assert_eq!(lo, U64::from_u64(1));
assert_eq!(hi, U64::from_u64(0xffff_ffff_ffff_fffe));
}

#[test]
fn square_larger() {
let n = U256::MAX;
let (hi, lo) = n.square().split();
let (lo, hi) = n.square().split();
assert_eq!(lo, U256::ONE);
assert_eq!(hi, U256::MAX.wrapping_sub(&U256::ONE));
}
Expand Down
11 changes: 5 additions & 6 deletions src/uint/split.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use crate::{Limb, Uint};

/// Split this number in half, returning its high and low components
/// respectively.
/// Split this number in half, returning its low and high components respectively.
#[inline]
pub(crate) const fn split_mixed<const L: usize, const H: usize, const O: usize>(
n: &Uint<O>,
) -> (Uint<H>, Uint<L>) {
) -> (Uint<L>, Uint<H>) {
let top = L + H;
let top = if top < O { top } else { O };
let mut lo = [Limb::ZERO; L];
Expand All @@ -21,7 +20,7 @@ pub(crate) const fn split_mixed<const L: usize, const H: usize, const O: usize>(
i += 1;
}

(Uint { limbs: hi }, Uint { limbs: lo })
(Uint { limbs: lo }, Uint { limbs: hi })
}

#[cfg(test)]
Expand All @@ -30,8 +29,8 @@ mod tests {

#[test]
fn split() {
let (hi, lo) = U128::from_be_hex("00112233445566778899aabbccddeeff").split();
assert_eq!(hi, U64::from_u64(0x0011223344556677));
let (lo, hi) = U128::from_be_hex("00112233445566778899aabbccddeeff").split();
assert_eq!(lo, U64::from_u64(0x8899aabbccddeeff));
assert_eq!(hi, U64::from_u64(0x0011223344556677));
}
}

0 comments on commit dc64fb4

Please sign in to comment.