feat: inversion function for Ext2

This commit is contained in:
zhenfei
2024-01-03 19:46:30 -05:00
parent d13b96b7d4
commit bb7ac0d158
4 changed files with 63 additions and 5 deletions

View File

@@ -126,7 +126,21 @@ impl Field for GoldilocksExt2 {
/// Computes the multiplicative inverse of this element,
/// failing if the element is zero.
fn invert(&self) -> CtOption<Self> {
unimplemented!()
if self.is_zero_vartime() {
return CtOption::new(Self::default(), (false as u8).into());
}
let a_pow_r_minus_1 = self.frobenius();
let a_pow_r = a_pow_r_minus_1 * *self;
debug_assert!(a_pow_r.0[1] == Goldilocks::ZERO);
let a_pow_r_inv = a_pow_r.0[0].invert().expect("inverse does not exist");
let res = [
a_pow_r_minus_1.0[0] * a_pow_r_inv,
a_pow_r_minus_1.0[1] * a_pow_r_inv,
];
CtOption::new(Self(res), Choice::from(1))
}
/// Returns the square root of the field element, if it is
@@ -333,3 +347,39 @@ impl FromUniformBytes<64> for GoldilocksExt2 {
])
}
}
impl GoldilocksExt2 {
/// FrobeniusField automorphisms: x -> x^p, where p is the order of BaseField.
fn frobenius(&self) -> Self {
self.repeated_frobenius(1)
}
/// Repeated Frobenius automorphisms: x -> x^(p^count).
///
/// Follows precomputation suggestion in Section 11.3.3 of the
/// Handbook of Elliptic and Hyperelliptic Curve Cryptography.
fn repeated_frobenius(&self, count: usize) -> Self {
if count == 0 {
return *self;
} else if count >= 2 {
// x |-> x^(p^D) is the identity, so x^(p^count) ==
// x^(p^(count % D))
return self.repeated_frobenius(count % 2);
}
let arr = self.0;
// z0 = DTH_ROOT^count = W^(k * count) where k = floor((p^D-1)/D)
let mut z0 = Goldilocks(18446744069414584320);
for _ in 1..count {
z0 *= Goldilocks(18446744069414584320);
}
let z0square = z0 * z0;
let mut res = [Goldilocks::ZERO; 2];
res[0] = arr[0] * z0;
res[1] = arr[1] * z0square;
Self(res)
}
}

View File

@@ -164,8 +164,12 @@ fn random_squaring_tests<F: Field, R: RngCore>(mut rng: R, type_name: String) {
end_timer!(start);
}
#[allow(dead_code)]
fn random_inversion_tests<F: Field, R: RngCore>(mut rng: R, type_name: String) {
pub fn random_inversion_tests<F: Field>(type_name: String) {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
assert!(bool::from(F::ZERO.invert().is_none()));
let message = format!("inversion {}", type_name);

View File

@@ -5,6 +5,7 @@ use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use super::random_field_tests;
use super::random_inversion_tests;
use super::random_prime_field_tests;
use crate::fp::Goldilocks;
use crate::fp::LegendreSymbol;
@@ -54,4 +55,5 @@ fn test_sqrt_fq() {
fn test_field() {
random_field_tests::<Goldilocks>("Goldilocks".to_string());
random_prime_field_tests::<Goldilocks>("Goldilocks".to_string());
random_inversion_tests::<Goldilocks>("Goldilocks".to_string());
}

View File

@@ -1,12 +1,14 @@
use super::random_field_tests;
use super::random_inversion_tests;
use super::random_prime_field_tests;
use crate::fp::Goldilocks;
use crate::fp2::GoldilocksExt2;
#[test]
fn test_field() {
random_field_tests::<GoldilocksExt2>("GoldilocksExt3".to_string());
random_prime_field_tests::<GoldilocksExt2>("GoldilocksExt3".to_string());
random_field_tests::<GoldilocksExt2>("GoldilocksExt2".to_string());
random_prime_field_tests::<GoldilocksExt2>("GoldilocksExt2".to_string());
random_inversion_tests::<GoldilocksExt2>("GoldilocksExt2".to_string());
}
#[test]