Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify SquareRootField and Field #387

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
12 changes: 6 additions & 6 deletions ec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ extern crate ark_std;

use ark_ff::{
bytes::{FromBytes, ToBytes},
fields::{BitIteratorBE, Field, PrimeField, SquareRootField},
fields::{BitIteratorBE, Field, PrimeField},
UniformRand,
};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
Expand All @@ -47,7 +47,7 @@ pub mod wnaf;

pub trait PairingEngine: Sized + 'static + Copy + Debug + Sync + Send + Eq + PartialEq {
/// This is the scalar field of the G1/G2 groups.
type Fr: PrimeField + SquareRootField;
type Fr: PrimeField;

/// The projective representation of an element in G1.
type G1Projective: ProjectiveCurve<BaseField = Self::Fq, ScalarField = Self::Fr, Affine = Self::G1Affine>
Expand Down Expand Up @@ -80,10 +80,10 @@ pub trait PairingEngine: Sized + 'static + Copy + Debug + Sync + Send + Eq + Par
type G2Prepared: ToBytes + Default + Clone + Send + Sync + Debug + From<Self::G2Affine>;

/// The base field that hosts G1.
type Fq: PrimeField + SquareRootField;
type Fq: PrimeField;

/// The extension field that hosts G2.
type Fqe: SquareRootField;
type Fqe: Field;

/// The extension field that hosts the target group of the pairing.
type Fqk: Field;
Expand Down Expand Up @@ -156,7 +156,7 @@ pub trait ProjectiveCurve:
+ From<<Self as ProjectiveCurve>::Affine>
{
type Parameters: ModelParameters<ScalarField = Self::ScalarField, BaseField = Self::BaseField>;
type ScalarField: PrimeField + SquareRootField;
type ScalarField: PrimeField;
type BaseField: Field;
type Affine: AffineCurve<
Parameters = Self::Parameters,
Expand Down Expand Up @@ -256,7 +256,7 @@ pub trait AffineCurve:
+ From<<Self as AffineCurve>::Projective>
{
type Parameters: ModelParameters<ScalarField = Self::ScalarField, BaseField = Self::BaseField>;
type ScalarField: PrimeField + SquareRootField + Into<<Self::ScalarField as PrimeField>::BigInt>;
type ScalarField: PrimeField + Into<<Self::ScalarField as PrimeField>::BigInt>;
type BaseField: Field;
type Projective: ProjectiveCurve<
Parameters = Self::Parameters,
Expand Down
4 changes: 2 additions & 2 deletions ec/src/models/bls12/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ark_ff::fields::{
fp12_2over3over2::{Fp12, Fp12Parameters},
fp2::Fp2Config,
fp6_3over2::Fp6Config,
BitIteratorBE, Field, Fp2, PrimeField, SquareRootField,
BitIteratorBE, Field, Fp2, PrimeField,
};
use core::marker::PhantomData;
use num_traits::{One, Zero};
Expand All @@ -33,7 +33,7 @@ pub trait Bls12Parameters: 'static {
/// What kind of twist is this?
const TWIST_TYPE: TwistType;

type Fp: PrimeField + SquareRootField + Into<<Self::Fp as PrimeField>::BigInt>;
type Fp: PrimeField + Into<<Self::Fp as PrimeField>::BigInt>;
type Fp2Params: Fp2Config<Fp = Self::Fp>;
type Fp6Params: Fp6Config<Fp2Params = Self::Fp2Params>;
type Fp12Params: Fp12Parameters<Fp6Params = Self::Fp6Params>;
Expand Down
4 changes: 2 additions & 2 deletions ec/src/models/bn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use ark_ff::fields::{
fp12_2over3over2::{Fp12, Fp12Parameters},
fp2::Fp2Config,
fp6_3over2::Fp6Config,
Field, Fp2, PrimeField, SquareRootField,
Field, Fp2, PrimeField,
};
use num_traits::One;

Expand All @@ -31,7 +31,7 @@ pub trait BnParameters: 'static {
const TWIST_TYPE: TwistType;
const TWIST_MUL_BY_Q_X: Fp2<Self::Fp2Params>;
const TWIST_MUL_BY_Q_Y: Fp2<Self::Fp2Params>;
type Fp: PrimeField + SquareRootField + Into<<Self::Fp as PrimeField>::BigInt>;
type Fp: PrimeField + Into<<Self::Fp as PrimeField>::BigInt>;
type Fp2Params: Fp2Config<Fp = Self::Fp>;
type Fp6Params: Fp6Config<Fp2Params = Self::Fp2Params>;
type Fp12Params: Fp12Parameters<Fp6Params = Self::Fp6Params>;
Expand Down
4 changes: 2 additions & 2 deletions ec/src/models/bw6/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
use ark_ff::fields::{
fp3::Fp3Config,
fp6_2over3::{Fp6, Fp6Config},
BitIteratorBE, Field, PrimeField, SquareRootField,
BitIteratorBE, Field, PrimeField,
};
use num_traits::One;

Expand All @@ -24,7 +24,7 @@ pub trait BW6Parameters: 'static + Eq + PartialEq {
const ATE_LOOP_COUNT_2: &'static [i8];
const ATE_LOOP_COUNT_2_IS_NEGATIVE: bool;
const TWIST_TYPE: TwistType;
type Fp: PrimeField + SquareRootField + Into<<Self::Fp as PrimeField>::BigInt>;
type Fp: PrimeField + Into<<Self::Fp as PrimeField>::BigInt>;
type Fp3Params: Fp3Config<Fp = Self::Fp>;
type Fp6Params: Fp6Config<Fp3Params = Self::Fp3Params>;
type G1Parameters: SWModelParameters<BaseField = Self::Fp>;
Expand Down
6 changes: 3 additions & 3 deletions ec/src/models/mnt4/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
use ark_ff::{
fp2::{Fp2, Fp2Config},
fp4::{Fp4, Fp4Config},
BitIteratorBE, Field, PrimeField, SquareRootField,
BitIteratorBE, Field, PrimeField,
};
use num_traits::{One, Zero};

Expand All @@ -30,8 +30,8 @@ pub trait MNT4Parameters: 'static {
const FINAL_EXPONENT_LAST_CHUNK_1: <Self::Fp as PrimeField>::BigInt;
const FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG: bool;
const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: <Self::Fp as PrimeField>::BigInt;
type Fp: PrimeField + SquareRootField + Into<<Self::Fp as PrimeField>::BigInt>;
type Fr: PrimeField + SquareRootField + Into<<Self::Fr as PrimeField>::BigInt>;
type Fp: PrimeField + Into<<Self::Fp as PrimeField>::BigInt>;
type Fr: PrimeField + Into<<Self::Fr as PrimeField>::BigInt>;
type Fp2Params: Fp2Config<Fp = Self::Fp>;
type Fp4Params: Fp4Config<Fp2Params = Self::Fp2Params>;
type G1Parameters: SWModelParameters<BaseField = Self::Fp, ScalarField = Self::Fr>;
Expand Down
6 changes: 3 additions & 3 deletions ec/src/models/mnt6/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
use ark_ff::{
fp3::{Fp3, Fp3Config},
fp6_2over3::{Fp6, Fp6Config},
BitIteratorBE, Field, PrimeField, SquareRootField,
BitIteratorBE, Field, PrimeField,
};
use num_traits::{One, Zero};

Expand All @@ -30,8 +30,8 @@ pub trait MNT6Parameters: 'static {
const FINAL_EXPONENT_LAST_CHUNK_1: <Self::Fp as PrimeField>::BigInt;
const FINAL_EXPONENT_LAST_CHUNK_W0_IS_NEG: bool;
const FINAL_EXPONENT_LAST_CHUNK_ABS_OF_W0: <Self::Fp as PrimeField>::BigInt;
type Fp: PrimeField + SquareRootField + Into<<Self::Fp as PrimeField>::BigInt>;
type Fr: PrimeField + SquareRootField + Into<<Self::Fr as PrimeField>::BigInt>;
type Fp: PrimeField + Into<<Self::Fp as PrimeField>::BigInt>;
type Fr: PrimeField + Into<<Self::Fr as PrimeField>::BigInt>;
type Fp3Params: Fp3Config<Fp = Self::Fp>;
type Fp6Params: Fp6Config<Fp3Params = Self::Fp3Params>;
type G1Parameters: SWModelParameters<BaseField = Self::Fp, ScalarField = Self::Fr>;
Expand Down
6 changes: 3 additions & 3 deletions ec/src/models/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::AffineCurve;
use ark_ff::{fields::BitIteratorBE, Field, PrimeField, SquareRootField, Zero};
use ark_ff::{fields::BitIteratorBE, Field, PrimeField, Zero};

pub mod bls12;
pub mod bn;
Expand All @@ -11,8 +11,8 @@ pub mod twisted_edwards_extended;

/// Model parameters for an elliptic curve.
pub trait ModelParameters: Send + Sync + Sized + 'static {
type BaseField: Field + SquareRootField;
type ScalarField: PrimeField + SquareRootField + Into<<Self::ScalarField as PrimeField>::BigInt>;
type BaseField: Field;
type ScalarField: PrimeField + Into<<Self::ScalarField as PrimeField>::BigInt>;

const COFACTOR: &'static [u64];
const COFACTOR_INV: Self::ScalarField;
Expand Down
2 changes: 1 addition & 1 deletion ec/src/models/short_weierstrass_jacobian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use ark_std::{

use ark_ff::{
bytes::{FromBytes, ToBytes},
fields::{Field, PrimeField, SquareRootField},
fields::{Field, PrimeField},
ToConstraintField, UniformRand,
};

Expand Down
2 changes: 1 addition & 1 deletion ec/src/models/twisted_edwards_extended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use zeroize::Zeroize;

use ark_ff::{
bytes::{FromBytes, ToBytes},
fields::{Field, PrimeField, SquareRootField},
fields::{Field, PrimeField},
ToConstraintField, UniformRand,
};

Expand Down
38 changes: 17 additions & 21 deletions ff/src/fields/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,19 @@ pub trait Field:
/// random field elements from a hash-function or RNG output.
fn from_random_bytes_with_flags<F: Flags>(bytes: &[u8]) -> Option<(Self, F)>;

/// Returns a `LegendreSymbol`, which indicates whether this field element
/// is 1 : a quadratic residue
/// 0 : equal to 0
/// -1 : a quadratic non-residue
fn legendre(&self) -> LegendreSymbol;

/// Returns the square root of self, if it exists.
#[must_use]
fn sqrt(&self) -> Option<Self>;

/// Sets `self` to be the square root of `self`, if it exists.
fn sqrt_in_place(&mut self) -> Option<&mut Self>;

/// Returns `self * self`.
#[must_use]
fn square(&self) -> Self;
Expand Down Expand Up @@ -329,30 +342,13 @@ pub trait PrimeField:
}
}

/// The interface for a field that supports an efficient square-root operation.
pub trait SquareRootField: Field {
/// Returns a `LegendreSymbol`, which indicates whether this field element
/// is
/// - 1: a quadratic residue
/// - 0: equal to 0
/// - -1: a quadratic non-residue
fn legendre(&self) -> LegendreSymbol;

/// Returns the square root of self, if it exists.
#[must_use]
fn sqrt(&self) -> Option<Self>;

/// Sets `self` to be the square root of `self`, if it exists.
fn sqrt_in_place(&mut self) -> Option<&mut Self>;
}

/// Indication of the field element's quadratic residuosity
///
/// # Examples
/// ```
/// # use ark_std::test_rng;
/// # use ark_std::UniformRand;
/// # use ark_test_curves::{LegendreSymbol, Field, SquareRootField, bls12_381::Fq as Fp};
/// # use ark_test_curves::{LegendreSymbol, Field, bls12_381::Fq as Fp};
/// let a: Fp = Fp::rand(&mut test_rng());
/// let b = a.square();
/// assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
Expand All @@ -371,7 +367,7 @@ impl LegendreSymbol {
/// ```
/// # use ark_std::test_rng;
/// # use ark_std::UniformRand;
/// # use ark_test_curves::{LegendreSymbol, Field, SquareRootField, bls12_381::Fq as Fp};
/// # use ark_test_curves::{LegendreSymbol, Field, bls12_381::Fq as Fp};
/// let a: Fp = Fp::rand(&mut test_rng());
/// let b: Fp = a.square();
/// assert!(!b.legendre().is_zero());
Expand All @@ -384,7 +380,7 @@ impl LegendreSymbol {
///
/// # Examples
/// ```
/// # use ark_test_curves::{Fp2Config, LegendreSymbol, SquareRootField, bls12_381::{Fq, Fq2Config}};
/// # use ark_test_curves::{Fp2Config, LegendreSymbol, bls12_381::{Fq, Fq2Config}};
/// let a: Fq = Fq2Config::NONRESIDUE;
/// assert!(a.legendre().is_qnr());
/// ```
Expand All @@ -398,7 +394,7 @@ impl LegendreSymbol {
/// # use ark_std::test_rng;
/// # use ark_test_curves::bls12_381::Fq as Fp;
/// # use ark_std::UniformRand;
/// # use ark_ff::{LegendreSymbol, Field, SquareRootField};
/// # use ark_ff::{LegendreSymbol, Field};
/// let a: Fp = Fp::rand(&mut test_rng());
/// let b: Fp = a.square();
/// assert!(b.legendre().is_qr());
Expand Down
91 changes: 90 additions & 1 deletion ff/src/fields/models/cubic_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ impl<P: CubicExtConfig> Field for CubicExtField<P> {
self
}

fn sqrt(&self) -> Option<Self> {
tonelli_shanks(self)
}

fn inverse(&self) -> Option<Self> {
if self.is_zero() {
None
Expand Down Expand Up @@ -314,8 +318,93 @@ impl<P: CubicExtConfig> Field for CubicExtField<P> {
}
}

fn tonelli_shanks<P: CubicExtConfig>(f: &CubicExtField<P>) -> Option<CubicExtField<P>> {
// https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
// Actually this is just normal Tonelli-Shanks; since `P::Generator`
// is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t`
// is also a quadratic non-residue (since `t` is odd).
if f.is_zero() {
return Some(CubicExtField::zero());
}
// Try computing the square root (x at the end of the algorithm)
// Check at the end of the algorithm if x was a square root
// Begin Tonelli-Shanks
let mut z = CubicExtField::qnr_to_t();
let mut w = f.pow(P::TRACE_MINUS_ONE_DIV_TWO);
let mut x = w * f;
let mut b = x * &w;

let mut v = P::TWO_ADICITY as usize;

while !b.is_one() {
let mut k = 0usize;

let mut b2k = b;
while !b2k.is_one() {
// invariant: b2k = b^(2^k) after entering this loop
b2k.square_in_place();
k += 1;
}

if k == (P::TWO_ADICITY as usize) {
// We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1,
// which means that no square root exists.
return None;
}
let j = v - k;
w = z;
for _ in 1..j {
w.square_in_place();
}

z = w.square();
b *= &z;
x *= &w;
v = k;
}
// Is x the square root? If so, return it.
if (x.square() == *f) {
return Some(x);
} else {
// Consistency check that if no square root is found,
// it is because none exists.
#[cfg(debug_assertions)]
{
use crate::fields::LegendreSymbol::*;
if (f.legendre() != QuadraticNonResidue) {
Pratyush marked this conversation as resolved.
Show resolved Hide resolved
panic!("Input has a square root per its legendre symbol, but it was not found")
}
}
None
}
}

fn shanks<P: CubicExtConfig>(f: &CubicExtField<P>) -> Option<CubicExtField<P>> {
// https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2)
// Using decomposition of (q-3)/ 4 = alpha + p[p(alpha) + (3a + 2)]*sum_i^((m-3)/2) p^{2i}

// t1 = f^alpha
let t1 = f.pow(\alpha);
Pratyush marked this conversation as resolved.
Show resolved Hide resolved
// t2 = f^p
let t2 = f.frobenius(1);
// t3 = f^((p^2)alpha) * f^(3p(alpha) + 2p)
let t3 = t2.frobenius(1).pow(alpha) * (t2.pow(3).pow(alpha) + t2.square());
let mut r = CubicExtField::one();
let n = (CubicExtField::extension_degree() - 3)/2;
for i in 1..(n+1) {
r *= t3.frobenius(2 * i);

let mut a_1 = t1 * r;
let mut x = a_1 * f;
let mut a_0 = a_1 * x;
if (a_0 == -CubicExtField::one()) {
return None;
}
x
}

/// `CubicExtField` elements are ordered lexicographically.
impl<P: CubicExtConfig> Ord for CubicExtField<P> {
impl<P: CubicExtConfig> Ord for CubicExtField<P> -> {
Pratyush marked this conversation as resolved.
Show resolved Hide resolved
#[inline(always)]
fn cmp(&self, other: &Self) -> Ordering {
let c2_cmp = self.c2.cmp(&other.c2);
Expand Down
5 changes: 2 additions & 3 deletions ff/src/fields/models/fp3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use core::marker::PhantomData;
/// Trait that specifies constants and methods for defining degree-three extension fields.
pub trait Fp3Config: 'static + Send + Sync + Sized {
/// Base prime field underlying this extension.
type Fp: PrimeField + SquareRootField;

type Fp: PrimeField;
/// Cubic non-residue in `Self::Fp` used to construct the extension
/// field. That is, `NONRESIDUE` is such that the cubic polynomial
/// `f(X) = X^3 - Self::NONRESIDUE` in Fp\[X\] is irreducible in `Self::Fp`.
Expand Down Expand Up @@ -100,7 +99,7 @@ impl<P: Fp3Config> Fp3<P> {
}
}

impl<P: Fp3Config> SquareRootField for Fp3<P> {
impl<P: Fp3Config> Field for Fp3<P> {
/// Returns the Legendre symbol.
fn legendre(&self) -> LegendreSymbol {
self.norm().legendre()
Expand Down
Loading