Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement more efficient squaring operation #133

Merged
merged 32 commits into from
Dec 28, 2022
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
213e796
Implement Modular with add and mul
jellevos Oct 11, 2022
f13f399
Implement modular exponentiation
jellevos Oct 11, 2022
d1177b1
Merge remote-tracking branch 'upstream/master' into powmod
jellevos Oct 11, 2022
d3887f0
Fix obvious issues and add documentation
jellevos Oct 11, 2022
4177420
Use Word instead of u64
jellevos Oct 11, 2022
df3c898
Use e.g. U64 instead of UInt::<1>
jellevos Oct 11, 2022
bf77788
Rewrite uint operations to const fn
jellevos Oct 12, 2022
154d82e
Checkpoint: working modulus macro
jellevos Oct 14, 2022
1814a0d
Add tests and make remaining fn const
jellevos Oct 14, 2022
daf3299
Make pow a const fn
jellevos Oct 14, 2022
515d78d
Add missing documentation
jellevos Oct 17, 2022
a0ed6ff
Bump rustc version to 1.61
jellevos Oct 17, 2022
0cd95b7
Bump rustc version to 1.61 in Github actions
jellevos Oct 17, 2022
dc85a35
Address comments
jellevos Nov 3, 2022
7f4b97b
Implement faster squaring
jellevos Nov 3, 2022
e57e1d9
Add const keyword to modular add
jellevos Nov 4, 2022
57cb0b7
Initial implementation of runtime moduli
jellevos Nov 4, 2022
9051b11
Write docstring where required
jellevos Nov 4, 2022
beccc95
Implement inverse for residues
jellevos Nov 5, 2022
2fff3e1
Cargo fmt
jellevos Nov 5, 2022
9d51b10
Merge branch 'runtime-moduli' into powmod
jellevos Nov 5, 2022
423e60f
Remove runtime moduli (not in PR scope)
jellevos Nov 5, 2022
b455a09
Fix docstring and remove stale code
jellevos Nov 5, 2022
dcdb1f6
Revert ConstResidue to Residue
jellevos Nov 6, 2022
a2ee635
Impl two invs: panicking and ctoption
jellevos Nov 8, 2022
dbcbc9a
Fix docs
jellevos Nov 11, 2022
25ce978
Merge branch 'powmod' into fast-squares
jellevos Nov 13, 2022
fcb3359
Merge remote-tracking branch 'upstream/master' into fast-squares
jellevos Nov 13, 2022
ea2d4a8
Merge branch 'master' into fast-squares
tarcieri Dec 28, 2022
2f864f5
UInt => Uint
tarcieri Dec 28, 2022
a158037
Add licensing note about translation of `square_wide`
tarcieri Dec 28, 2022
7893271
Remove newline to fix rustfmt
tarcieri Dec 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 80 additions & 3 deletions src/uint/mul.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! [`Uint`] addition operations.

use crate::{Checked, CheckedMul, Concat, Limb, Uint, Wrapping, Zero};
use crate::{Checked, CheckedMul, Concat, Limb, Uint, WideWord, Word, Wrapping, Zero};
use core::ops::{Mul, MulAssign};
use subtle::CtOption;

Expand Down Expand Up @@ -86,7 +86,76 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// Square self, returning a "wide" result in two parts as (lo, hi).
pub const fn square_wide(&self) -> (Self, Self) {
self.mul_wide(self)
// Translated from https://github.com/ucbrise/jedi-pairing/blob/c4bf151/include/core/bigint.hpp#L410
//
// Permission to relicense the resulting translation as Apache 2.0 + MIT was given
// by the original author Sam Kumar: https://github.com/RustCrypto/crypto-bigint/pull/133#discussion_r1056870411
let mut lo = Self::ZERO;
let mut hi = Self::ZERO;

// Schoolbook multiplication, but only considering half of the multiplication grid
let mut i = 1;
while i < LIMBS {
let mut j = 0;
let mut carry = Limb::ZERO;

while j < i {
let k = i + j;

if k >= LIMBS {
let (n, c) = hi.limbs[k - LIMBS].mac(self.limbs[i], self.limbs[j], carry);
hi.limbs[k - LIMBS] = n;
carry = c;
} else {
let (n, c) = lo.limbs[k].mac(self.limbs[i], self.limbs[j], carry);
lo.limbs[k] = n;
carry = c;
}

j += 1;
}

if (2 * i) < LIMBS {
lo.limbs[2 * i] = carry;
} else {
hi.limbs[2 * i - LIMBS] = carry;
}

i += 1;
}

// Double the current result, this accounts for the other half of the multiplication grid.
// TODO: The top word is empty so we can also use a special purpose shl.
(lo, hi) = Self::shl_vartime_wide((lo, hi), 1);

// Handle the diagonal of the multiplication grid, which finishes the multiplication grid.
let mut carry = Limb::ZERO;
let mut i = 0;
while i < LIMBS {
if (i * 2) < LIMBS {
let (n, c) = lo.limbs[i * 2].mac(self.limbs[i], self.limbs[i], carry);
lo.limbs[i * 2] = n;
carry = c;
} else {
let (n, c) = hi.limbs[i * 2 - LIMBS].mac(self.limbs[i], self.limbs[i], carry);
hi.limbs[i * 2 - LIMBS] = n;
carry = c;
}

if (i * 2 + 1) < LIMBS {
let n = lo.limbs[i * 2 + 1].0 as WideWord + carry.0 as WideWord;
lo.limbs[i * 2 + 1] = Limb(n as Word);
carry = Limb((n >> Word::BITS) as Word);
} else {
let n = hi.limbs[i * 2 + 1 - LIMBS].0 as WideWord + carry.0 as WideWord;
hi.limbs[i * 2 + 1 - LIMBS] = Limb(n as Word);
carry = Limb((n >> Word::BITS) as Word);
}

i += 1;
}

(lo, hi)
}
}

Expand Down Expand Up @@ -189,7 +258,7 @@ impl<const LIMBS: usize> MulAssign<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS

#[cfg(test)]
mod tests {
use crate::{CheckedMul, Zero, U64};
use crate::{CheckedMul, Zero, U256, U64};

#[test]
fn mul_wide_zero_and_one() {
Expand Down Expand Up @@ -248,4 +317,12 @@ mod tests {
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();
assert_eq!(lo, U256::ONE);
assert_eq!(hi, U256::MAX.wrapping_sub(&U256::ONE));
}
}