diff --git a/src/pluto_eris/engine.rs b/src/pluto_eris/engine.rs index d6919557..d35fc749 100644 --- a/src/pluto_eris/engine.rs +++ b/src/pluto_eris/engine.rs @@ -26,7 +26,7 @@ const NEG_SIX_U_PLUS_2_NAF: [i8; 114] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, ]; -/// Value of (57/(u + 3))^((p - 1)/2) where u^2 + 5 = 0 in Fp2 +/// Value of (57/(u + 3))^((p - 1)/2) where u^2 + 5 = 0 in Fp2. const XI_TO_P_MINUS_1_OVER_2: Fp2 = Fp2 { c0: Fp::from_raw([ 0x54cf5ad1c0926216, @@ -212,6 +212,8 @@ impl Group for Gt { } } +/// Points of G2 in Jacobian coordinates. +/// These are points lie in the twisted curve E'(Fp2). #[derive(Clone, Debug)] pub struct G2Prepared { pub(crate) coeffs: Vec<(Fp2, Fp2, Fp2)>, @@ -219,12 +221,12 @@ pub struct G2Prepared { } impl G2Prepared { - /// Returns true if `self` is the infinity point + /// Returns true if `self` is the infinity point. pub fn is_zero(&self) -> bool { self.infinity } - /// Prepares a G2 point in affine coordinates + /// Prepares a G2 point in affine coordinates. pub fn from_affine(q: G2Affine) -> Self { if bool::from(q.is_identity()) { return G2Prepared { @@ -661,13 +663,7 @@ impl MultiMillerLoop for Pluto { } } -// pub fn pairing(g1: &G1Affine, g2: &G2Affine) -> Gt { -// let g2 = G2Prepared::from_affine(*g2); -// let terms: &[(&G1Affine, &G2Prepared)] = &[(g1, &g2)]; -// let u = multi_miller_loop(terms); -// u.final_exponentiation() -// } - +/// Pluto pairing-friendly curve. See: https://github.com/daira/pluto-eris #[derive(Clone, Debug)] pub struct Pluto; @@ -684,19 +680,9 @@ impl Engine for Pluto { let terms: &[(&G1Affine, &G2Prepared)] = &[(p, &q)]; let u = Self::multi_miller_loop(terms); u.final_exponentiation() - // pairing(p, q) } } -// impl MultiMillerLoop for Pluto { -// type G2Prepared = G2Prepared; -// type Result = Gt; - -// fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result { -// multi_miller_loop(terms) -// } -// } - #[cfg(test)] use rand::SeedableRng; #[cfg(test)] diff --git a/src/pluto_eris/fields/fp.rs b/src/pluto_eris/fields/fp.rs index 10c3a6c9..3651a19a 100644 --- a/src/pluto_eris/fields/fp.rs +++ b/src/pluto_eris/fields/fp.rs @@ -1,8 +1,8 @@ use crate::arithmetic::{adc, mac, sbb}; use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; use crate::{ - field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs, impl_from_u64_7_limbs, - prime_field_legendre, + extend_field_legendre, field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs, + impl_from_u64_7_limbs, }; use crate::{ impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, @@ -202,7 +202,7 @@ field_bits_7_limbs!(Fp, MODULUS); #[cfg(not(target_pointer_width = "64"))] field_bits_7_limbs!(Fp, MODULUS, MODULUS_LIMBS_32); -prime_field_legendre!(Fp); +extend_field_legendre!(Fp); impl Fp { pub const fn size() -> usize { diff --git a/src/pluto_eris/fields/fp2.rs b/src/pluto_eris/fields/fp2.rs index f27953c5..14536fb6 100644 --- a/src/pluto_eris/fields/fp2.rs +++ b/src/pluto_eris/fields/fp2.rs @@ -1,6 +1,6 @@ use super::fp::{Fp, MODULUS_STR}; use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::legendre::Legendre; +use crate::ff_ext::Legendre; use core::convert::TryInto; use core::ops::{Add, Mul, Neg, Sub}; use rand::RngCore; @@ -315,16 +315,9 @@ impl Fp2 { tmp }) } -} - -impl Legendre for Fp2 { - type BasePrimeField = Fp; - fn legendre_exp() -> &'static [u64] { - Self::BasePrimeField::legendre_exp() - } /// Norm of Fp2 as extension field in u over Fp - fn norm(&self) -> Self::BasePrimeField { + fn norm(&self) -> Fp { // norm = self * self.cojungate() let t0 = self.c0.square(); let t1 = self.c1.square() * U_SQUARE; @@ -332,6 +325,12 @@ impl Legendre for Fp2 { } } +impl Legendre for Fp2 { + fn legendre(&self) -> i64 { + self.norm().legendre() + } +} + impl Field for Fp2 { const ZERO: Self = Self::zero(); const ONE: Self = Self::one(); @@ -699,7 +698,7 @@ pub fn test_sqrt() { const N_ITER: usize = 1000; for _ in 0..N_ITER { let a = Fp2::random(&mut rng); - if a.legendre() == -Fp::ONE { + if a.legendre() == -1 { assert!(bool::from(a.sqrt().is_none())); } } @@ -708,7 +707,7 @@ pub fn test_sqrt() { let a = Fp2::random(&mut rng); let mut b = a; b.square_assign(); - assert_eq!(b.legendre(), Fp::ONE); + assert_eq!(b.legendre(), 1); let b = b.sqrt().unwrap(); let mut negb = b; @@ -721,7 +720,7 @@ pub fn test_sqrt() { for _ in 0..N_ITER { let mut b = c; b.square_assign(); - assert_eq!(b.legendre(), Fp::ONE); + assert_eq!(b.legendre(), 1); b = b.sqrt().unwrap(); diff --git a/src/pluto_eris/fields/fq.rs b/src/pluto_eris/fields/fq.rs index 899192db..7aecd8a7 100644 --- a/src/pluto_eris/fields/fq.rs +++ b/src/pluto_eris/fields/fq.rs @@ -1,8 +1,8 @@ use crate::arithmetic::{adc, mac, sbb}; use crate::ff::{FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; use crate::{ - field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs, impl_from_u64_7_limbs, - prime_field_legendre, + extend_field_legendre, field_arithmetic_7_limbs, field_bits_7_limbs, field_common_7_limbs, + impl_from_u64_7_limbs, }; use crate::{ impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, @@ -192,7 +192,7 @@ field_bits_7_limbs!(Fq, MODULUS); #[cfg(not(target_pointer_width = "64"))] field_bits_7_limbs!(Fq, MODULUS, MODULUS_LIMBS_32); -prime_field_legendre!(Fq); +extend_field_legendre!(Fq); impl Fq { /// Return field element size in bytes. diff --git a/src/pluto_eris/fields/mod.rs b/src/pluto_eris/fields/mod.rs index ef59d49c..2ed86a6b 100644 --- a/src/pluto_eris/fields/mod.rs +++ b/src/pluto_eris/fields/mod.rs @@ -44,6 +44,16 @@ macro_rules! field_common_7_limbs { $r } + // Returns the Jacobi symbol, where the numerator and denominator + // are the element and the characteristic of the field, respectively. + // The Jacobi symbol is applicable to odd moduli + // while the Legendre symbol is applicable to prime moduli. + // They are equivalent for prime moduli. + #[inline(always)] + pub fn jacobi(&self) -> i64 { + $crate::ff_ext::jacobi::jacobi::<8>(&self.0, &$modulus.0) + } + fn from_u512(limbs: [u64; 8]) -> $field { // We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits // with the higher bits multiplied by 2^256. Thus, we perform two reductions diff --git a/src/pluto_eris/mod.rs b/src/pluto_eris/mod.rs index d81c9275..fd5c0aac 100644 --- a/src/pluto_eris/mod.rs +++ b/src/pluto_eris/mod.rs @@ -1,3 +1,10 @@ +//! # `Pluto\Eris half-pairing ccyle` +//! +//! Implementation of the Pluto / Eris half-pairing cycle of prime order elliptic curves. +//! +//! Supporting evidence: https://github.com/daira/pluto-eris +//! Field constant derivation: https://github.com/davidnevadoc/ec-constants/tree/main/pluto_eris +//! Pairing constants derivation: https://github.com/John-Gong-Math/pluto_eris/blob/main/pluto_pairing.ipynb mod curve; mod engine; mod fields;