Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into vec-allocator
Browse files Browse the repository at this point in the history
* upstream/master:
  Update hashbrown requirement from 0.12.1 to 0.13.1 (arkworks-rs#515)
  Update libtest-mimic requirement from 0.5.2 to 0.6.0 (arkworks-rs#514)
  Update changelog (arkworks-rs#511)
  Add a Discord link (arkworks-rs#510)
  Improve documentation via better READMEs (arkworks-rs#508)
  • Loading branch information
andrewmilson committed Nov 25, 2022
2 parents 5faa166 + e062140 commit 9547f2f
Show file tree
Hide file tree
Showing 18 changed files with 412 additions and 35 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
- Rename some associated types:
- `AffineCurve``Affine`
- Rename some methods:
- `batch_normalization_to_affine``normalize_batch`
- `batch_normalization_into_affine``normalize_batch`
- Rename `AffineCurve` to `Affine`.
- Rename associated types:
- `Projective``Group`
Expand All @@ -90,6 +90,8 @@
- `miller_loop``multi_miller_loop`
- `pairing``multi_pairing`
- Change method signatures:
- `product_of_pairings` -> `multi_pairing`
- take two references to element iterators instead of an iterator of tuples.
- `miller_loop` and `multi_miller_loop` now
- take two iterators over `impl Into<G1Prepared>` and `impl Into<G2Prepared>` as input, and
- output `MillerLoopOutput`, which is a newtype wrapper around `TargetField`.
Expand Down
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<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>
<a href="https://discord.gg/UNtS7QXyPk"><img src="https://img.shields.io/discord/908465643727253524?label=Discord&logo=discord"></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)).

Expand All @@ -17,12 +18,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

Expand Down Expand Up @@ -67,7 +68,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.
Expand Down
4 changes: 2 additions & 2 deletions ec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ derivative = { version = "2", features = ["use_core"] }
num-traits = { version = "0.2", default-features = false }
rayon = { version = "1", optional = true }
zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] }
hashbrown = "0.12.1"
hashbrown = "0.13.1"
itertools = { version = "0.10", default-features = false }

[dev-dependencies]
ark-test-curves = { version = "^0.3.0", path = "../test-curves", default-features = false, features = ["bls12_381_curve"] }
sha2 = { version = "0.10", default-features = false }
libtest-mimic = "0.5.2"
libtest-mimic = "0.6.0"
serde = "1.0.110"
serde_json = "1.0.53"
serde_derive = "1.0.110"
Expand Down
162 changes: 154 additions & 8 deletions ec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
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
Expand Up @@ -12,6 +12,7 @@
clippy::suspicious_op_assign_impl,
clippy::many_single_char_names
)]
#![doc = include_str!("../README.md")]

#[macro_use]
extern crate derivative;
Expand Down
2 changes: 1 addition & 1 deletion ff/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ ark-test-curves = { version = "^0.3.0", path = "../test-curves", default-feature
blake2 = { version = "0.10", default-features = false }
sha3 = { version = "0.10", default-features = false }
sha2 = { version = "0.10", default-features = false }
libtest-mimic = "0.5.2"
libtest-mimic = "0.6.0"
serde = "1.0.110"
serde_json = "1.0.53"
serde_derive = "1.0.110"
Expand Down
97 changes: 97 additions & 0 deletions ff/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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());
```
Loading

0 comments on commit 9547f2f

Please sign in to comment.