diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c330e894..bb65f2694 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -149,6 +149,7 @@ - `MNT4Parameters` → `MNT4Config` - `MNT6Parameters` → `MNT6Config` - `GLVParameters` → `GLVConfig` +- [\#557](https://github.com/arkworks-rs/algebra/pull/557) (`ark-ff`) Change `frobenius_map` to return the result, instead of mutating the input. Add `frobenius_map_in_place` for the old behavior. ### Features diff --git a/ec/src/models/bls12/mod.rs b/ec/src/models/bls12/mod.rs index 56956bc8c..ca8a66351 100644 --- a/ec/src/models/bls12/mod.rs +++ b/ec/src/models/bls12/mod.rs @@ -105,7 +105,7 @@ pub trait Bls12Config: 'static + Sized { // f2 = f^(p^6 - 1) f2 = r; // r = f^((p^6 - 1)(p^2)) - r.frobenius_map(2); + r.frobenius_map_in_place(2); // r = f^((p^6 - 1)(p^2) + (p^6 - 1)) // r = f^((p^6 - 1)(p^2 + 1)) @@ -131,7 +131,7 @@ pub trait Bls12Config: 'static + Sized { // t[2].Expt(&t[1]) Bls12::::exp_by_x(&y1, &mut y2); // t[1].Frobenius(&t[1]) - y1.frobenius_map(1); + y1.frobenius_map_in_place(1); // t[1].Mul(&t[1], &t[2]) y1 *= &y2; // result.Mul(&result, &t[0]) @@ -142,7 +142,7 @@ pub trait Bls12Config: 'static + Sized { Bls12::::exp_by_x(&y0, &mut y2); // t[0].FrobeniusSquare(&t[1]) y0 = y1; - y0.frobenius_map(2); + y0.frobenius_map_in_place(2); // t[1].InverseUnitary(&t[1]) y1.cyclotomic_inverse_in_place(); // t[1].Mul(&t[1], &t[2]) diff --git a/ec/src/models/bn/g2.rs b/ec/src/models/bn/g2.rs index 0e05fb8de..231b74402 100644 --- a/ec/src/models/bn/g2.rs +++ b/ec/src/models/bn/g2.rs @@ -177,9 +177,9 @@ fn mul_by_char(r: G2Affine

) -> G2Affine

{ // multiply by field characteristic let mut s = r; - s.x.frobenius_map(1); + s.x.frobenius_map_in_place(1); s.x *= &P::TWIST_MUL_BY_Q_X; - s.y.frobenius_map(1); + s.y.frobenius_map_in_place(1); s.y *= &P::TWIST_MUL_BY_Q_Y; s diff --git a/ec/src/models/bn/mod.rs b/ec/src/models/bn/mod.rs index 8b4bc1e05..611906bc0 100644 --- a/ec/src/models/bn/mod.rs +++ b/ec/src/models/bn/mod.rs @@ -174,7 +174,7 @@ impl Pairing for Bn

{ // f2 = f^(p^6 - 1) f2 = r; // r = f^((p^6 - 1)(p^2)) - r.frobenius_map(2); + r.frobenius_map_in_place(2); // r = f^((p^6 - 1)(p^2) + (p^6 - 1)) // r = f^((p^6 - 1)(p^2 + 1)) @@ -206,13 +206,13 @@ impl Pairing for Bn

{ let y10 = y8 * &y4; let y11 = y10 * &r; let mut y12 = y9; - y12.frobenius_map(1); + y12.frobenius_map_in_place(1); let y13 = y12 * &y11; - y8.frobenius_map(2); + y8.frobenius_map_in_place(2); let y14 = y8 * &y13; r.cyclotomic_inverse_in_place(); let mut y15 = r * &y9; - y15.frobenius_map(3); + y15.frobenius_map_in_place(3); let y16 = y15 * &y14; PairingOutput(y16) diff --git a/ec/src/models/bw6/mod.rs b/ec/src/models/bw6/mod.rs index c03dafeee..1dddd0d29 100644 --- a/ec/src/models/bw6/mod.rs +++ b/ec/src/models/bw6/mod.rs @@ -120,7 +120,7 @@ pub trait BW6Config: 'static + Eq + Sized { f_2.cyclotomic_inverse_in_place(); } - f_2.frobenius_map(1); + f_2.frobenius_map_in_place(1); MillerLoopOutput(f_1 * &f_2) } @@ -180,7 +180,7 @@ impl BW6

{ let elt_q3_over_elt = elt_q3 * elt_inv; // alpha = elt^((q^3-1) * q) let mut alpha = elt_q3_over_elt; - alpha.frobenius_map(1); + alpha.frobenius_map_in_place(1); // beta = elt^((q^3-1)*(q+1) alpha * &elt_q3_over_elt } @@ -198,28 +198,28 @@ impl BW6

{ // steps 1,2,3 let f0 = *f; let mut f0p = f0; - f0p.frobenius_map(1); + f0p.frobenius_map_in_place(1); let f1 = Self::exp_by_x(f0); let mut f1p = f1; - f1p.frobenius_map(1); + f1p.frobenius_map_in_place(1); let f2 = Self::exp_by_x(f1); let mut f2p = f2; - f2p.frobenius_map(1); + f2p.frobenius_map_in_place(1); let f3 = Self::exp_by_x(f2); let mut f3p = f3; - f3p.frobenius_map(1); + f3p.frobenius_map_in_place(1); let f4 = Self::exp_by_x(f3); let mut f4p = f4; - f4p.frobenius_map(1); + f4p.frobenius_map_in_place(1); let f5 = Self::exp_by_x(f4); let mut f5p = f5; - f5p.frobenius_map(1); + f5p.frobenius_map_in_place(1); let f6 = Self::exp_by_x(f5); let mut f6p = f6; - f6p.frobenius_map(1); + f6p.frobenius_map_in_place(1); let f7 = Self::exp_by_x(f6); let mut f7p = f7; - f7p.frobenius_map(1); + f7p.frobenius_map_in_place(1); // step 4 let f8p = Self::exp_by_x(f7p); diff --git a/ec/src/models/mnt4/mod.rs b/ec/src/models/mnt4/mod.rs index 2f0159482..1fdec8f9f 100644 --- a/ec/src/models/mnt4/mod.rs +++ b/ec/src/models/mnt4/mod.rs @@ -183,7 +183,7 @@ impl MNT4

{ let elt_inv_clone = *elt_inv; let mut elt_q = *elt; - elt_q.frobenius_map(1); + elt_q.frobenius_map_in_place(1); let w1_part = elt_q.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_1); let w0_part = if P::FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG { diff --git a/ec/src/models/mnt6/mod.rs b/ec/src/models/mnt6/mod.rs index f49dab433..2f6b24f04 100644 --- a/ec/src/models/mnt6/mod.rs +++ b/ec/src/models/mnt6/mod.rs @@ -176,7 +176,7 @@ impl MNT6

{ let elt_q3_over_elt = elt_q3 * elt_inv; // alpha = elt^((q^3-1) * q) let mut alpha = elt_q3_over_elt; - alpha.frobenius_map(1); + alpha.frobenius_map_in_place(1); // beta = elt^((q^3-1)*(q+1) alpha * &elt_q3_over_elt } @@ -189,7 +189,7 @@ impl MNT6

{ let elt_inv_clone = *elt_inv; let mut elt_q = *elt; - elt_q.frobenius_map(1); + elt_q.frobenius_map_in_place(1); let w1_part = elt_q.cyclotomic_exp(&P::FINAL_EXPONENT_LAST_CHUNK_1); let w0_part = if P::FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG { diff --git a/ff/src/fields/mod.rs b/ff/src/fields/mod.rs index 608ce400a..fd63cea2a 100644 --- a/ff/src/fields/mod.rs +++ b/ff/src/fields/mod.rs @@ -261,11 +261,19 @@ pub trait Field: sum } - /// Exponentiates this element by a power of the base prime modulus via - /// the Frobenius automorphism. - fn frobenius_map(&mut self, power: usize); + /// Sets `self` to `self^s`, where `s = Self::BasePrimeField::MODULUS^power`. + /// This is also called the Frobenius automorphism. + fn frobenius_map_in_place(&mut self, power: usize); + + /// Returns `self^s`, where `s = Self::BasePrimeField::MODULUS^power`. + /// This is also called the Frobenius automorphism. + fn frobenius_map(&self, power: usize) -> Self { + let mut this = *self; + this.frobenius_map_in_place(power); + this + } - /// Exponentiates this element by a number represented with `u64` limbs, + /// Returns `self^exp`, where `exp` is an integer represented with `u64` limbs, /// least significant limb first. #[must_use] fn pow>(&self, exp: S) -> Self { diff --git a/ff/src/fields/models/cubic_extension.rs b/ff/src/fields/models/cubic_extension.rs index 88c8db3c5..ff4203f03 100644 --- a/ff/src/fields/models/cubic_extension.rs +++ b/ff/src/fields/models/cubic_extension.rs @@ -135,9 +135,9 @@ impl CubicExtField

{ // indexed w.r.t. to BasePrimeField, we need to calculate the correct index. let index_multiplier = P::BaseField::extension_degree() as usize; let mut self_to_p = *self; - self_to_p.frobenius_map(index_multiplier); + self_to_p.frobenius_map_in_place(index_multiplier); let mut self_to_p2 = *self; - self_to_p2.frobenius_map(2 * index_multiplier); + self_to_p2.frobenius_map_in_place(2 * index_multiplier); self_to_p *= &(self_to_p2 * self); assert!(self_to_p.c1.is_zero() && self_to_p.c2.is_zero()); self_to_p.c0 @@ -328,10 +328,10 @@ impl Field for CubicExtField

{ } } - fn frobenius_map(&mut self, power: usize) { - self.c0.frobenius_map(power); - self.c1.frobenius_map(power); - self.c2.frobenius_map(power); + fn frobenius_map_in_place(&mut self, power: usize) { + self.c0.frobenius_map_in_place(power); + self.c1.frobenius_map_in_place(power); + self.c2.frobenius_map_in_place(power); P::mul_base_field_by_frob_coeff(&mut self.c1, &mut self.c2, power); } diff --git a/ff/src/fields/models/fp/mod.rs b/ff/src/fields/models/fp/mod.rs index 7ddf59b98..9ff3bbc68 100644 --- a/ff/src/fields/models/fp/mod.rs +++ b/ff/src/fields/models/fp/mod.rs @@ -316,7 +316,7 @@ impl, const N: usize> Field for Fp { /// The Frobenius map has no effect in a prime field. #[inline] - fn frobenius_map(&mut self, _: usize) {} + fn frobenius_map_in_place(&mut self, _: usize) {} #[inline] fn legendre(&self) -> LegendreSymbol { diff --git a/ff/src/fields/models/quadratic_extension.rs b/ff/src/fields/models/quadratic_extension.rs index 49e1eaa69..f62c7d353 100644 --- a/ff/src/fields/models/quadratic_extension.rs +++ b/ff/src/fields/models/quadratic_extension.rs @@ -149,9 +149,9 @@ impl QuadExtField

{ /// let norm = c.norm(); /// // We now compute the norm using the `a * a.conjugate()` approach. /// // A Frobenius map sends an element of `Fp2` to one of its p_th powers: - /// // `a.frobenius_map(1) -> a^p` and `a^p` is also `a`'s Galois conjugate. + /// // `a.frobenius_map_in_place(1) -> a^p` and `a^p` is also `a`'s Galois conjugate. /// let mut c_conjugate = c; - /// c_conjugate.frobenius_map(1); + /// c_conjugate.frobenius_map_in_place(1); /// let norm2 = c * c_conjugate; /// // Computing the norm of an `Fp2` element should result in an element /// // in BaseField `Fp`, i.e. `c1 == 0` @@ -354,9 +354,9 @@ impl Field for QuadExtField

{ } } - fn frobenius_map(&mut self, power: usize) { - self.c0.frobenius_map(power); - self.c1.frobenius_map(power); + fn frobenius_map_in_place(&mut self, power: usize) { + self.c0.frobenius_map_in_place(power); + self.c1.frobenius_map_in_place(power); P::mul_base_field_by_frob_coeff(&mut self.c1, power); } diff --git a/test-curves/src/bls12_381/g2.rs b/test-curves/src/bls12_381/g2.rs index 21427afc3..f4c970910 100644 --- a/test-curves/src/bls12_381/g2.rs +++ b/test-curves/src/bls12_381/g2.rs @@ -165,8 +165,8 @@ pub fn p_power_endomorphism(p: &Affine) -> Affine { // as implemented in the code as follows. let mut res = *p; - res.x.frobenius_map(1); - res.y.frobenius_map(1); + res.x.frobenius_map_in_place(1); + res.y.frobenius_map_in_place(1); let tmp_x = res.x; res.x.c0 = -P_POWER_ENDOMORPHISM_COEFF_0.c1 * tmp_x.c1; diff --git a/test-templates/src/fields.rs b/test-templates/src/fields.rs index a2914eb7f..309ea79ce 100644 --- a/test-templates/src/fields.rs +++ b/test-templates/src/fields.rs @@ -63,13 +63,16 @@ macro_rules! __test_field { let a = <$field>::rand(&mut rng); let mut a_0 = a; - a_0.frobenius_map(0); + a_0.frobenius_map_in_place(0); assert_eq!(a, a_0); + assert_eq!(a, a.frobenius_map(0)); let mut a_q = a.pow(&characteristic); for power in 1..max_power { + assert_eq!(a_q, a.frobenius_map(power)); + let mut a_qi = a; - a_qi.frobenius_map(power); + a_qi.frobenius_map_in_place(power); assert_eq!(a_qi, a_q, "failed on power {}", power); a_q = a_q.pow(&characteristic);