Skip to content

Commit 0af57a6

Browse files
Lighter-weight support for Uint concat, split operations (#1191)
This also moves `EncodedUint` <-> `[u8; N]` conversion out of the macro rules for different Uint sizes. The `Concat`, `Split`, and `SplitMixed` traits are changed to define the output types only, while the `ConcatMixed` trait is removed as unnecessary. In all, this seems to have a positive effect on build times. New tests are added to ensure that result types can be inferred when it is useful. Related to #1095 --------- Signed-off-by: Andrew Whitehead <cywolf@gmail.com>
1 parent 5b5f80b commit 0af57a6

14 files changed

Lines changed: 271 additions & 202 deletions

File tree

src/int/gcd.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ impl<const LIMBS: usize> Xgcd for OddInt<LIMBS> {
323323
#[cfg(all(test, not(miri)))]
324324
mod tests {
325325
use crate::int::gcd::{IntXgcdOutput, NonZeroIntXgcdOutput, OddIntXgcdOutput};
326-
use crate::{ConcatMixed, Gcd, Int, Uint};
326+
use crate::{Concat, Gcd, Int, Uint};
327327

328328
impl<const LIMBS: usize> From<NonZeroIntXgcdOutput<LIMBS>> for IntXgcdOutput<LIMBS> {
329329
fn from(value: NonZeroIntXgcdOutput<LIMBS>) -> Self {
@@ -419,7 +419,7 @@ mod tests {
419419
rhs: Int<LIMBS>,
420420
output: IntXgcdOutput<LIMBS>,
421421
) where
422-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
422+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
423423
{
424424
let gcd = lhs.gcd(&rhs);
425425
assert_eq!(gcd, output.gcd);
@@ -455,21 +455,21 @@ mod tests {
455455
mod test_int_xgcd {
456456
use crate::int::gcd::tests::xgcd_test;
457457
use crate::{
458-
ConcatMixed, Gcd, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096,
459-
U8192, Uint,
458+
Concat, Gcd, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192,
459+
Uint,
460460
};
461461

462462
fn test<const LIMBS: usize, const DOUBLE: usize>(lhs: Int<LIMBS>, rhs: Int<LIMBS>)
463463
where
464-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
464+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
465465
Int<LIMBS>: Gcd<Output = Uint<LIMBS>>,
466466
{
467467
xgcd_test(lhs, rhs, lhs.xgcd(&rhs));
468468
}
469469

470470
fn run_tests<const LIMBS: usize, const DOUBLE: usize>()
471471
where
472-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
472+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
473473
Int<LIMBS>: Gcd<Output = Uint<LIMBS>>,
474474
{
475475
test(Int::MIN, Int::MIN);
@@ -516,21 +516,20 @@ mod tests {
516516
mod test_nonzero_int_xgcd {
517517
use crate::int::gcd::tests::xgcd_test;
518518
use crate::{
519-
ConcatMixed, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192,
520-
Uint,
519+
Concat, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192, Uint,
521520
};
522521

523522
fn test<const LIMBS: usize, const DOUBLE: usize>(lhs: Int<LIMBS>, rhs: Int<LIMBS>)
524523
where
525-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
524+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
526525
{
527526
let output = lhs.to_nz().unwrap().xgcd(&rhs.to_nz().unwrap());
528527
xgcd_test(lhs, rhs, output.into());
529528
}
530529

531530
fn run_tests<const LIMBS: usize, const DOUBLE: usize>()
532531
where
533-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
532+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
534533
{
535534
test(Int::MIN, Int::MIN);
536535
test(Int::MIN, Int::MINUS_ONE);
@@ -567,21 +566,20 @@ mod tests {
567566
mod test_odd_int_xgcd {
568567
use crate::int::gcd::tests::xgcd_test;
569568
use crate::{
570-
ConcatMixed, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192,
571-
Uint,
569+
Concat, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192, Uint,
572570
};
573571

574572
fn test<const LIMBS: usize, const DOUBLE: usize>(lhs: Int<LIMBS>, rhs: Int<LIMBS>)
575573
where
576-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
574+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
577575
{
578576
let output = lhs.to_odd().unwrap().xgcd(&rhs.to_nz().unwrap());
579577
xgcd_test(lhs, rhs, output.into());
580578
}
581579

582580
fn run_tests<const LIMBS: usize, const DOUBLE: usize>()
583581
where
584-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
582+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
585583
{
586584
let neg_max = Int::MAX.wrapping_neg();
587585
test(neg_max, neg_max);

src/int/mul.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! [`Int`] multiplication operations.
22
33
use crate::{
4-
Checked, CheckedMul, Choice, ConcatMixed, CtOption, Int, Mul, MulAssign, Uint, WrappingMul,
4+
Checked, CheckedMul, Choice, Concat, CtOption, Int, Mul, MulAssign, Uint, WrappingMul,
55
};
66

77
impl<const LIMBS: usize> Int<LIMBS> {
@@ -54,7 +54,7 @@ impl<const LIMBS: usize> Int<LIMBS> {
5454
rhs: &Int<RHS_LIMBS>,
5555
) -> Int<WIDE_LIMBS>
5656
where
57-
Uint<LIMBS>: ConcatMixed<Uint<RHS_LIMBS>, MixedOutput = Uint<WIDE_LIMBS>>,
57+
Uint<LIMBS>: Concat<RHS_LIMBS, Output = Uint<WIDE_LIMBS>>,
5858
{
5959
let (lhs_abs, lhs_sign) = self.abs_sign();
6060
let (rhs_abs, rhs_sign) = rhs.abs_sign();
@@ -112,7 +112,7 @@ impl<const LIMBS: usize> Int<LIMBS> {
112112
#[must_use]
113113
pub fn widening_square<const WIDE_LIMBS: usize>(&self) -> Uint<WIDE_LIMBS>
114114
where
115-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<WIDE_LIMBS>>,
115+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
116116
{
117117
self.abs().widening_square()
118118
}

src/int/mul_unsigned.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{CheckedMul, Choice, ConcatMixed, CtOption, Int, Uint};
1+
use crate::{CheckedMul, Choice, Concat, CtOption, Int, Uint};
22
use core::ops::Mul;
33

44
impl<const LIMBS: usize> Int<LIMBS> {
@@ -81,7 +81,7 @@ impl<const LIMBS: usize> Int<LIMBS> {
8181
rhs: &Uint<RHS_LIMBS>,
8282
) -> Int<WIDE_LIMBS>
8383
where
84-
Uint<LIMBS>: ConcatMixed<Uint<RHS_LIMBS>, MixedOutput = Uint<WIDE_LIMBS>>,
84+
Uint<LIMBS>: Concat<RHS_LIMBS, Output = Uint<WIDE_LIMBS>>,
8585
{
8686
let (lhs_abs, lhs_sign) = self.abs_sign();
8787
let product_abs = lhs_abs.concatenating_mul(rhs);

src/modular/bingcd/xgcd.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
366366
#[cfg(all(test, not(miri)))]
367367
mod tests {
368368
use crate::modular::bingcd::xgcd::PatternXgcdOutput;
369-
use crate::{ConcatMixed, Uint};
369+
use crate::{Concat, Uint};
370370
use core::ops::Div;
371371

372372
mod test_extract_quotients {
@@ -570,7 +570,7 @@ mod tests {
570570
rhs: Uint<LIMBS>,
571571
output: PatternXgcdOutput<LIMBS>,
572572
) where
573-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
573+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
574574
{
575575
// Test the gcd
576576
assert_eq!(lhs.gcd(&rhs), output.gcd, "{lhs} {rhs}");
@@ -599,23 +599,22 @@ mod tests {
599599
mod test_binxgcd_nz {
600600
use crate::modular::bingcd::xgcd::tests::test_xgcd;
601601
use crate::{
602-
ConcatMixed, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192,
603-
Uint,
602+
Concat, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192, Uint,
604603
};
605604

606605
fn binxgcd_nz_test<const LIMBS: usize, const DOUBLE: usize>(
607606
lhs: Uint<LIMBS>,
608607
rhs: Uint<LIMBS>,
609608
) where
610-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
609+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
611610
{
612611
let output = lhs.to_odd().unwrap().binxgcd_nz(&rhs.to_nz().unwrap());
613612
test_xgcd(lhs, rhs, output);
614613
}
615614

616615
fn binxgcd_nz_tests<const LIMBS: usize, const DOUBLE: usize>()
617616
where
618-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
617+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
619618
{
620619
let max_int = *Int::MAX.as_uint();
621620
let int_abs_min = Int::MIN.abs();
@@ -651,15 +650,14 @@ mod tests {
651650
mod test_classic_binxgcd {
652651
use crate::modular::bingcd::xgcd::tests::test_xgcd;
653652
use crate::{
654-
ConcatMixed, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192,
655-
Uint,
653+
Concat, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192, Uint,
656654
};
657655

658656
fn classic_binxgcd_test<const LIMBS: usize, const DOUBLE: usize>(
659657
lhs: Uint<LIMBS>,
660658
rhs: Uint<LIMBS>,
661659
) where
662-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
660+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
663661
{
664662
let output = lhs
665663
.to_odd()
@@ -671,7 +669,7 @@ mod tests {
671669

672670
fn classic_binxgcd_tests<const LIMBS: usize, const DOUBLE: usize>()
673671
where
674-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
672+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
675673
{
676674
let max_int = *Int::MAX.as_uint();
677675

@@ -704,13 +702,12 @@ mod tests {
704702
use crate::modular::bingcd::xgcd::tests::test_xgcd;
705703
use crate::modular::bingcd::xgcd::{DOUBLE_SUMMARY_LIMBS, SUMMARY_BITS, SUMMARY_LIMBS};
706704
use crate::{
707-
ConcatMixed, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192,
708-
Uint,
705+
Concat, Int, U64, U128, U192, U256, U384, U512, U768, U1024, U2048, U4096, U8192, Uint,
709706
};
710707

711708
fn test<const LIMBS: usize, const DOUBLE: usize>(lhs: Uint<LIMBS>, rhs: Uint<LIMBS>)
712709
where
713-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
710+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
714711
{
715712
let output = lhs
716713
.to_odd()
@@ -722,7 +719,7 @@ mod tests {
722719

723720
fn run_tests<const LIMBS: usize, const DOUBLE: usize>()
724721
where
725-
Uint<LIMBS>: ConcatMixed<Uint<LIMBS>, MixedOutput = Uint<DOUBLE>>,
722+
Uint<LIMBS>: Concat<LIMBS, Output = Uint<DOUBLE>>,
726723
{
727724
let upper_bound = *Int::MAX.as_uint();
728725
test(Uint::ONE, Uint::ONE);

src/traits.rs

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -664,49 +664,24 @@ pub trait CheckedSub<Rhs = Self>: Sized {
664664
fn checked_sub(&self, rhs: &Rhs) -> CtOption<Self>;
665665
}
666666

667-
/// Concatenate two numbers into a "wide" double-width value, using the `hi` value as the most
668-
/// significant portion of the resulting value.
669-
pub trait Concat: ConcatMixed<Self, MixedOutput = Self::Output> {
670-
/// Concatenated output: twice the width of `Self`.
667+
/// Define the result of concatenating two numbers into a "wide" value.
668+
pub trait Concat<const HI: usize> {
669+
/// Concatenated output: having the width of `Self` plus `HI`.
671670
type Output: Integer;
672-
673-
/// Concatenate the two halves, with `self` as least significant and `hi` as the most significant.
674-
#[must_use]
675-
fn concat(&self, hi: &Self) -> Self::Output {
676-
self.concat_mixed(hi)
677-
}
678-
}
679-
680-
/// Concatenate two numbers into a "wide" combined-width value, using the `hi` value as the most
681-
/// significant value.
682-
pub trait ConcatMixed<Hi: ?Sized = Self> {
683-
/// Concatenated output: combination of `Self` and `Hi`.
684-
type MixedOutput: Integer;
685-
686-
/// Concatenate the two values, with `self` as least significant and `hi` as the most
687-
/// significant.
688-
#[must_use]
689-
fn concat_mixed(&self, hi: &Hi) -> Self::MixedOutput;
690671
}
691672

692-
/// Split a number in half, returning the least significant half followed by the most significant.
693-
pub trait Split: SplitMixed<Self::Output, Self::Output> {
694-
/// Split output: low/high components of the value.
695-
type Output;
696-
697-
/// Split this number in half, returning its low and high components respectively.
698-
#[must_use]
699-
fn split(&self) -> (Self::Output, Self::Output) {
700-
self.split_mixed()
701-
}
673+
/// Define the result of splitting a number into two parts, with the
674+
/// first part having the width `LO`.
675+
pub trait Split<const LO: usize> {
676+
/// High limbs of output: having the width of `Self` minus `LO`.
677+
type Output: Integer;
702678
}
703679

704-
/// Split a number into parts, returning the least significant part followed by the most
705-
/// significant.
706-
pub trait SplitMixed<Lo, Hi> {
707-
/// Split this number into parts, returning its low and high components respectively.
708-
#[must_use]
709-
fn split_mixed(&self) -> (Lo, Hi);
680+
/// Define the result of splitting a number into two parts, with
681+
/// each part having an equal width.
682+
pub trait SplitEven {
683+
/// Split output: each component having half the width of `Self`.
684+
type Output: Integer;
710685
}
711686

712687
/// Encoding support.
@@ -735,6 +710,12 @@ pub trait Encoding: Sized {
735710
fn to_le_bytes(&self) -> Self::Repr;
736711
}
737712

713+
/// A trait mapping between encoded representations of integers.
714+
pub trait EncodedSize {
715+
/// The equivalent encoded representation.
716+
type Target;
717+
}
718+
738719
/// Possible errors in variable-time integer decoding methods.
739720
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
740721
pub enum DecodeError {

src/uint/concat.rs

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,38 @@
1-
use crate::{Concat, ConcatMixed, Limb, Uint};
1+
use crate::{Concat, Uint};
22

3-
impl<const L: usize> Uint<L> {
3+
impl<const LIMBS: usize> Uint<LIMBS> {
44
/// Concatenate the two values, with `self` as least significant and `hi` as the most
5-
/// significant.
5+
/// significant, with both values having the same size.
66
#[must_use]
7-
pub const fn concat<const O: usize>(&self, hi: &Self) -> Uint<O>
7+
pub const fn concat<const WIDE_LIMBS: usize>(&self, hi: &Self) -> Uint<WIDE_LIMBS>
88
where
9-
Self: Concat<Output = Uint<O>>,
9+
Self: Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
1010
{
1111
Uint::concat_mixed(self, hi)
1212
}
1313

14-
/// Concatenate the two values, with `lo` as least significant and `hi`
14+
/// Concatenate the two values, with `self` as least significant and `hi`
1515
/// as the most significant.
1616
#[inline]
1717
#[must_use]
18-
pub const fn concat_mixed<const H: usize, const O: usize>(lo: &Uint<L>, hi: &Uint<H>) -> Uint<O>
18+
pub const fn concat_mixed<const HI_LIMBS: usize, const WIDE_LIMBS: usize>(
19+
&self,
20+
hi: &Uint<HI_LIMBS>,
21+
) -> Uint<WIDE_LIMBS>
1922
where
20-
Self: ConcatMixed<Uint<H>, MixedOutput = Uint<O>>,
23+
Self: Concat<HI_LIMBS, Output = Uint<WIDE_LIMBS>>,
2124
{
22-
let top = L + H;
23-
let top = if top < O { top } else { O };
24-
let mut limbs = [Limb::ZERO; O];
25-
let mut i = 0;
26-
27-
while i < top {
28-
if i < L {
29-
limbs[i] = lo.limbs[i];
30-
} else {
31-
limbs[i] = hi.limbs[i - L];
32-
}
33-
i += 1;
34-
}
35-
36-
Uint { limbs }
25+
let mut res = Uint::ZERO;
26+
let (res_lo, res_hi) = res.as_mut_uint_ref().split_at_mut(LIMBS);
27+
res_lo.copy_from(self.as_uint_ref());
28+
res_hi.copy_from(hi.as_uint_ref());
29+
res
3730
}
3831
}
3932

40-
impl<T> Concat for T
41-
where
42-
T: ConcatMixed<T>,
43-
{
44-
type Output = Self::MixedOutput;
45-
}
46-
4733
#[cfg(test)]
4834
mod tests {
49-
use crate::{ConcatMixed, U64, U128, U192};
35+
use crate::{BitOps, U64, U128, U192, Uint};
5036

5137
#[test]
5238
fn concat() {
@@ -80,4 +66,15 @@ mod tests {
8066
let res: U128 = U64::ONE.square_wide().into();
8167
assert_eq!(res, U128::ONE);
8268
}
69+
70+
#[test]
71+
fn infer_sizes() {
72+
let wide = U64::ONE.concat(&Uint::ZERO);
73+
assert_eq!(wide.bits_precision(), 128);
74+
assert_eq!(wide, Uint::ONE);
75+
76+
let wide = U64::ONE.concat_mixed(&U128::ZERO);
77+
assert_eq!(wide.bits_precision(), 192);
78+
assert_eq!(wide, Uint::ONE);
79+
}
8380
}

0 commit comments

Comments
 (0)