Skip to content

Commit

Permalink
Merge pull request #402 from recmo/recmo/montgomery
Browse files Browse the repository at this point in the history
Optimize Montgomery multiplication
  • Loading branch information
prestwich authored Dec 16, 2024
2 parents b91e6f7 + 2776215 commit e657576
Show file tree
Hide file tree
Showing 9 changed files with 342 additions and 98 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added `Uint::square_redc`. ([#402])
- Support for diesel @ 2.2 ([#404])
- Support for sqlx @ 0.8 ([#400])
- Support for fastrlp @ 0.4 ([#401])
Expand All @@ -21,10 +22,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support for sqlx @ 0.7. This is a breaking change, outside of
regular semver policy, as 0.7 contains a security vulnerability ([#400])

### Fixed

- `Uint::mul_redc` is now alloc free ([#402])

[#399]: https://github.com/recmo/uint/pull/399
[#400]: https://github.com/recmo/uint/pull/400
[#401]: https://github.com/recmo/uint/pull/401
[#404]: https://github.com/recmo/uint/pull/404
[#402]: https://github.com/recmo/uint/pull/402

## [1.12.3] - 2024-06-03

Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ parity-scale-codec = { version = "3", optional = true, features = [
"max-encoded-len",
], default-features = false }
primitive-types = { version = "0.12", optional = true, default-features = false }
proptest = { version = "1.3", optional = true, default-features = false }
proptest = { version = "=1.5", optional = true, default-features = false }
pyo3 = { version = "0.19", optional = true, default-features = false }
quickcheck = { version = "1", optional = true, default-features = false }
rand = { version = "0.8", optional = true, default-features = false }
Expand Down Expand Up @@ -105,7 +105,7 @@ bincode = "1.3"
hex = "0.4"
hex-literal = "0.4"
postgres = "0.19"
proptest = "1.2"
proptest = "=1.5"
serde_json = "1.0"

[features]
Expand Down
11 changes: 11 additions & 0 deletions proptest-regressions/algorithms/mul_redc.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc f8106a52136ed4aac61eec137e12c5da14188344055de1af2c70670a9bdcb685 # shrinks to a = 1, b = 1, m = 6096796062212595973
cc d8b943c322534ac6073b169239a6a57d92ed874bd1af77abcaca5fd6c17d0922 # shrinks to a = 1, m = 6467196249019906631
cc 7bce74ed04eba0d78a0753b45256b4fa898002bfbfdd2a45e2fa8692bddda85b # shrinks to a = 17273988827536164680, m = 4783851910396016589
cc 31a52325174b546a906b7327ea489c5df219ac159f819e2cd0240aaab7fe1da6 # shrinks to a = 14240046082810188870, b = 16896972505368501529, m = 6144969318566343923
cc 14972b6b9d20d6efe0cc3595dd60936ae21f0985b25cf47b5bf667cdf0b6f9b3 # shrinks to mut a = 194085243466426527248460240309849653567, m = 302498102704436076702507509051420483905
1 change: 1 addition & 0 deletions proptest-regressions/modular.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ cc d3df2bf31e0850f89f640c6a35c5ddb7fd15bc57c04eb60df5c04aea86d4b27a # shrinks to
cc 530d6a1671f6f937904c349f7ae6504c7cd2e05c31bf194e3aa38d7161a5fc2a # shrinks to a = 0x00_U2, b = 0x00_U2, m = 0x03_U2
cc d7d611337732de2c417788803637c596949792f5bcb942956ea0ec3e8b889d82 # shrinks to a = 0x00_U2, b = 0x00_U2, c = 0x00_U2, m = 0x03_U2
cc f3498e21378eea45e82848df9f85d19faa37874e686e4874bb1da885f3a2ac38 # shrinks to a = 0x00_U2, b = 0x00_U2, c = 0x00_U2, m = 0x03_U2
cc e40e555ad3f7103369086e7a27e810f9223e6e67d575d7b26a5a43fc8b103afc # shrinks to a = 2251333493155034715, b = 12864035474233633436, m = 17624464859391105743
29 changes: 8 additions & 21 deletions src/add.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::Uint;
use crate::{
algorithms::{borrowing_sub, carrying_add},
Uint,
};
use core::{
iter::Sum,
ops::{Add, AddAssign, Neg, Sub, SubAssign},
Expand Down Expand Up @@ -56,24 +59,16 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
#[inline]
#[must_use]
pub const fn overflowing_add(mut self, rhs: Self) -> (Self, bool) {
// TODO: Replace with `u64::carrying_add` once stable.
#[inline]
const fn u64_carrying_add(lhs: u64, rhs: u64, carry: bool) -> (u64, bool) {
let (a, b) = lhs.overflowing_add(rhs);
let (c, d) = a.overflowing_add(carry as u64);
(c, b | d)
}

if BITS == 0 {
return (Self::ZERO, false);
}
let mut carry = false;
let mut i = 0;
while i < LIMBS {
(self.limbs[i], carry) = u64_carrying_add(self.limbs[i], rhs.limbs[i], carry);
(self.limbs[i], carry) = carrying_add(self.limbs[i], rhs.limbs[i], carry);
i += 1;
}
let overflow = carry || self.limbs[LIMBS - 1] > Self::MASK;
let overflow = carry | (self.limbs[LIMBS - 1] > Self::MASK);
self.limbs[LIMBS - 1] &= Self::MASK;
(self, overflow)
}
Expand All @@ -98,24 +93,16 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
#[inline]
#[must_use]
pub const fn overflowing_sub(mut self, rhs: Self) -> (Self, bool) {
// TODO: Replace with `u64::borrowing_sub` once stable.
#[inline]
const fn u64_borrowing_sub(lhs: u64, rhs: u64, borrow: bool) -> (u64, bool) {
let (a, b) = lhs.overflowing_sub(rhs);
let (c, d) = a.overflowing_sub(borrow as u64);
(c, b | d)
}

if BITS == 0 {
return (Self::ZERO, false);
}
let mut borrow = false;
let mut i = 0;
while i < LIMBS {
(self.limbs[i], borrow) = u64_borrowing_sub(self.limbs[i], rhs.limbs[i], borrow);
(self.limbs[i], borrow) = borrowing_sub(self.limbs[i], rhs.limbs[i], borrow);
i += 1;
}
let overflow = borrow || self.limbs[LIMBS - 1] > Self::MASK;
let overflow = borrow | (self.limbs[LIMBS - 1] > Self::MASK);
self.limbs[LIMBS - 1] &= Self::MASK;
(self, overflow)
}
Expand Down
2 changes: 2 additions & 0 deletions src/algorithms/gcd/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![allow(clippy::module_name_repetitions)]

// TODO: https://github.com/bitcoin-core/secp256k1/blob/master/doc/safegcd_implementation.md

// TODO: Make these algorithms work on limb slices.
mod matrix;

Expand Down
22 changes: 19 additions & 3 deletions src/algorithms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ mod add;
pub mod div;
mod gcd;
mod mul;
#[cfg(feature = "alloc")] // TODO: Make mul_redc alloc-free
mod mul_redc;
mod ops;
mod shift;
Expand All @@ -21,11 +20,10 @@ pub use self::{
div::div,
gcd::{gcd, gcd_extended, inv_mod, LehmerMatrix},
mul::{add_nx1, addmul, addmul_n, addmul_nx1, mul_nx1, submul_nx1},
mul_redc::{mul_redc, square_redc},
ops::{adc, sbb},
shift::{shift_left_small, shift_right_small},
};
#[cfg(feature = "alloc")]
pub use mul_redc::mul_redc;

trait DoubleWord<T>: Sized + Copy {
fn join(high: T, low: T) -> Self;
Expand Down Expand Up @@ -116,3 +114,21 @@ pub fn cmp(left: &[u64], right: &[u64]) -> Ordering {

left.len().cmp(&right.len())
}

// Helper while [Rust#85532](https://github.com/rust-lang/rust/issues/85532) stabilizes.
#[inline]
#[must_use]
pub const fn carrying_add(lhs: u64, rhs: u64, carry: bool) -> (u64, bool) {
let (result, carry_1) = lhs.overflowing_add(rhs);
let (result, carry_2) = result.overflowing_add(carry as u64);
(result, carry_1 | carry_2)
}

// Helper while [Rust#85532](https://github.com/rust-lang/rust/issues/85532) stabilizes.
#[inline]
#[must_use]
pub const fn borrowing_sub(lhs: u64, rhs: u64, borrow: bool) -> (u64, bool) {
let (result, borrow_1) = lhs.overflowing_sub(rhs);
let (result, borrow_2) = result.overflowing_sub(borrow as u64);
(result, borrow_1 | borrow_2)
}
Loading

0 comments on commit e657576

Please sign in to comment.