Skip to content

Commit

Permalink
Implement double for field elements (#839)
Browse files Browse the repository at this point in the history
* Implement double for field elements

* clean up
  • Loading branch information
tcoratger authored Mar 20, 2024
1 parent 6baac21 commit 41b001e
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,14 @@ mod tests {
assert_eq!(a + &b, a_extension + b);
}

#[test]
fn double_base_field_with_degree_2_extension() {
let a = FieldElement::<BLS12381PrimeField>::from(3);
let b = FieldElement::<Degree2ExtensionField>::from(2);
assert_eq!(a.double(), a.clone() + a);
assert_eq!(b.double(), b.clone() + b);
}

#[test]
fn mul_base_field_with_degree_2_extension() {
let a = FieldElement::<BLS12381PrimeField>::from(3);
Expand Down
8 changes: 8 additions & 0 deletions math/src/field/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,14 @@ where
}
}

/// Returns the double of `self`
#[inline(always)]
pub fn double(&self) -> Self {
Self {
value: F::double(&self.value),
}
}

/// Returns `self` raised to the power of `exponent`
#[inline(always)]
pub fn pow<T>(&self, exponent: T) -> Self
Expand Down
16 changes: 16 additions & 0 deletions math/src/field/fields/montgomery_backed_prime_fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,14 @@ mod tests_u384_prime_fields {
assert_eq!(x_deserialized, x);
}

#[test]
fn doubling() {
assert_eq!(
U384F23Element::from(2).double(),
U384F23Element::from(2) + U384F23Element::from(2),
);
}

const ORDER: usize = 23;
#[test]
fn two_plus_one_is_three() {
Expand Down Expand Up @@ -843,6 +851,14 @@ mod tests_u256_prime_fields {
assert_eq!(x * y, c);
}

#[test]
fn doubling() {
assert_eq!(
U256F29Element::from(2).double(),
U256F29Element::from(2) + U256F29Element::from(2),
);
}

const ORDER: usize = 29;
#[test]
fn two_plus_one_is_three() {
Expand Down
5 changes: 5 additions & 0 deletions math/src/field/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ pub trait IsField: Debug + Clone {
/// Returns the sum of `a` and `b`.
fn add(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType;

/// Returns the double of `a`.
fn double(a: &Self::BaseType) -> Self::BaseType {
Self::add(a, a)
}

/// Returns the multiplication of `a` and `b`.
fn mul(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType;

Expand Down
43 changes: 43 additions & 0 deletions math/src/unsigned_integer/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,11 @@ impl<const NUM_LIMBS: usize> UnsignedInteger<NUM_LIMBS> {
(UnsignedInteger { limbs }, carry > 0)
}

/// Returns the double of `self`.
pub fn double(a: &UnsignedInteger<NUM_LIMBS>) -> (UnsignedInteger<NUM_LIMBS>, bool) {
Self::add(a, a)
}

/// Multi-precision subtraction.
/// Adapted from Algorithm 14.9 of "Handbook of Applied Cryptography" (https://cacr.uwaterloo.ca/hac/)
/// Returns the results and a flag that is set if the substraction underflowed
Expand Down Expand Up @@ -1442,6 +1447,16 @@ mod tests_u384 {
assert!(!U384::const_ne(&a, &b));
}

#[test]
fn double_two_384_bit_integers() {
let a = U384::from_u64(2);
let b = U384::from_u64(5);
let c = U384::from_u64(7);
assert_eq!(U384::double(&a).0, a + a);
assert_eq!(U384::double(&b).0, b + b);
assert_eq!(U384::double(&c).0, c + c);
}

#[test]
fn add_two_384_bit_integers_1() {
let a = U384::from_u64(2);
Expand Down Expand Up @@ -1550,6 +1565,12 @@ mod tests_u384 {
assert!(overflow);
}

#[test]
fn double_384_bit_integer_12_with_overflow() {
let a = U384::from_hex_unchecked("b07bc844363dd56467d9ebdd5929e9bb34a8e2577db77df6cf8f2ac45bd3d0bc2fc3078d265fe761af51d6aec5b59428");
assert_eq!(U384::double(&a), U384::add(&a, &a));
}

#[test]
fn sub_two_384_bit_integers_1() {
let a = U384::from_u64(2);
Expand Down Expand Up @@ -2406,6 +2427,16 @@ mod tests_u256 {
assert_ne!(a, b);
}

#[test]
fn double_256_bit_integer_1() {
let a = U256::from_u64(2);
let b = U256::from_u64(5);
let c = U256::from_u64(7);
assert_eq!(U256::double(&a).0, a + a);
assert_eq!(U256::double(&b).0, b + b);
assert_eq!(U256::double(&c).0, c + c);
}

#[test]
fn add_two_256_bit_integers_1() {
let a = U256::from_u64(2);
Expand Down Expand Up @@ -2544,6 +2575,18 @@ mod tests_u256 {
assert!(overflow);
}

#[test]
fn double_256_bit_integer_12_with_overflow() {
let a = U256::from_hex_unchecked(
"b07bc844363dd56467d9ebdd5929e9bb34a8e2577db77df6cf8f2ac45bd3d0bc",
);
let b = U256::from_hex_unchecked(
"cbbc474761bb7995ff54e25fa5d30295604fe3545d0cde405e72d8c0acebb119",
);
assert_eq!(U256::double(&a), U256::add(&a, &a));
assert_eq!(U256::double(&b), U256::add(&b, &b));
}

#[test]
fn sub_two_256_bit_integers_1() {
let a = U256::from_u64(2);
Expand Down

0 comments on commit 41b001e

Please sign in to comment.