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

Improve documentation via better READMEs #508

Merged
merged 9 commits into from
Nov 3, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<h1 style="text-align: center;">arkworks::algebra</h1>
<h1 align="center">arkworks::algebra</h1>

<p style="text-align: center;">
<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>

The arkworks ecosystem consist of Rust libraries for designing and working with __zero knowledge succinct non-interactive arguments (zkSNARKs)__. This repository contains efficient implementations some of the key algebraic components underlying zkSNARKs: finite fields, elliptic curves, and polynomials.
The arkworks ecosystem consist of Rust libraries for designing and working with *zero knowledge succinct non-interactive arguments (zkSNARKs)*. This repository contains efficient implementations of the key algebraic components underlying zkSNARKs: finite fields, elliptic curves, and polynomials.

This library is released under the MIT License and the Apache v2 License (see [License](#license)).

@@ -17,12 +17,12 @@ This library is released under the MIT License and the Apache v2 License (see [L

This repository contains several Rust crates:

* [`ark-ff`](ff): Provides generic implementations of various finite fields
* [`ark-ec`](ec): Provides generic implementations for different kinds of elliptic curves, along with pairings over these
* [`ark-poly`](poly): Implements univariate, multivariate, and multilinear polynomials, and FFTs over finite fields.
* [`ark-serialize`](serialize): Provides efficient serialization and point compression for finite fields and elliptic curves
* [`ark-ff`](ff): Generic abstractions for, and implementations of various kinds of finite fields
* [`ark-ec`](ec): Generic abstractions for prime-order groups, and implementations of various kinds of (pairing-friendly and standard) elliptic curves
* [`ark-poly`](poly): Interfaces for univariate, multivariate, and multilinear polynomials, and FFTs over finite fields
* [`ark-serialize`](serialize): Efficient interfaces for serialization and point compression for finite fields and elliptic curves

In addition, the [`curves`](https://github.com/arkworks-rs/curves) repository contains implementations of popular elliptic curves; see [here](https://github.com/arkworks-rs/curves/README.md) for details.
In addition, the [`curves`](https://github.com/arkworks-rs/curves) repository contains concrete implementations of popular elliptic curves; see [here](https://github.com/arkworks-rs/curves/README.md) for details.

## Build guide

@@ -67,7 +67,7 @@ RUSTFLAGS="-C target-feature=+bmi2,+adx" cargo +nightly [test/build/bench] --fea
To enable this in the `Cargo.toml` of your own projects, enable the `asm` feature flag:

```toml
ark-ff = { version = "0.3.0", features = [ "asm" ] }
ark-ff = { version = "0.4", features = [ "asm" ] }
```

Note that because inline assembly support in Rust is currently unstable, using this backend requires using the Nightly compiler at the moment.
162 changes: 154 additions & 8 deletions ec/README.md
Original file line number Diff line number Diff line change
@@ -6,18 +6,164 @@
<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 Elliptic Curve traits, curve models that follow these traits, and multi-scalar multiplications.
`ark-ec` defines traits and algorithms for working with different kinds of additive groups, with a focus on groups arising from elliptic curves. It further provides concrete instantiations of these traits for various elliptic curve models, including popular families of pairing-friendly curves such as the BLS12 family of curves.
Implementations of particular curves using these curve models can be found in [`arkworks-rs/curves`](https://github.com/arkworks-rs/curves/README.md).

The available elliptic curve traits are:
## Usage

* [`AffineRepr`](https://github.com/arkworks-rs/algebra/blob/master/ec/src/lib.rs#L223) - Interface for elliptic curve points in the 'canonical form' for serialization.
* [`CurveGroup`](https://github.com/arkworks-rs/algebra/blob/master/ec/src/lib.rs#L118) - Interface for elliptic curve points in a representation that is more efficient for most computation.
* [`Pairing`](https://github.com/arkworks-rs/algebra/blob/master/ec/src/lib.rs#L41) - Pairing friendly elliptic curves (Contains the pairing function, and acts as a wrapper type on G1, G2, GT, and the relevant fields).
* [`CurveCycle`](https://github.com/arkworks-rs/algebra/blob/master/ec/src/lib.rs#L319) - Trait representing a cycle of elliptic curves.
* [`PairingFriendlyCycle`](https://github.com/arkworks-rs/algebra/blob/master/ec/src/lib.rs#L331) - Trait representing a cycle of pairing friendly elliptic curves.
### The `Group` trait

The elliptic curve models implemented are:
Many cryptographic protocols use as core building-blocks prime-order groups. The [`Group`](https://github.com/arkworks-rs/algebra/blob/master/ec/src/lib.rs) trait is an abstraction that represents elements of such abelian prime-order groups. It provides methods for performing common operations on group elements:

```rust
use ark_ec::Group;
use ark_ff::{PrimeField, Field};
// We'll use the BLS12-381 G1 curve for this example.
// This group has a prime order `r`, and is associated with a prime field `Fr`.
use ark_test_curves::bls12_381::{G1Projective as G, Fr as ScalarField};
use ark_std::{Zero, UniformRand, ops::Mul};

let mut rng = ark_std::test_rng();
// Let's sample uniformly random group elements:
let a = G::rand(&mut rng);
let b = G::rand(&mut rng);

// We can add elements, ...
let c = a + b;
// ... subtract them, ...
let d = a - b;
// ... and double them.
assert_eq!(c + d, a.double());
// We can also negate elements, ...
let e = -a;
// ... and check that negation satisfies the basic group law
assert_eq!(e + a, G::zero());

// We can also multiply group elements by elements of the corresponding scalar field
// (an act known as *scalar multiplication*)
let scalar = ScalarField::rand(&mut rng);
let e = c.mul(scalar);
let f = e.mul(scalar.inverse().unwrap());
assert_eq!(f, c);
```

## Scalar multiplication

While the `Group` trait already produces scalar multiplication routines, in many cases one can take advantage of
the group structure to perform scalar multiplication more efficiently. To allow such specialization, `ark-ec` provides
the `ScalarMul` and `VariableBaseMSM` traits. The latter trait computes an "inner product" between a vector of scalars `s` and a vector of group elements `g`. That is, it computes `s.iter().zip(g).map(|(s, g)| g * s).sum()`.

```rust
use ark_ec::{Group, VariableBaseMSM};
use ark_ff::{PrimeField, Field};
// We'll use the BLS12-381 G1 curve for this example.
// This group has a prime order `r`, and is associated with a prime field `Fr`.
use ark_test_curves::bls12_381::{G1Projective as G, G1Affine as GAffine, Fr as ScalarField};
use ark_std::{Zero, UniformRand};

let mut rng = ark_std::test_rng();
// Let's sample uniformly random group elements:
let a = GAffine::rand(&mut rng);
let b = GAffine::rand(&mut rng);

let s1 = ScalarField::rand(&mut rng);
let s2 = ScalarField::rand(&mut rng);

// Note that we're using the `GAffine` type here, as opposed to `G`.
// This is because MSMs are more efficient when the group elements are in affine form. (See below for why.)
//
// The `VariableBaseMSM` trait allows specializing the input group element representation to allow
// for more efficient implementations.
let result = G::msm(&[a, b], &[s1, s2]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something that reads odd, why is it group MSM, but GAffine base points?

(I understand the reason, just not sure if we want to note anything about this in README, or for simplicity make a,b in G)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I'll add some explanation there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added an explanation in the example; let me know if this looks better =)

assert_eq!(result, a * s1 + b * s2);
```

### Elliptic curve groups

There are two traits that are important when working with elliptic curves
over finite fields: [`CurveGroup`], and [`AffineRepr`]. Both traits
represent elements of the same curve, but provide different underlying representations.
In particular, the [`CurveGroup`] representation of a curve point is generally
more efficient for arithmetic, but does not provide a unique representative
for a curve point. An [`AffineRepr`] representation, on the other hand, *is* unique,
but is slower for most arithmetic operations. Let's explore how and when to use
these:

```rust
use ark_ec::{AffineRepr, Group, CurveGroup, VariableBaseMSM};
use ark_ff::{PrimeField, Field};
use ark_test_curves::bls12_381::{G1Projective as G, G1Affine as GAffine, Fr as ScalarField};
use ark_std::{Zero, UniformRand};

let mut rng = ark_std::test_rng();
// Let's generate an elliptic curve group element in the `CurveGroup` representation
let a = G::rand(&mut rng);
// We can convert it the `AffineRepr` representation...
let a_aff = a.into_affine();
// ... and check that the two representations are equal.
assert_eq!(a_aff, a);
// We can also convert back to the `CurveGroup` representation:
assert_eq!(a, a_aff.into_group());

// As a general rule, most group operations are slower when elements
// are represented as `AffineRepr`. However, adding an `AffineRepr`
// point to a `CurveGroup` one is usually slightly more efficient than
// adding two `CurveGroup` points.
let d = a + a_aff;
assert_eq!(d, a.double());

// This efficiency also translates into more efficient scalar multiplication routines.
let scalar = ScalarField::rand(&mut rng);
let mul_result = a_aff * scalar;
assert_eq!(a * scalar, mul_result);

// Finally, while not recommended, users can directly construct group elements
// from the x and y coordinates of the curve points. This is useful when implementing algorithms
// like hash-to-curve.
let a_x = a_aff.x;
let a_y = a_aff.y;
let is_at_infinity = a_aff.is_zero();
// This check ensures that `new_a` is indeed in the curve group, and in particular
// is within the prime-order group.
let new_a = GAffine::new(a_x, a_y);
assert_eq!(a_aff, new_a);
assert!(new_a.is_on_curve());
assert!(new_a.is_in_correct_subgroup_assuming_on_curve());
```

Besides the foregoing abstract interfaces for elliptic curve groups, `ark-ec` also provides
the following concrete instantiations of common elliptic curve models:

* [*Short Weierstrass*](https://github.com/arkworks-rs/algebra/blob/master/ec/src/models/short_weierstrass.rs) curves. The `AffineRepr` in this case is in typical Short Weierstrass point representation, and the `CurveGroup` is using points in [Jacobian Coordinates](https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates).
* [*Twisted Edwards*](https://github.com/arkworks-rs/algebra/blob/master/ec/src/models/twisted_edwards.rs) curves. The `AffineRepr` in this case is in standard Twisted Edwards curve representation, whereas the `CurveGroup` uses points in [Extended Twisted Edwards Coordinates](https://eprint.iacr.org/2008/522.pdf).

### Pairings

[`Pairing`](https://github.com/arkworks-rs/algebra/blob/master/ec/src/pairing.rs) is a trait that defines the interface for a pairing-friendly elliptic curve. Besides the general interface, we provide concrete instantiations of popular pairing-friendly families of curves, such as the [Barreto-Lynn-Scott](https://github.com/arkworks-rs/algebra/blob/master/ec/src/models/bls12/mod.rs) and [Barreto-Naehrig](https://github.com/arkworks-rs/algebra/blob/master/ec/src/models/bn/mod.rs) families.

```rust
use ark_ec::{pairing::Pairing, AffineRepr};
use ark_ff::Field;
use ark_std::UniformRand;

use ark_test_curves::bls12_381::{Bls12_381, G1Projective as G1, G2Projective as G2, Fq12 as Fq12};
use ark_test_curves::bls12_381::Fr as ScalarField;

// The pairing engine is parameterized by the scalar field of the curve.
let mut rng = ark_std::test_rng();
let s = ScalarField::rand(&mut rng);
let a = G1::rand(&mut rng);
let b = G2::rand(&mut rng);

// We can compute the pairing of two points on the curve, either monolithically...
let e1 = Bls12_381::pairing(a, b);
// ... or in two steps. First, we compute the Miller loop...
let ml_result = Bls12_381::miller_loop(a, b);
// ... and then the final exponentiation.
let e2 = Bls12_381::final_exponentiation(ml_result).unwrap();
assert_eq!(e1, e2);
```

### Hash-to-group

`ark-ec` also provides traits for hashing to elliptic curve groups. The [`HashToCurve`](https://github.com/arkworks-rs/algebra/blob/master/ec/src/hashing/mod.rs) trait allows users to hash arbitrary byte strings to elliptic curve group elements, and allows using different hashing strategies.
1 change: 1 addition & 0 deletions ec/src/lib.rs
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
clippy::suspicious_op_assign_impl,
clippy::many_single_char_names
)]
#![doc = include_str!("../README.md")]

#[macro_use]
extern crate derivative;
97 changes: 97 additions & 0 deletions ff/README.md
Original file line number Diff line number Diff line change
@@ -36,3 +36,100 @@ The above two models serve as abstractions for constructing the extension fields
- [`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 `Fp6_3over2`, i.e. `BaseField = Fp6`.

## Usage

There are two important traits when working with finite fields: [`Field`],
and [`PrimeField`]. Let's explore these via examples.

### [`Field`]

The [`Field`] trait provides a generic interface for any finite field.
Types implementing [`Field`] support common field operations
such as addition, subtraction, multiplication, and inverses.

```rust
use ark_ff::Field;
// We'll use a field associated with the BLS12-381 pairing-friendly
// group for this example.
use ark_test_curves::bls12_381::Fq2 as F;
// `ark-std` is a utility crate that enables `arkworks` libraries
// to easily support `std` and `no_std` workloads, and also re-exports
// useful crates that should be common across the entire ecosystem, such as `rand`.
use ark_std::{One, UniformRand};

let mut rng = ark_std::test_rng();
// Let's sample uniformly random field elements:
let a = F::rand(&mut rng);
let b = F::rand(&mut rng);

// We can add...
let c = a + b;
// ... subtract ...
let d = a - b;
// ... double elements ...
assert_eq!(c + d, a.double());

// ... multiply ...
let e = c * d;
// ... square elements ...
assert_eq!(e, a.square() - b.square());

// ... and compute inverses ...
assert_eq!(a.inverse().unwrap() * a, F::one()); // have to to unwrap, as `a` could be zero.
```

In some cases, it is useful to be able to compute square roots of field elements
(e.g.: for point compression of elliptic curve elements).
To support this, users can implement the `sqrt`-related methods for their field type. This method
is already implemented for prime fields (see below), and also for quadratic extension fields.

The `sqrt`-related methods can be used as follows:

```rust
use ark_ff::Field;
// As before, we'll use a field associated with the BLS12-381 pairing-friendly
// group for this example.
use ark_test_curves::bls12_381::Fq2 as F;
use ark_std::{One, UniformRand};

let mut rng = ark_std::test_rng();
let a = F::rand(&mut rng);

// We can check if a field element is a square by computing its Legendre symbol...
if a.legendre().is_qr() {
// ... and if it is, we can compute its square root.
let b = a.sqrt().unwrap();
assert_eq!(b.square(), a);
} else {
// Otherwise, we can check that the square root is `None`.
assert_eq!(a.sqrt(), None);
}
```

### [`PrimeField`]

If the field is of prime order, then users can choose
to implement the [`PrimeField`] trait for it. This provides access to the following
additional APIs:

```rust
use ark_ff::{Field, PrimeField, FpConfig, BigInteger};
// Now we'll use the prime field underlying the BLS12-381 G1 curve.
use ark_test_curves::bls12_381::Fq as F;
use ark_std::{One, Zero, UniformRand};

let mut rng = ark_std::test_rng();
let a = F::rand(&mut rng);
// We can access the prime modulus associated with `F`:
let modulus = <F as PrimeField>::MODULUS;
assert_eq!(a.pow(&modulus), a);

// We can convert field elements to integers in the range [0, MODULUS - 1]:
let one: num_bigint::BigUint = F::one().into();
assert_eq!(one, num_bigint::BigUint::one());

// We can construct field elements from an arbitrary sequence of bytes:
let n = F::from_le_bytes_mod_order(&modulus.to_bytes_le());
assert_eq!(n, F::zero());
```
10 changes: 5 additions & 5 deletions ff/src/biginteger/mod.rs
Original file line number Diff line number Diff line change
@@ -797,7 +797,7 @@ pub trait BigInteger:
/// zero.mul2();
/// assert_eq!(zero, B::from(0u64));
///
/// let mut arr : [bool; 64] = [false; 64];
/// let mut arr: [bool; 64] = [false; 64];
/// arr[0] = true;
/// let mut mul = B::from_bits_be(&arr);
/// mul.mul2();
@@ -822,7 +822,7 @@ pub trait BigInteger:
/// zero.muln(5);
/// assert_eq!(zero, B::from(0u64));
///
/// let mut arr : [bool; 64] = [false; 64];
/// let mut arr: [bool; 64] = [false; 64];
/// arr[4] = true;
/// let mut mul = B::from_bits_be(&arr);
/// mul.muln(5);
@@ -865,7 +865,7 @@ pub trait BigInteger:
/// assert_eq!(one, thirty_two_div);
///
/// // Edge-Case
/// let mut arr : [bool; 64] = [false; 64];
/// let mut arr: [bool; 64] = [false; 64];
/// arr[4] = true;
/// let mut div = B::from_bits_le(&arr);
/// div.divn(5);
@@ -941,7 +941,7 @@ pub trait BigInteger:
/// ```
/// use ark_ff::{biginteger::BigInteger64 as B, BigInteger as _};
///
/// let mut arr : [bool; 64] = [false; 64];
/// let mut arr: [bool; 64] = [false; 64];
/// arr[63] = true;
/// let mut one = B::from(1u64);
/// assert_eq!(B::from_bits_be(&arr), one);
@@ -955,7 +955,7 @@ pub trait BigInteger:
/// ```
/// use ark_ff::{biginteger::BigInteger64 as B, BigInteger as _};
///
/// let mut arr : [bool; 64] = [false; 64];
/// let mut arr: [bool; 64] = [false; 64];
/// arr[0] = true;
/// let mut one = B::from(1u64);
/// assert_eq!(B::from_bits_le(&arr), one);
2 changes: 1 addition & 1 deletion ff/src/fields/field_hashers/mod.rs
Original file line number Diff line number Diff line change
@@ -28,8 +28,8 @@ pub trait HashToField<F: Field>: Sized {
/// # Examples
///
/// ```
/// use ark_test_curves::bls12_381::Fq;
/// use ark_ff::fields::field_hashers::{DefaultFieldHasher, HashToField};
/// use ark_test_curves::bls12_381::Fq;
/// use sha2::Sha256;
///
/// let hasher = <DefaultFieldHasher<Sha256> as HashToField<Fq>>::new(&[1, 2, 3]);
3 changes: 1 addition & 2 deletions ff/src/fields/mod.rs
Original file line number Diff line number Diff line change
@@ -387,8 +387,7 @@ mod std_tests {
#[cfg(test)]
mod no_std_tests {
use super::*;
use ark_std::str::FromStr;
use ark_std::test_rng;
use ark_std::{str::FromStr, test_rng};
use num_bigint::*;

// TODO: only Fr & FrConfig should need to be imported.
Loading