Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 5 additions & 7 deletions ec/src/scalar_mul/variable_base/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use ark_ff::prelude::*;
use ark_ff::biginteger::{S128, S64};
use ark_ff::prelude::*;
use ark_std::{
borrow::Borrow,
cfg_chunks, cfg_into_iter, cfg_iter,
Expand Down Expand Up @@ -640,9 +640,8 @@ pub fn msm_s64<V: VariableBaseMSM>(
Either::Right(b)
}
});
let (negative_scalars, non_negative_scalars): (Vec<u64>, Vec<u64>) = scalars
.iter()
.partition_map(|s| {
let (negative_scalars, non_negative_scalars): (Vec<u64>, Vec<u64>) =
scalars.iter().partition_map(|s| {
let mag = s.magnitude_as_u64();
if !s.sign() {
Either::Left(mag)
Expand Down Expand Up @@ -688,9 +687,8 @@ pub fn msm_s128<V: VariableBaseMSM>(
Either::Right(b)
}
});
let (negative_scalars, non_negative_scalars): (Vec<u128>, Vec<u128>) = scalars
.iter()
.partition_map(|s| {
let (negative_scalars, non_negative_scalars): (Vec<u128>, Vec<u128>) =
scalars.iter().partition_map(|s| {
let mag = s.magnitude_as_u128();
if !s.sign() {
Either::Left(mag)
Expand Down
10 changes: 5 additions & 5 deletions ff/src/biginteger/i8_or_i96.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::biginteger::{S160, S224};
use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
use allocative::Allocative;
use ark_serialize::{
CanonicalDeserialize, CanonicalSerialize, Compress, Read, SerializationError, Valid, Validate,
Write,
};
use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};

/// Compact signed integer optimized for the common `i8` case, widening to a 96-bit
/// split representation when needed (low 64 bits in `large_lo`, next 32 bits in `large_hi`).
Expand Down Expand Up @@ -563,8 +563,8 @@ impl Mul<S160> for I8OrI96 {
let mut c2 = c1;
let r2 = mac_with_carry!(0u64, x0, b2, &mut c2);

let r3_low = ((c2 as u128)
+ crate::biginteger::arithmetic::widening_mul(x1, b2)) as u64;
let r3_low =
((c2 as u128) + crate::biginteger::arithmetic::widening_mul(x1, b2)) as u64;
let hi32 = (r3_low & 0xFFFF_FFFF) as u32;
(r0, r1, r2, hi32)
}
Expand All @@ -588,8 +588,8 @@ impl Mul<S160> for I8OrI96 {
let mut r2 = mac_with_carry!(0u64, x0, b2, &mut c2);
r2 = mac_with_carry!(r2, x1, b1, &mut c2);

let r3_low = ((c2 as u128)
+ crate::biginteger::arithmetic::widening_mul(x1, b2)) as u64;
let r3_low =
((c2 as u128) + crate::biginteger::arithmetic::widening_mul(x1, b2)) as u64;
let hi32 = (r3_low & 0xFFFF_FFFF) as u32;
(r0, r1, r2, hi32)
}
Expand Down
71 changes: 57 additions & 14 deletions ff/src/biginteger/signed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,10 @@ impl<const N: usize> SignedBigInt<N> {
/// Debug-asserts that M <= N.
#[inline]
pub fn zero_extend_from<const M: usize>(smaller: &SignedBigInt<M>) -> SignedBigInt<N> {
debug_assert!(M <= N, "cannot zero-extend: source has more limbs than destination");
debug_assert!(
M <= N,
"cannot zero-extend: source has more limbs than destination"
);
let widened_mag = BigInt::<N>::zero_extend_from::<M>(&smaller.magnitude);
SignedBigInt::from_bigint(widened_mag, smaller.is_positive)
}
Expand All @@ -223,16 +226,25 @@ impl<const N: usize> SignedBigInt<N> {
pub fn add_trunc<const M: usize>(&self, rhs: &SignedBigInt<N>) -> SignedBigInt<M> {
if self.is_positive == rhs.is_positive {
let mag = self.magnitude.add_trunc::<N, M>(&rhs.magnitude);
return SignedBigInt::<M> { magnitude: mag, is_positive: self.is_positive };
return SignedBigInt::<M> {
magnitude: mag,
is_positive: self.is_positive,
};
}
match self.magnitude.cmp(&rhs.magnitude) {
Ordering::Greater | Ordering::Equal => {
let mag = self.magnitude.sub_trunc::<N, M>(&rhs.magnitude);
SignedBigInt::<M> { magnitude: mag, is_positive: self.is_positive }
SignedBigInt::<M> {
magnitude: mag,
is_positive: self.is_positive,
}
},
Ordering::Less => {
let mag = rhs.magnitude.sub_trunc::<N, M>(&self.magnitude);
SignedBigInt::<M> { magnitude: mag, is_positive: rhs.is_positive }
SignedBigInt::<M> {
magnitude: mag,
is_positive: rhs.is_positive,
}
},
}
}
Expand All @@ -242,16 +254,25 @@ impl<const N: usize> SignedBigInt<N> {
pub fn sub_trunc<const M: usize>(&self, rhs: &SignedBigInt<N>) -> SignedBigInt<M> {
if self.is_positive != rhs.is_positive {
let mag = self.magnitude.add_trunc::<N, M>(&rhs.magnitude);
return SignedBigInt::<M> { magnitude: mag, is_positive: self.is_positive };
return SignedBigInt::<M> {
magnitude: mag,
is_positive: self.is_positive,
};
}
match self.magnitude.cmp(&rhs.magnitude) {
Ordering::Greater | Ordering::Equal => {
let mag = self.magnitude.sub_trunc::<N, M>(&rhs.magnitude);
SignedBigInt::<M> { magnitude: mag, is_positive: self.is_positive }
SignedBigInt::<M> {
magnitude: mag,
is_positive: self.is_positive,
}
},
Ordering::Less => {
let mag = rhs.magnitude.sub_trunc::<N, M>(&self.magnitude);
SignedBigInt::<M> { magnitude: mag, is_positive: !self.is_positive }
SignedBigInt::<M> {
magnitude: mag,
is_positive: !self.is_positive,
}
},
}
}
Expand All @@ -265,16 +286,25 @@ impl<const N: usize> SignedBigInt<N> {
) -> SignedBigInt<P> {
if self.is_positive == rhs.is_positive {
let mag = self.magnitude.add_trunc::<M, P>(&rhs.magnitude);
return SignedBigInt::<P> { magnitude: mag, is_positive: self.is_positive };
return SignedBigInt::<P> {
magnitude: mag,
is_positive: self.is_positive,
};
}
match self.cmp_magnitude_mixed(rhs) {
Ordering::Greater | Ordering::Equal => {
let mag = self.magnitude.sub_trunc::<M, P>(&rhs.magnitude);
SignedBigInt::<P> { magnitude: mag, is_positive: self.is_positive }
SignedBigInt::<P> {
magnitude: mag,
is_positive: self.is_positive,
}
},
Ordering::Less => {
let mag = rhs.magnitude.sub_trunc::<N, P>(&self.magnitude);
SignedBigInt::<P> { magnitude: mag, is_positive: rhs.is_positive }
SignedBigInt::<P> {
magnitude: mag,
is_positive: rhs.is_positive,
}
},
}
}
Expand Down Expand Up @@ -373,16 +403,25 @@ impl<const N: usize> SignedBigInt<N> {
) -> SignedBigInt<P> {
if self.is_positive != rhs.is_positive {
let mag = self.magnitude.add_trunc::<M, P>(&rhs.magnitude);
return SignedBigInt::<P> { magnitude: mag, is_positive: self.is_positive };
return SignedBigInt::<P> {
magnitude: mag,
is_positive: self.is_positive,
};
}
match self.cmp_magnitude_mixed(rhs) {
Ordering::Greater | Ordering::Equal => {
let mag = self.magnitude.sub_trunc::<M, P>(&rhs.magnitude);
SignedBigInt::<P> { magnitude: mag, is_positive: self.is_positive }
SignedBigInt::<P> {
magnitude: mag,
is_positive: self.is_positive,
}
},
Ordering::Less => {
let mag = rhs.magnitude.sub_trunc::<N, P>(&self.magnitude);
SignedBigInt::<P> { magnitude: mag, is_positive: !self.is_positive }
SignedBigInt::<P> {
magnitude: mag,
is_positive: !self.is_positive,
}
},
}
}
Expand Down Expand Up @@ -696,7 +735,11 @@ impl<const N: usize> core::cmp::Ord for SignedBigInt<N> {
(false, true) => Ordering::Less,
_ => {
let ord = self.magnitude.cmp(&other.magnitude);
if self.is_positive { ord } else { ord.reverse() }
if self.is_positive {
ord
} else {
ord.reverse()
}
},
}
}
Expand Down
29 changes: 21 additions & 8 deletions ff/src/biginteger/signed_hi_32.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::biginteger::{BigInt, SignedBigInt, S128, S64};
use allocative::Allocative;
use ark_std::cmp::Ordering;
use ark_std::vec::Vec;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use crate::biginteger::{BigInt, SignedBigInt, S64, S128};
use ark_serialize::{
CanonicalDeserialize, CanonicalSerialize, Compress, Read, SerializationError, Valid, Validate,
Write,
};
use ark_std::cmp::Ordering;
use ark_std::vec::Vec;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};

/// Compact signed big-integer parameterized by limb count `N` (total width = `N*64 + 32` bits).
///
Expand Down Expand Up @@ -312,7 +312,10 @@ impl<const N: usize> SignedBigIntHi32<N> {
/// This ignores the sign; pair with `is_positive()` if you need a signed value.
#[inline]
pub fn magnitude_as_bigint_nplus1<const NPLUS1: usize>(&self) -> BigInt<NPLUS1> {
debug_assert!(NPLUS1 == N + 1, "NPLUS1 must be N+1 for SignedBigIntHi32 magnitude pack");
debug_assert!(
NPLUS1 == N + 1,
"NPLUS1 must be N+1 for SignedBigIntHi32 magnitude pack"
);
let mut limbs = [0u64; NPLUS1];
if N > 0 {
limbs[..N].copy_from_slice(&self.magnitude_lo);
Expand All @@ -327,7 +330,10 @@ impl<const N: usize> SignedBigIntHi32<N> {
/// Debug-asserts that M <= N.
#[inline]
pub fn zero_extend_from<const M: usize>(smaller: &SignedBigIntHi32<M>) -> SignedBigIntHi32<N> {
debug_assert!(M <= N, "cannot zero-extend: source has more limbs than destination");
debug_assert!(
M <= N,
"cannot zero-extend: source has more limbs than destination"
);
if N == M {
return SignedBigIntHi32::<N>::new(
// copy to avoid borrowing issues
Expand Down Expand Up @@ -357,7 +363,10 @@ impl<const N: usize> SignedBigIntHi32<N> {
/// Debug-asserts that NPLUS1 == N + 1.
#[inline]
pub fn to_signed_bigint_nplus1<const NPLUS1: usize>(&self) -> SignedBigInt<NPLUS1> {
debug_assert!(NPLUS1 == N + 1, "to_signed_bigint_nplus1 requires NPLUS1 = N + 1");
debug_assert!(
NPLUS1 == N + 1,
"to_signed_bigint_nplus1 requires NPLUS1 = N + 1"
);
let mut limbs = [0u64; NPLUS1];
if N > 0 {
limbs[..N].copy_from_slice(self.magnitude_lo());
Expand Down Expand Up @@ -579,7 +588,11 @@ impl<const N: usize> core::cmp::Ord for SignedBigIntHi32<N> {
(false, true) => Ordering::Less,
_ => {
let ord = self.compare_magnitudes(other);
if self.is_positive { ord } else { ord.reverse() }
if self.is_positive {
ord
} else {
ord.reverse()
}
},
}
}
Expand Down
55 changes: 45 additions & 10 deletions ff/src/biginteger/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,10 @@ pub mod tests {
limbs[1] = lo[1];
limbs[2] = lo[2];
limbs[3] = hi32;
(num_bigint::BigUint::from(crate::biginteger::BigInt::<4>(limbs)), v.is_positive())
(
num_bigint::BigUint::from(crate::biginteger::BigInt::<4>(limbs)),
v.is_positive(),
)
}

// Case 1: small i8 * b1-only rhs
Expand Down Expand Up @@ -774,7 +777,10 @@ pub mod tests {
let b = S::<2>::from_u128(0x0000_0000_0000_0001_0000_0000_0000_0001);
// Add and truncate to 1 limb
// Respect BigInt::add_trunc contract by truncating rhs to 1 limb
let b1 = S::<1>::from_bigint(crate::biginteger::BigInt::<1>::new([b.magnitude.0[0]]), b.is_positive);
let b1 = S::<1>::from_bigint(
crate::biginteger::BigInt::<1>::new([b.magnitude.0[0]]),
b.is_positive,
);
let r1 = a.add_trunc_mixed::<1, 1>(&b1);
// expected low limb wrap of the low words, ignoring carry to limb1
let expected_low = (0xffff_ffff_ffff_fffeu64).wrapping_add(0x0000_0000_0000_0001u64);
Expand Down Expand Up @@ -1020,24 +1026,44 @@ pub mod tests {
let mut b: BigInt<$m> = UniformRand::rand(&mut rng);

// Clamp low P limbs to avoid any carry across limb P-1 in add_trunc.
let mut i = 0; while i < core::cmp::min($p, $n) { a.0[i] >>= 1; i += 1; }
let mut j = 0; while j < core::cmp::min($p, $m) { b.0[j] >>= 1; j += 1; }
let mut i = 0;
while i < core::cmp::min($p, $n) {
a.0[i] >>= 1;
i += 1;
}
let mut j = 0;
while j < core::cmp::min($p, $m) {
b.0[j] >>= 1;
j += 1;
}

// Build rhs respecting M <= P
let (res, b_p): (BigInt<$p>, BigInt<$p>) = if $m <= $p {
let mut b_p = BigInt::<$p>::zero();
let mut k = 0; while k < $m { b_p.0[k] = b.0[k]; k += 1; }
let mut k = 0;
while k < $m {
b_p.0[k] = b.0[k];
k += 1;
}
(a.add_trunc::<$m, $p>(&b), b_p)
} else {
let mut bl = [0u64; $p];
let mut t = 0; while t < $p { bl[t] = b.0[t]; t += 1; }
let mut t = 0;
while t < $p {
bl[t] = b.0[t];
t += 1;
}
let b_trunc = BigInt::<$p>::new(bl);
(a.add_trunc::<$p, $p>(&b_trunc), b_trunc)
};

// Expected using low-P truncated operands (after clamping)
let mut a_p = BigInt::<$p>::zero();
let mut u = 0; while u < core::cmp::min($p, $n) { a_p.0[u] = a.0[u]; u += 1; }
let mut u = 0;
while u < core::cmp::min($p, $n) {
a_p.0[u] = a.0[u];
u += 1;
}
let a_bu = BigUint::from(a_p);
let b_bu = BigUint::from(b_p);
let modulus = BigUint::from(1u8) << (64 * $p);
Expand All @@ -1064,7 +1090,10 @@ pub mod tests {
let mut a: BigInt<4> = UniformRand::rand(&mut rng);
let mut b: BigInt<4> = UniformRand::rand(&mut rng);
// Ensure no carry anywhere by masking all limbs to 62 bits
for i in 0..4 { a.0[i] &= (1u64 << 62) - 1; b.0[i] &= (1u64 << 62) - 1; }
for i in 0..4 {
a.0[i] &= (1u64 << 62) - 1;
b.0[i] &= (1u64 << 62) - 1;
}
let r_trunc = a.add_trunc::<4, 4>(&b);
let mut a2 = a;
a2.add_assign_trunc::<4>(&b);
Expand All @@ -1080,7 +1109,10 @@ pub mod tests {
for _ in 0..200 {
let mut a: BigInt<4> = UniformRand::rand(&mut rng);
let mut b: BigInt<4> = UniformRand::rand(&mut rng);
for i in 0..4 { a.0[i] &= (1u64 << 62) - 1; b.0[i] &= (1u64 << 62) - 1; }
for i in 0..4 {
a.0[i] &= (1u64 << 62) - 1;
b.0[i] &= (1u64 << 62) - 1;
}
// Respect add_trunc contract by pre-truncating rhs to P limbs
let b3 = crate::biginteger::BigInt::<3>::new([b.0[0], b.0[1], b.0[2]]);
let r_trunc = a.add_trunc::<3, 3>(&b3);
Expand Down Expand Up @@ -1113,7 +1145,10 @@ pub mod tests {
// Use values that don't overflow beyond N to respect debug contract
let mut a = BigInt::<4>::new([u64::MAX; 4]);
let mut b = BigInt::<4>::new([u64::MAX; 4]);
for i in 0..4 { a.0[i] >>= 1; b.0[i] >>= 1; }
for i in 0..4 {
a.0[i] >>= 1;
b.0[i] >>= 1;
}
// P = 4: result should match BigUint addition modulo 2^256
// add_assign_trunc debug-overflow behavior cannot be reliably asserted in this
// environment without std; we validate the non-mutating truncated result above.
Expand Down
Loading
Loading