Skip to content

Commit

Permalink
Documentation for the ff crate (#334)
Browse files Browse the repository at this point in the history
* Add the ff README

* Start the documentation for extension field fp2

* Document definitions in macros

* Make the test_field module usable in doctests

Doctest should have access to test_fields.
Since doctests are not run within the context of the current crate, they need to
import the ark_ff crate as `extern` (this happens implicitly) - and since
test_field was public only within the crate, this wouldn't work.

* Add first doctests to ark_ff

- fp2.rs: mul_assign_by_fp

* Quadratic extension docs & doctests

* Add TODO for Fp2

Should we replace the `mul_assign_by_fp` with a method from QuadExtParametes?

* Docs & doctests for LegendreSymbol

* Document missing items from fields/mod.rs

* Expand the README draft

Explain the models, difference between Fp2/QuadExt, fields vs. parameters traits

* Doctests cfg attribute fix

Seems that the tests are collected well, but items with `cfg(doctest)` are not
included in the compilation of doctests

* Apply suggestions from code review

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>

* Add fq2 to test-curves crate

* Replace the usage of test_field by external crate

Instead of using
```
use arf_ff...
```
in doctests, now use instead:
```
use arf_test_curves...
```

* Revert "Make the test_field module usable in doctests"

This reverts commit 923a8c6.

* Formatting and cleanup

* Apply suggestions from code review

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>

* Fix the stringification of macro attribute in rustdoc

* Simplify the FpXParameters doc

* Doc test for CubicExtField::new(...)

* Add an extensive doctest for quadratic extension norm()

* Apply suggestions from code review

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>

* Add more precise description for mul_by_fp & mul_by_basefield

* Make an explicit distinction between BaseField and BasePrimeField

* Fix the README links & formatting

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>
  • Loading branch information
mmagician and Pratyush authored Dec 22, 2021
1 parent 2ce9db4 commit dabf462
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 2 deletions.
39 changes: 39 additions & 0 deletions ff/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<h1 align="center">ark-ff</h1>
<p align="center">
<img src="https://github.com/arkworks-rs/algebra/workflows/CI/badge.svg?branch=master">
<a href="https://github.com/arkworks-rs/algebra/blob/master/LICENSE-APACHE"><img src="https://img.shields.io/badge/license-APACHE-blue.svg"></a>
<a href="https://github.com/arkworks-rs/algebra/blob/master/LICENSE-MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
<a href="https://deps.rs/repo/github/arkworks-rs/algebra"><img src="https://deps.rs/repo/github/arkworks-rs/algebra/status.svg"></a>
</p>

This crate defines Finite Field traits and useful abstraction models that follow these traits.
Implementations of finite fields with concrete parameters can be found in [`arkworks-rs/curves`](https://github.com/arkworks-rs/curves/README.md) under `arkworks-rs/curves/<your favourite curve>/src/fields/`, which are used for some of the popular curves, such as a specific [`Fq`](https://github.com/arkworks-rs/curves/blob/master/bls12_381/src/fields/fq.rs) used in BLS-381.

This crate contains two types of traits:

- `Field` traits: These define interfaces for manipulating field elements, such as addition, multiplication, inverses, square roots, and more.
- Field Parameters: holds the parameters defining the field in question. For extension fields, it also provides additional functionality required for the field, such as operations involving a (cubic or quadratic) non-residue used for constructing the field (`NONRESIDUE`).

The available field traits are:

- [`Field`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L66) - Interface for the most generic finte field
- [`FftField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L275) - Exposes methods that allow for performing efficient FFTs on this field's elements
- [`PrimeField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L347) - Field with `p` (`p` prime) elements, later referred to as `Fp`.
- [`SquareRootField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/mod.rs#L431) - Interface for fields that support square-root operations

The models implemented are:

- [`Quadratic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs)
- [`QuadExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L140) - Struct representing a quadratic extension field, in this case holding two elements
- [`QuadExtParameters`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/quadratic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Quadratic Extension Field
- [`Cubic Extension`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs)
- [`CubicExtField`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L72) - Struct representing a cubic extension field, holds three elements
- [`CubicExtParameters`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/cubic_extension.rs#L27) - Trait defining the necessary parameters needed to instantiate a Cubic Extension Field

The above two models serve as abstractions for constructing the extension fields `Fp^m` directly (i.e. `m` equal 2 or 3) or for creating extension towers to arrive at higher `m`. The latter is done by applying the extensions iteratively, e.g. cubic extension over a quadratic extension field.

- [`Fp2`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp2.rs#L103) - Quadratic extension directly on the prime field, i.e. `BaseField == BasePrimeField`
- [`Fp3`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp3.rs#L54) - Cubic extension directly on the prime field, i.e. `BaseField == BasePrimeField`
- [`Fp6_2over3`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp6_2over3.rs#L48) - Extension tower: quadratic extension on a cubic extension field, i.e. `BaseField = Fp3`, but `BasePrimeField = Fp`.
- [`Fp6_3over2`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp6_3over2.rs#L49) - Extension tower, similar to the above except that the towering order is reversed: it's a cubic extension on a quadratic extension field, i.e. `BaseField = Fp2`, but `BasePrimeField = Fp`. Only this latter one is exported by default as `Fp6`.
- [`Fp12_2over3over2`](https://github.com/arkworks-rs/algebra/blob/master/ff/src/fields/models/fp12_2over3over2.rs#L83) - Extension tower: quadratic extension of the `Fp6_3over2`, i.e. `BaseField = Fp6`.
6 changes: 6 additions & 0 deletions ff/src/fields/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ macro_rules! impl_prime_field_serializer {

macro_rules! impl_Fp {
($Fp:ident, $FpParameters:ident, $BigInteger:ident, $BigIntegerType:ty, $limbs:expr, $field_size:expr) => {
/// Trait for prime field parameters of size at most
#[doc = $field_size]
/// bits.
pub trait $FpParameters: FpParameters<BigInt = $BigIntegerType> {}

/// Represents an element of the prime field F_p, where `p == P::MODULUS`.
Expand All @@ -112,6 +115,9 @@ macro_rules! impl_Fp {
);

impl<P> $Fp<P> {
/// Construct a new prime element directly from its underlying
/// `BigInteger` data type. The `BigInteger` should be in
/// Montgomery representation. If it is not, use `Self::from_repr`.
#[inline]
pub const fn new(element: $BigIntegerType) -> Self {
Self(element, PhantomData)
Expand Down
52 changes: 50 additions & 2 deletions ff/src/fields/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ pub trait Field:
#[must_use]
fn inverse(&self) -> Option<Self>;

// If `self.inverse().is_none()`, this just returns `None`. Otherwise, it sets
// `self` to `self.inverse().unwrap()`.
/// If `self.inverse().is_none()`, this just returns `None`. Otherwise, it sets
/// `self` to `self.inverse().unwrap()`.
fn inverse_in_place(&mut self) -> Option<&mut Self>;

/// Exponentiates this element by a power of the base prime modulus via
Expand Down Expand Up @@ -353,7 +353,10 @@ pub trait PrimeField:
+ From<BigUint>
+ Into<BigUint>
{
/// Associated `FpParameters` that define this field.
type Params: FpParameters<BigInt = Self::BigInt>;

/// A `BigInteger` type that can represent elements of this field.
type BigInt: BigInteger;

/// Returns a prime field element from its underlying representation.
Expand Down Expand Up @@ -445,6 +448,18 @@ pub trait SquareRootField: Field {
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_test_curves::bls12_381::Fq as Fp;
/// # use ark_std::UniformRand;
/// # use ark_ff::{LegendreSymbol, Field, SquareRootField};
/// let a: Fp = Fp::rand(&mut test_rng());
/// let b = a.square();
/// assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
/// ```
#[derive(Debug, PartialEq)]
pub enum LegendreSymbol {
Zero = 0,
Expand All @@ -453,14 +468,47 @@ pub enum LegendreSymbol {
}

impl LegendreSymbol {
/// Returns true if `self.is_zero()`.
///
/// # Examples
/// ```
/// # use ark_std::test_rng;
/// # use ark_test_curves::bls12_381::Fq as Fp;
/// # use ark_std::UniformRand;
/// # use ark_ff::{LegendreSymbol, Field, SquareRootField};
/// let a: Fp = Fp::rand(&mut test_rng());
/// let b: Fp = a.square();
/// assert!(!b.legendre().is_zero());
/// ```
pub fn is_zero(&self) -> bool {
*self == LegendreSymbol::Zero
}

/// Returns true if `self` is a quadratic non-residue.
///
/// # Examples
/// ```
/// # use ark_test_curves::bls12_381::{Fq, Fq2Parameters};
/// # use ark_ff::{LegendreSymbol, SquareRootField};
/// # use ark_ff::Fp2Parameters;
/// let a: Fq = Fq2Parameters::NONRESIDUE;
/// assert!(a.legendre().is_qnr());
/// ```
pub fn is_qnr(&self) -> bool {
*self == LegendreSymbol::QuadraticNonResidue
}

/// Returns true if `self` is a quadratic residue.
/// # Examples
/// ```
/// # use ark_std::test_rng;
/// # use ark_test_curves::bls12_381::Fq as Fp;
/// # use ark_std::UniformRand;
/// # use ark_ff::{LegendreSymbol, Field, SquareRootField};
/// let a: Fp = Fp::rand(&mut test_rng());
/// let b: Fp = a.square();
/// assert!(b.legendre().is_qr());
/// ```
pub fn is_qr(&self) -> bool {
*self == LegendreSymbol::QuadraticResidue
}
Expand Down
27 changes: 27 additions & 0 deletions ff/src/fields/models/cubic_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ use crate::{
ToConstraintField, UniformRand,
};

/// Defines a Cubic extension field from a cubic non-residue.
pub trait CubicExtParameters: 'static + Send + Sync {
/// The prime field that this cubic extension is eventually an extension of.
type BasePrimeField: PrimeField;
/// The base field that this field is a cubic extension of.
///
/// Note: while for simple instances of cubic extensions such as `Fp3`
/// we might see `BaseField == BasePrimeField`, it won't always hold true.
/// E.g. for an extension tower: `BasePrimeField == Fp`, but `BaseField == Fp2`.
type BaseField: Field<BasePrimeField = Self::BasePrimeField>;
/// The type of the coefficients for an efficient implemntation of the
/// Frobenius endomorphism.
Expand Down Expand Up @@ -59,6 +64,8 @@ pub trait CubicExtParameters: 'static + Send + Sync {
);
}

/// An element of a cubic extension field F_p\[X\]/(X^3 - P::NONRESIDUE) is
/// represented as c0 + c1 * X + c2 * X^2, for c0, c1, c2 in `P::BaseField`.
#[derive(Derivative)]
#[derivative(
Default(bound = "P: CubicExtParameters"),
Expand All @@ -76,6 +83,26 @@ pub struct CubicExtField<P: CubicExtParameters> {
}

impl<P: CubicExtParameters> CubicExtField<P> {
/// Create a new field element from coefficients `c0`, `c1` and `c2`
/// so that the result is of the form `c0 + c1 * X + c2 * X^2`.
///
/// # Examples
///
/// ```
/// # use ark_std::test_rng;
/// # use ark_test_curves::bls12_381::{Fq2 as Fp2, Fq6 as Fp6};
/// # use ark_test_curves::bls12_381::Fq6Parameters;
/// # use ark_std::UniformRand;
/// # use ark_ff::models::fp6_3over2::Fp6ParamsWrapper;
/// use ark_ff::models::cubic_extension::CubicExtField;
///
/// let c0: Fp2 = Fp2::rand(&mut test_rng());
/// let c1: Fp2 = Fp2::rand(&mut test_rng());
/// let c2: Fp2 = Fp2::rand(&mut test_rng());
/// # type Params = Fp6ParamsWrapper<Fq6Parameters>;
/// // `Fp6` a degree-3 extension over `Fp2`.
/// let c: CubicExtField<Params> = Fp6::new(c0, c1, c2);
/// ```
pub fn new(c0: P::BaseField, c1: P::BaseField, c2: P::BaseField) -> Self {
Self { c0, c1, c2 }
}
Expand Down
29 changes: 29 additions & 0 deletions ff/src/fields/models/fp2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ use super::quadratic_extension::*;
use crate::fields::PrimeField;
use core::marker::PhantomData;

/// Parameters for defining degree-two extension fields.
pub trait Fp2Parameters: 'static + Send + Sync {
/// Base prime field underlying this extension.
type Fp: PrimeField;

/// Quadratic non-residue in `Self::Fp` used to construct the extension
/// field. That is, `NONRESIDUE` is such that the quadratic polynomial
/// `f(X) = X^2 - Self::NONRESIDUE` in Fp\[X\] is irreducible in `Self::Fp`.
const NONRESIDUE: Self::Fp;

/// A quadratic nonresidue in Fp2, used for calculating square roots in Fp2.
const QUADRATIC_NONRESIDUE: (Self::Fp, Self::Fp);

/// Coefficients for the Frobenius automorphism.
Expand Down Expand Up @@ -44,6 +50,7 @@ pub trait Fp2Parameters: 'static + Send + Sync {
}
}

/// Wrapper for Fp2Parameters, allowing combination of Fp2Parameters & QuadExtParameters traits
pub struct Fp2ParamsWrapper<P: Fp2Parameters>(PhantomData<P>);

impl<P: Fp2Parameters> QuadExtParameters for Fp2ParamsWrapper<P> {
Expand Down Expand Up @@ -91,9 +98,31 @@ impl<P: Fp2Parameters> QuadExtParameters for Fp2ParamsWrapper<P> {
}
}

/// Alias for instances of quadratic extension fields. Helpful for omitting verbose
/// instantiations involving `Fp2ParamsWrapper`.
pub type Fp2<P> = QuadExtField<Fp2ParamsWrapper<P>>;

impl<P: Fp2Parameters> Fp2<P> {
/// In-place multiply both coefficients `c0` & `c1` of the extension field
/// `Fp2` by an element from `Fp`. The coefficients themselves
/// are elements of `Fp`.
///
/// # Examples
///
/// ```
/// # use ark_std::test_rng;
/// # use ark_test_curves::bls12_381::{Fq as Fp, Fq2 as Fp2};
/// # use ark_std::UniformRand;
/// let c0: Fp = Fp::rand(&mut test_rng());
/// let c1: Fp = Fp::rand(&mut test_rng());
/// let mut ext_element: Fp2 = Fp2::new(c0, c1);
///
/// let base_field_element: Fp = Fp::rand(&mut test_rng());
/// ext_element.mul_assign_by_fp(&base_field_element);
///
/// assert_eq!(ext_element.c0, c0*base_field_element);
/// assert_eq!(ext_element.c1, c1*base_field_element);
/// ```
pub fn mul_assign_by_fp(&mut self, other: &P::Fp) {
self.c0 *= other;
self.c1 *= other;
Expand Down
41 changes: 41 additions & 0 deletions ff/src/fields/models/quadratic_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ pub trait QuadExtParameters: 'static + Send + Sync + Sized {
/// The prime field that this quadratic extension is eventually an extension of.
type BasePrimeField: PrimeField;
/// The base field that this field is a quadratic extension of.
///
/// Note: while for simple instances of quadratic extensions such as `Fp2`
/// we might see `BaseField == BasePrimeField`, it won't always hold true.
/// E.g. for an extension tower: `BasePrimeField == Fp`, but `BaseField == Fp3`.
type BaseField: Field<BasePrimeField = Self::BasePrimeField>;
/// The type of the coefficients for an efficient implemntation of the
/// Frobenius endomorphism.
Expand Down Expand Up @@ -132,11 +136,27 @@ pub trait QuadExtParameters: 'static + Send + Sync + Sized {
Eq(bound = "P: QuadExtParameters")
)]
pub struct QuadExtField<P: QuadExtParameters> {
/// Coefficient `c0` in the representation of the field element `c = c0 + c1 * X`
pub c0: P::BaseField,
/// Coefficient `c1` in the representation of the field element `c = c0 + c1 * X`
pub c1: P::BaseField,
}

impl<P: QuadExtParameters> QuadExtField<P> {
/// Create a new field element from coefficients `c0` and `c1`,
/// so that the result is of the form `c0 + c1 * X`.
///
/// # Examples
///
/// ```
/// # use ark_std::test_rng;
/// # use ark_test_curves::bls12_381::{Fq as Fp, Fq2 as Fp2};
/// # use ark_std::UniformRand;
/// let c0: Fp = Fp::rand(&mut test_rng());
/// let c1: Fp = Fp::rand(&mut test_rng());
/// // `Fp2` a degree-2 extension over `Fp`.
/// let c: Fp2 = Fp2::new(c0, c1);
/// ```
pub fn new(c0: P::BaseField, c1: P::BaseField) -> Self {
Self { c0, c1 }
}
Expand All @@ -156,6 +176,25 @@ impl<P: QuadExtParameters> QuadExtField<P> {
/// Norm of QuadExtField over `P::BaseField`:`Norm(a) = a * a.conjugate()`.
/// This simplifies to: `Norm(a) = a.x^2 - P::NON_RESIDUE * a.y^2`.
/// This is alternatively expressed as `Norm(a) = a^(1 + p)`.
///
/// # Examples
/// ```
/// # use ark_std::test_rng;
/// # use ark_std::{UniformRand, Zero};
/// # use ark_test_curves::{Field, bls12_381::Fq2 as Fp2};
/// let c: Fp2 = Fp2::rand(&mut test_rng());
/// 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.
/// let mut c_conjugate = c;
/// c_conjugate.frobenius_map(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`
/// assert!(norm2.c1.is_zero());
/// assert_eq!(norm, norm2.c0);
/// ```
pub fn norm(&self) -> P::BaseField {
let t0 = self.c0.square();
// t1 = t0 - P::NON_RESIDUE * c1^2
Expand All @@ -164,6 +203,8 @@ impl<P: QuadExtParameters> QuadExtField<P> {
t1
}

/// In-place multiply both coefficients `c0` & `c1` of the quadratic
/// extension field by an element from the base field.
pub fn mul_assign_by_basefield(&mut self, element: &P::BaseField) {
self.c0.mul_assign(element);
self.c1.mul_assign(element);
Expand Down

0 comments on commit dabf462

Please sign in to comment.