diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 859e8bb..2566161 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: 1.51.0 override: true - name: Run tests uses: actions-rs/cargo@v1 @@ -37,7 +37,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: 1.51.0 override: true - name: Add target run: rustup target add ${{ matrix.target }} @@ -55,7 +55,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: 1.51.0 override: true # Build benchmarks to prevent bitrot - name: Build benchmarks @@ -71,7 +71,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: 1.51.0 override: true - name: cargo build uses: actions-rs/cargo@v1 @@ -85,7 +85,7 @@ jobs: run: mdbook test -L target/debug/deps book/ clippy: - name: Clippy (stable) + name: Clippy (1.51.0) timeout-minutes: 30 runs-on: ubuntu-latest @@ -93,13 +93,13 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: 1.51.0 components: clippy override: true - name: Run clippy uses: actions-rs/clippy-check@v1 with: - name: Clippy (stable) + name: Clippy (1.51.0) token: ${{ secrets.GITHUB_TOKEN }} args: --all-features --all-targets -- -D warnings @@ -158,7 +158,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: 1.51.0 override: true - name: cargo fetch uses: actions-rs/cargo@v1 @@ -181,7 +181,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: 1.51.0 override: true - run: rustup component add rustfmt - uses: actions-rs/cargo@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index bafd9c5..5fea405 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,4 +6,6 @@ and this project adheres to Rust's notion of [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [0.1.0] - 2021-06-01 Initial release! diff --git a/Cargo.toml b/Cargo.toml index bdb9213..4f543de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "pasta_curves" description = "Implementation of the Pallas and Vesta (Pasta) curve cycle" -version = "0.0.0" +version = "0.1.0" authors = [ "Sean Bowe ", "Ying Tong Lai ", @@ -13,9 +13,7 @@ license-file = "LICENSE-BOSL" repository = "https://github.com/zcash/pasta_curves" documentation = "https://docs.rs/pasta_curves" readme = "README.md" - -# We are not publishing this yet. -publish = false +exclude = ["Contributor_Agreement"] [package.metadata.docs.rs] all-features = true @@ -39,12 +37,13 @@ harness = false [dependencies] subtle = "2.3" -ff = "0.9" -group = "0.9" +ff = "0.10" +group = "0.10" rand = "0.8" blake2b_simd = "0.5" lazy_static = "1.4.0" static_assertions = "1.1.0" -# Temporary workaround for https://github.com/myrrlyn/funty/issues/3 -funty = "=1.1.0" +[features] +default = ["bits"] +bits = ["ff/bits"] diff --git a/README.md b/README.md index cbace05..20813c8 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,35 @@ # `pasta_curves` -**IMPORTANT**: This library is being actively developed and should not be used in production software. +This crate provides an implementation of the Pasta elliptic curve constructions, +Pallas and Vesta. More details about the Pasta curves can be found +[in this blog post](https://electriccoin.co/blog/the-pasta-curves-for-halo-2-and-beyond/). ## [Documentation](https://docs.rs/pasta_curves) -This crate currently has a Minimum Supported Rust Version of 1.49.0. When const generics -are stabilized [in Rust 1.51.0](https://github.com/rust-lang/rust/pull/79135), we plan -to require that version. +## Minimum Supported Rust Version + +Requires Rust **1.51** or higher. + +Minimum supported Rust version can be changed in the future, but it will be done with a +minor version bump. + +## Curve Descriptions + +- Pallas: y2 = x3 + 5 over + `GF(0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001)`. + +- Vesta: y2 = x3 + 5 over + `GF(0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001)`. + +The Pasta curves form a cycle with one another: the order of each curve is exactly the +base field of the other. This property is critical to the efficiency of recursive proof +systems. They are designed to be highly 2-adic, meaning that a large power-of-two +multiplicative subgroup exists in each field. This is important for the performance of +polynomial arithmetic over their scalar fields and is essential for protocols similar +to PLONK. + +These curves can be reproducibly obtained +[using a curve search utility we’ve published](https://github.com/zcash/pasta). ## License diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..ba0a719 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +1.51.0 diff --git a/src/arithmetic/fields.rs b/src/arithmetic/fields.rs index 664aade..2d774f6 100644 --- a/src/arithmetic/fields.rs +++ b/src/arithmetic/fields.rs @@ -219,8 +219,8 @@ impl SqrtTables { // Now invert gtab[3]. let mut inv: Vec = vec![1; hash_mod]; - for j in 0..256 { - let hash = hasher.hash(>ab_3[j]); + for (j, gtab_3_j) in gtab_3.iter().enumerate() { + let hash = hasher.hash(gtab_3_j); // 1 is the last value to be assigned, so this ensures there are no collisions. assert!(inv[hash] == 1); inv[hash] = ((256 - j) & 0xFF) as u8; diff --git a/src/fields/fp.rs b/src/fields/fp.rs index 406d76c..d72b0ee 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -1,11 +1,13 @@ use core::convert::TryInto; use core::fmt; use core::ops::{Add, Mul, Neg, Sub}; -use ff::FieldBits; use lazy_static::lazy_static; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +#[cfg(feature = "bits")] +use ff::{FieldBits, PrimeFieldBits}; + use crate::arithmetic::{adc, mac, sbb, FieldExt, Group, SqrtTables}; /// This represents an element of $\mathbb{F}_p$ where @@ -529,15 +531,8 @@ impl ff::Field for Fp { } } -#[cfg(not(target_pointer_width = "64"))] -type ReprBits = [u32; 8]; - -#[cfg(target_pointer_width = "64")] -type ReprBits = [u64; 4]; - impl ff::PrimeField for Fp { type Repr = [u8; 32]; - type ReprBits = ReprBits; const NUM_BITS: u32 = 255; const CAPACITY: u32 = 254; @@ -551,6 +546,29 @@ impl ff::PrimeField for Fp { self.to_bytes() } + fn is_odd(&self) -> bool { + self.to_bytes()[0] & 1 == 1 + } + + fn multiplicative_generator() -> Self { + GENERATOR + } + + fn root_of_unity() -> Self { + Self::ROOT_OF_UNITY + } +} + +#[cfg(all(feature = "bits", not(target_pointer_width = "64")))] +type ReprBits = [u32; 8]; + +#[cfg(all(feature = "bits", target_pointer_width = "64"))] +type ReprBits = [u64; 4]; + +#[cfg(feature = "bits")] +impl PrimeFieldBits for Fp { + type ReprBits = ReprBits; + fn to_le_bits(&self) -> FieldBits { let bytes = self.to_bytes(); @@ -577,10 +595,6 @@ impl ff::PrimeField for Fp { FieldBits::new(limbs) } - fn is_odd(&self) -> bool { - self.to_bytes()[0] & 1 == 1 - } - fn char_le_bits() -> FieldBits { #[cfg(not(target_pointer_width = "64"))] { @@ -590,14 +604,6 @@ impl ff::PrimeField for Fp { #[cfg(target_pointer_width = "64")] FieldBits::new(MODULUS.0) } - - fn multiplicative_generator() -> Self { - GENERATOR - } - - fn root_of_unity() -> Self { - Self::ROOT_OF_UNITY - } } lazy_static! { diff --git a/src/fields/fq.rs b/src/fields/fq.rs index cc8954a..3bf0b1f 100644 --- a/src/fields/fq.rs +++ b/src/fields/fq.rs @@ -1,11 +1,13 @@ use core::convert::TryInto; use core::fmt; use core::ops::{Add, Mul, Neg, Sub}; -use ff::FieldBits; use lazy_static::lazy_static; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +#[cfg(feature = "bits")] +use ff::{FieldBits, PrimeFieldBits}; + use crate::arithmetic::{adc, mac, sbb, FieldExt, Group, SqrtTables}; /// This represents an element of $\mathbb{F}_q$ where @@ -529,15 +531,8 @@ impl ff::Field for Fq { } } -#[cfg(not(target_pointer_width = "64"))] -type ReprBits = [u32; 8]; - -#[cfg(target_pointer_width = "64")] -type ReprBits = [u64; 4]; - impl ff::PrimeField for Fq { type Repr = [u8; 32]; - type ReprBits = ReprBits; const NUM_BITS: u32 = 255; const CAPACITY: u32 = 254; @@ -551,6 +546,29 @@ impl ff::PrimeField for Fq { self.to_bytes() } + fn is_odd(&self) -> bool { + self.to_bytes()[0] & 1 == 1 + } + + fn multiplicative_generator() -> Self { + GENERATOR + } + + fn root_of_unity() -> Self { + Self::ROOT_OF_UNITY + } +} + +#[cfg(all(feature = "bits", not(target_pointer_width = "64")))] +type ReprBits = [u32; 8]; + +#[cfg(all(feature = "bits", target_pointer_width = "64"))] +type ReprBits = [u64; 4]; + +#[cfg(feature = "bits")] +impl PrimeFieldBits for Fq { + type ReprBits = ReprBits; + fn to_le_bits(&self) -> FieldBits { let bytes = self.to_bytes(); @@ -577,10 +595,6 @@ impl ff::PrimeField for Fq { FieldBits::new(limbs) } - fn is_odd(&self) -> bool { - self.to_bytes()[0] & 1 == 1 - } - fn char_le_bits() -> FieldBits { #[cfg(not(target_pointer_width = "64"))] { @@ -590,14 +604,6 @@ impl ff::PrimeField for Fq { #[cfg(target_pointer_width = "64")] FieldBits::new(MODULUS.0) } - - fn multiplicative_generator() -> Self { - GENERATOR - } - - fn root_of_unity() -> Self { - Self::ROOT_OF_UNITY - } } lazy_static! { diff --git a/src/lib.rs b/src/lib.rs index b48409d..6247a17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,7 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![allow(unknown_lints)] -#![allow( - clippy::op_ref, - clippy::same_item_push, - clippy::upper_case_acronyms, - clippy::unknown_clippy_lints -)] +#![allow(clippy::op_ref, clippy::same_item_push, clippy::upper_case_acronyms)] #![deny(broken_intra_doc_links)] #![deny(missing_debug_implementations)] #![deny(missing_docs)]