Skip to content

Commit

Permalink
Rename BigInteger::add_nocarry and sub_noborrow and add tests (#383)
Browse files Browse the repository at this point in the history
Co-authored-by: Pratyush Mishra <[email protected]>
  • Loading branch information
alexander-zw and Pratyush authored Feb 1, 2022
1 parent cfa0e97 commit 08c4cdb
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 41 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
- Rename `Fp*Parameters` to `Fp*Config`.
- Add `From<u32>`, `From<u16>`, and `From<u8>` `impl`s for `BigInt<N>`.
- Remove `FftConfig`; move its contents to `FftField`.
- [\#383](https://github.com/arkworks-rs/algebra/pull/383) (arc-ff) Rename `BigInteger::add_nocarry` to `add_with_carry` and `sub_noborrow` to `sub_with_borrow`.


### Features

Expand Down
50 changes: 28 additions & 22 deletions ff/src/biginteger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ macro_rules! const_modulo {
remainder = remainder.const_mul2();
remainder.0[0] |= $a.get_bit(i as usize) as u64;
if remainder.const_geq($divisor) {
let (r, borrow) = remainder.const_sub_noborrow($divisor);
let (r, borrow) = remainder.const_sub_with_borrow($divisor);
remainder = r;
assert!(!borrow);
}
Expand Down Expand Up @@ -183,7 +183,7 @@ impl<const N: usize> BigInt<N> {

#[inline]
#[ark_ff_asm::unroll_for_loops]
pub(crate) const fn const_sub_noborrow(mut self, other: &Self) -> (Self, bool) {
pub(crate) const fn const_sub_with_borrow(mut self, other: &Self) -> (Self, bool) {
let mut borrow = 0;

const_for!((i in 0..N) {
Expand Down Expand Up @@ -235,7 +235,7 @@ impl<const N: usize> BigInteger for BigInt<N> {

#[inline]
#[ark_ff_asm::unroll_for_loops]
fn add_nocarry(&mut self, other: &Self) -> bool {
fn add_with_carry(&mut self, other: &Self) -> bool {
let mut carry = 0;

for i in 0..N {
Expand All @@ -257,7 +257,7 @@ impl<const N: usize> BigInteger for BigInt<N> {

#[inline]
#[ark_ff_asm::unroll_for_loops]
fn sub_noborrow(&mut self, other: &Self) -> bool {
fn sub_with_borrow(&mut self, other: &Self) -> bool {
let mut borrow = 0;

for i in 0..N {
Expand Down Expand Up @@ -701,42 +701,47 @@ pub trait BigInteger:
/// Number of 64-bit limbs representing `Self`.
const NUM_LIMBS: usize;

/// Add another representation to this one, returning the carry bit.
/// Add another [`BigInteger`] to `self`. This method stores the result in `self`,
/// and returns a carry bit.
/// # Example
///
/// ```
/// use ark_ff::{biginteger::BigInteger64 as B, BigInteger as _};
///
/// // Basic
/// let (mut one, mut two_add) = (B::from(1u64), B::from(2u64));
/// two_add.add_nocarry(&one);
/// assert_eq!(two_add, B::from(3u64));
/// let (mut one, mut x) = (B::from(1u64), B::from(2u64));
/// let carry = x.add_with_carry(&one);
/// assert_eq!(x, B::from(3u64));
/// assert_eq!(carry, false);
///
/// // Edge-Case
/// let mut max_one = B::from(u64::MAX);
/// let carry = max_one.add_nocarry(&one);
/// assert_eq!(max_one, B::from(0u64));
/// let mut x = B::from(u64::MAX);
/// let carry = x.add_with_carry(&one);
/// assert_eq!(x, B::from(0u64));
/// assert_eq!(carry, true)
/// ```
fn add_nocarry(&mut self, other: &Self) -> bool;
fn add_with_carry(&mut self, other: &Self) -> bool;

/// Subtract another representation from this one, returning the borrow bit.
/// Subtract another [`BigInteger`] from this one. This method stores the result in
/// `self`, and returns a borrow.
/// the borrow bit.
/// # Example
///
/// ```
/// use ark_ff::{biginteger::BigInteger64 as B, BigInteger as _};
///
/// // Basic
/// let (mut one, mut two, mut three_sub) = (B::from(1u64), B::from(2u64), B::from(3u64));
/// three_sub.sub_noborrow(&two);
/// assert_eq!(three_sub, one);
/// let (mut one_sub, two, mut three_sub) = (B::from(1u64), B::from(2u64), B::from(3u64));
/// let borrow = three_sub.sub_with_borrow(&two);
/// assert_eq!(three_sub, one_sub);
/// assert_eq!(borrow, false);
///
/// // Edge-Case
/// let borrow = one.sub_noborrow(&two);
/// let borrow = one_sub.sub_with_borrow(&two);
/// assert_eq!(one_sub, B::from(u64::MAX));
/// assert_eq!(borrow, true);
/// assert_eq!(one, B::from(u64::MAX));
/// ```
fn sub_noborrow(&mut self, other: &Self) -> bool;
fn sub_with_borrow(&mut self, other: &Self) -> bool;

/// Performs a leftwise bitshift of this number, effectively multiplying
/// it by 2. Overflow is ignored.
Expand All @@ -763,7 +768,8 @@ pub trait BigInteger:
/// ```
fn mul2(&mut self);

/// Performs a leftwise bitshift of this number by some amount.
/// Performs a leftwise bitshift of this number by n bits, effectively multiplying
/// it by 2^n. Overflow is ignored.
/// # Example
///
/// ```
Expand Down Expand Up @@ -996,9 +1002,9 @@ pub trait BigInteger:
if e.is_odd() {
z = signed_mod_reduction(e.as_ref()[0], 1 << w);
if z >= 0 {
e.sub_noborrow(&Self::from(z as u64));
e.sub_with_borrow(&Self::from(z as u64));
} else {
e.add_nocarry(&Self::from((-z) as u64));
e.add_with_carry(&Self::from((-z) as u64));
}
} else {
z = 0;
Expand Down
26 changes: 21 additions & 5 deletions ff/src/biginteger/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,41 @@ fn biginteger_arithmetic_test<B: BigInteger>(a: B, b: B, zero: B) {

// a + 0 = a
let mut a0_add = a.clone();
a0_add.add_nocarry(&zero);
let carry = a0_add.add_with_carry(&zero);
assert_eq!(a0_add, a);
assert_eq!(carry, false);

// a - 0 = a
let mut a0_sub = a.clone();
a0_sub.sub_noborrow(&zero);
let borrow = a0_sub.sub_with_borrow(&zero);
assert_eq!(a0_sub, a);
assert_eq!(borrow, false);

// a - a = 0
let mut aa_sub = a.clone();
aa_sub.sub_noborrow(&a);
let borrow = aa_sub.sub_with_borrow(&a);
assert_eq!(aa_sub, zero);
assert_eq!(borrow, false);

// a + b = b + a
let mut ab_add = a.clone();
ab_add.add_nocarry(&b);
let ab_carry = ab_add.add_with_carry(&b);
let mut ba_add = b.clone();
ba_add.add_nocarry(&a);
let ba_carry = ba_add.add_with_carry(&a);
assert_eq!(ab_add, ba_add);
assert_eq!(ab_carry, ba_carry);

// a * 1 = a
let mut a_mul1 = a.clone();
a_mul1.muln(0);
assert_eq!(a_mul1, a);

// a * 2 = a + a
let mut a_mul2 = a.clone();
a_mul2.mul2();
let mut a_plus_a = a.clone();
a_plus_a.add_with_carry(&a); // Won't assert anything about carry bit.
assert_eq!(a_mul2, a_plus_a);
}

// Test correctness of BigInteger's bit values
Expand Down
4 changes: 2 additions & 2 deletions ff/src/fields/models/fp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ impl<P: FpConfig<N>, const N: usize> Fp<P, N> {
#[inline]
fn subtract_modulus(&mut self) {
if !self.is_less_than_modulus() {
self.0.sub_noborrow(&Self::MODULUS);
self.0.sub_with_borrow(&Self::MODULUS);
}
}

Expand Down Expand Up @@ -733,7 +733,7 @@ impl<P: FpConfig<N>, const N: usize> Neg for Fp<P, N> {
fn neg(self) -> Self {
if !self.is_zero() {
let mut tmp = P::MODULUS;
tmp.sub_noborrow(&self.0);
tmp.sub_with_borrow(&self.0);
Fp::new(tmp)
} else {
self
Expand Down
22 changes: 11 additions & 11 deletions ff/src/fields/models/fp/montgomery_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@ pub trait MontConfig<const N: usize>: 'static + Sync + Send + Sized {
/// Set a += b;
fn add_assign(a: &mut Fp<MontBackend<Self, N>, N>, b: &Fp<MontBackend<Self, N>, N>) {
// This cannot exceed the backing capacity.
a.0.add_nocarry(&b.0);
a.0.add_with_carry(&b.0);
// However, it may need to be reduced
a.subtract_modulus();
}

fn sub_assign(a: &mut Fp<MontBackend<Self, N>, N>, b: &Fp<MontBackend<Self, N>, N>) {
// If `other` is larger than `self`, add the modulus to self first.
if b.0 > a.0 {
a.0.add_nocarry(&Self::MODULUS);
a.0.add_with_carry(&Self::MODULUS);
}
a.0.sub_noborrow(&b.0);
a.0.sub_with_borrow(&b.0);
}

fn double_in_place(a: &mut Fp<MontBackend<Self, N>, N>) {
Expand Down Expand Up @@ -220,7 +220,7 @@ pub trait MontConfig<const N: usize>: 'static + Sync + Send + Sized {
if b.0.is_even() {
b.0.div2();
} else {
b.0.add_nocarry(&Self::MODULUS);
b.0.add_with_carry(&Self::MODULUS);
b.0.div2();
}
}
Expand All @@ -231,16 +231,16 @@ pub trait MontConfig<const N: usize>: 'static + Sync + Send + Sized {
if c.0.is_even() {
c.0.div2();
} else {
c.0.add_nocarry(&Self::MODULUS);
c.0.add_with_carry(&Self::MODULUS);
c.0.div2();
}
}

if v < u {
u.sub_noborrow(&v);
u.sub_with_borrow(&v);
b -= &c;
} else {
v.sub_noborrow(&u);
v.sub_with_borrow(&u);
c -= &b;
}
}
Expand Down Expand Up @@ -428,7 +428,7 @@ impl<T, const N: usize> Fp<MontBackend<T, N>, N> {

const fn const_neg(self, modulus: BigInt<N>) -> Self {
if !self.const_is_zero() {
Self::new(Self::sub_noborrow(&modulus, &self.0))
Self::new(Self::sub_with_borrow(&modulus, &self.0))
} else {
self
}
Expand Down Expand Up @@ -539,13 +539,13 @@ impl<T, const N: usize> Fp<MontBackend<T, N>, N> {
#[inline]
const fn const_reduce(mut self, modulus: BigInt<N>) -> Self {
if !self.const_is_valid(modulus) {
self.0 = Self::sub_noborrow(&self.0, &modulus);
self.0 = Self::sub_with_borrow(&self.0, &modulus);
}
self
}

const fn sub_noborrow(a: &BigInt<N>, b: &BigInt<N>) -> BigInt<N> {
a.const_sub_noborrow(b).0
const fn sub_with_borrow(a: &BigInt<N>, b: &BigInt<N>) -> BigInt<N> {
a.const_sub_with_borrow(b).0
}
}

Expand Down
2 changes: 1 addition & 1 deletion ff/src/fields/models/quadratic_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ where
// This is cheaper than `P::BaseField::one().double().inverse()`
let mut two_inv = P::BasePrimeField::MODULUS;

two_inv.add_nocarry(&1u64.into());
two_inv.add_with_carry(&1u64.into());
two_inv.div2();

let two_inv = P::BasePrimeField::from(two_inv);
Expand Down

0 comments on commit 08c4cdb

Please sign in to comment.