From d9fb6e6c3325af0fd3fe41a300f5a25e6fcdbcb6 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 10 May 2024 16:42:30 -0700 Subject: [PATCH 1/2] Mimic the standard library for `adc` and `sbb` fallbacks The intrinsic x86/x86_64 versions are still faster though. --- src/biguint/addition.rs | 12 ++++++------ src/biguint/subtraction.rs | 14 ++++++-------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/biguint/addition.rs b/src/biguint/addition.rs index a054e66d..98b588b6 100644 --- a/src/biguint/addition.rs +++ b/src/biguint/addition.rs @@ -25,14 +25,14 @@ fn adc(carry: u8, a: u32, b: u32, out: &mut u32) -> u8 { } // fallback for environments where we don't have an addcarry intrinsic +// (copied from the standard library's `carrying_add`) #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] #[inline] -fn adc(carry: u8, a: BigDigit, b: BigDigit, out: &mut BigDigit) -> u8 { - use crate::big_digit::DoubleBigDigit; - - let sum = DoubleBigDigit::from(a) + DoubleBigDigit::from(b) + DoubleBigDigit::from(carry); - *out = sum as BigDigit; - (sum >> big_digit::BITS) as u8 +fn adc(carry: u8, lhs: BigDigit, rhs: BigDigit, out: &mut BigDigit) -> u8 { + let (a, b) = lhs.overflowing_add(rhs); + let (c, d) = a.overflowing_add(carry as BigDigit); + *out = c; + u8::from(b || d) } /// Two argument addition of raw slices, `a += b`, returning the carry. diff --git a/src/biguint/subtraction.rs b/src/biguint/subtraction.rs index 58839403..0154a3b0 100644 --- a/src/biguint/subtraction.rs +++ b/src/biguint/subtraction.rs @@ -25,16 +25,14 @@ fn sbb(borrow: u8, a: u32, b: u32, out: &mut u32) -> u8 { } // fallback for environments where we don't have a subborrow intrinsic +// (copied from the standard library's `borrowing_sub`) #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] #[inline] -fn sbb(borrow: u8, a: BigDigit, b: BigDigit, out: &mut BigDigit) -> u8 { - use crate::big_digit::SignedDoubleBigDigit; - - let difference = SignedDoubleBigDigit::from(a) - - SignedDoubleBigDigit::from(b) - - SignedDoubleBigDigit::from(borrow); - *out = difference as BigDigit; - u8::from(difference < 0) +fn sbb(borrow: u8, lhs: BigDigit, rhs: BigDigit, out: &mut BigDigit) -> u8 { + let (a, b) = lhs.overflowing_sub(rhs); + let (c, d) = a.overflowing_sub(borrow as BigDigit); + *out = c; + u8::from(b || d) } pub(super) fn sub2(a: &mut [BigDigit], b: &[BigDigit]) { From 98bea13b5c904ade5a3693cf12f10561978b230f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 10 May 2024 17:18:32 -0700 Subject: [PATCH 2/2] Remove the last use of `SignedDoubleBigDigit` The inverse for `MontyReducer` doesn't need a wider type at all! --- src/biguint/monty.rs | 9 +++++---- src/lib.rs | 6 ------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/biguint/monty.rs b/src/biguint/monty.rs index eeb0791e..a0b26b54 100644 --- a/src/biguint/monty.rs +++ b/src/biguint/monty.rs @@ -3,7 +3,7 @@ use core::mem; use core::ops::Shl; use num_traits::One; -use crate::big_digit::{self, BigDigit, DoubleBigDigit, SignedDoubleBigDigit}; +use crate::big_digit::{self, BigDigit, DoubleBigDigit}; use crate::biguint::BigUint; struct MontyReducer { @@ -15,8 +15,8 @@ struct MontyReducer { fn inv_mod_alt(b: BigDigit) -> BigDigit { assert_ne!(b & 1, 0); - let mut k0 = 2 - b as SignedDoubleBigDigit; - let mut t = (b - 1) as SignedDoubleBigDigit; + let mut k0 = BigDigit::wrapping_sub(2, b); + let mut t = b - 1; let mut i = 1; while i < big_digit::BITS { t = t.wrapping_mul(t); @@ -24,7 +24,8 @@ fn inv_mod_alt(b: BigDigit) -> BigDigit { i <<= 1; } - -k0 as BigDigit + debug_assert_eq!(k0.wrapping_mul(b), 1); + k0.wrapping_neg() } impl MontyReducer { diff --git a/src/lib.rs b/src/lib.rs index 671d544b..6e47479d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,12 +238,6 @@ mod big_digit { pub(crate) type DoubleBigDigit = u128; ); - // A [`SignedDoubleBigDigit`] is the signed version of [`DoubleBigDigit`]. - cfg_digit!( - pub(crate) type SignedDoubleBigDigit = i64; - pub(crate) type SignedDoubleBigDigit = i128; - ); - pub(crate) const BITS: u8 = BigDigit::BITS as u8; pub(crate) const HALF_BITS: u8 = BITS / 2; pub(crate) const HALF: BigDigit = (1 << HALF_BITS) - 1;