From e3766101f4ae62e56f4dc6fa1e460ca05bfff92c Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Dec 2019 18:01:28 -0700 Subject: [PATCH 1/4] Bring in the macros used for operator overloading in the bls12_381 crate. --- src/util.rs | 117 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 50 deletions(-) diff --git a/src/util.rs b/src/util.rs index 05e0e48..bd25dd0 100644 --- a/src/util.rs +++ b/src/util.rs @@ -19,92 +19,75 @@ pub const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) { (ret as u64, (ret >> 64) as u64) } -macro_rules! impl_binops_additive { - ($lhs:ident, $rhs:ident) => { - impl<'b> Sub<&'b $rhs> for $lhs { - type Output = $lhs; - - #[inline] - fn sub(self, rhs: &'b $rhs) -> $lhs { - &self - rhs - } - } - +macro_rules! impl_add_binop_specify_output { + ($lhs:ident, $rhs:ident, $output:ident) => { impl<'b> Add<&'b $rhs> for $lhs { - type Output = $lhs; + type Output = $output; #[inline] - fn add(self, rhs: &'b $rhs) -> $lhs { + fn add(self, rhs: &'b $rhs) -> $output { &self + rhs } } - impl<'a> Sub<$rhs> for &'a $lhs { - type Output = $lhs; - - #[inline] - fn sub(self, rhs: $rhs) -> $lhs { - self - &rhs - } - } - impl<'a> Add<$rhs> for &'a $lhs { - type Output = $lhs; + type Output = $output; #[inline] - fn add(self, rhs: $rhs) -> $lhs { + fn add(self, rhs: $rhs) -> $output { self + &rhs } } - impl Sub<$rhs> for $lhs { - type Output = $lhs; - - #[inline] - fn sub(self, rhs: $rhs) -> $lhs { - &self - &rhs - } - } - impl Add<$rhs> for $lhs { - type Output = $lhs; + type Output = $output; #[inline] - fn add(self, rhs: $rhs) -> $lhs { + fn add(self, rhs: $rhs) -> $output { &self + &rhs } } + }; +} + +macro_rules! impl_sub_binop_specify_output { + ($lhs:ident, $rhs:ident, $output:ident) => { + impl<'b> Sub<&'b $rhs> for $lhs { + type Output = $output; - impl SubAssign<$rhs> for $lhs { #[inline] - fn sub_assign(&mut self, rhs: $rhs) { - *self = &*self - &rhs; + fn sub(self, rhs: &'b $rhs) -> $output { + &self - rhs } } - impl AddAssign<$rhs> for $lhs { + impl<'a> Sub<$rhs> for &'a $lhs { + type Output = $output; + #[inline] - fn add_assign(&mut self, rhs: $rhs) { - *self = &*self + &rhs; + fn sub(self, rhs: $rhs) -> $output { + self - &rhs } } - impl<'b> SubAssign<&'b $rhs> for $lhs { - #[inline] - fn sub_assign(&mut self, rhs: &'b $rhs) { - *self = &*self - rhs; - } - } + impl Sub<$rhs> for $lhs { + type Output = $output; - impl<'b> AddAssign<&'b $rhs> for $lhs { #[inline] - fn add_assign(&mut self, rhs: &'b $rhs) { - *self = &*self + rhs; + fn sub(self, rhs: $rhs) -> $output { + &self - &rhs } } }; } +macro_rules! impl_binops_additive_specify_output { + ($lhs:ident, $rhs:ident, $output:ident) => { + impl_add_binop_specify_output!($lhs, $rhs, $output); + impl_sub_binop_specify_output!($lhs, $rhs, $output); + }; +} + macro_rules! impl_binops_multiplicative_mixed { ($lhs:ident, $rhs:ident, $output:ident) => { impl<'b> Mul<&'b $rhs> for $lhs { @@ -136,6 +119,40 @@ macro_rules! impl_binops_multiplicative_mixed { }; } +macro_rules! impl_binops_additive { + ($lhs:ident, $rhs:ident) => { + impl_binops_additive_specify_output!($lhs, $rhs, $lhs); + + impl SubAssign<$rhs> for $lhs { + #[inline] + fn sub_assign(&mut self, rhs: $rhs) { + *self = &*self - &rhs; + } + } + + impl AddAssign<$rhs> for $lhs { + #[inline] + fn add_assign(&mut self, rhs: $rhs) { + *self = &*self + &rhs; + } + } + + impl<'b> SubAssign<&'b $rhs> for $lhs { + #[inline] + fn sub_assign(&mut self, rhs: &'b $rhs) { + *self = &*self - rhs; + } + } + + impl<'b> AddAssign<&'b $rhs> for $lhs { + #[inline] + fn add_assign(&mut self, rhs: &'b $rhs) { + *self = &*self + rhs; + } + } + }; +} + macro_rules! impl_binops_multiplicative { ($lhs:ident, $rhs:ident) => { impl_binops_multiplicative_mixed!($lhs, $rhs, $lhs); From b54b846b504edf5315a06c73576f55af07587c8d Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Dec 2019 18:17:35 -0700 Subject: [PATCH 2/4] Make Fq/Fr similar to each other. --- src/fr.rs | 86 +++++++++++++++++++++++++++++++++--------------------- src/lib.rs | 6 ++++ 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/src/fr.rs b/src/fr.rs index 3986200..4e5aa51 100644 --- a/src/fr.rs +++ b/src/fr.rs @@ -1,3 +1,6 @@ +//! This module provides an implementation of the Jubjub scalar field $\mathbb{F}_r$ +//! where `r = 0x0e7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7` + use core::convert::TryInto; use core::fmt; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; @@ -6,7 +9,8 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use crate::util::{adc, mac, sbb}; -/// Represents an element of `GF(r)`. +/// Represents an element of the scalar field $\mathbb{F}_r$ of the Jubjub elliptic +/// curve construction. // The internal representation of this type is four 64-bit unsigned // integers in little-endian order. Elements of Fr are always in // Montgomery form; i.e., Fr(a) = aR mod r, with R = 2^256. @@ -40,6 +44,7 @@ impl ConstantTimeEq for Fr { } impl PartialEq for Fr { + #[inline] fn eq(&self, other: &Self) -> bool { self.ct_eq(other).unwrap_u8() == 1 } @@ -70,19 +75,7 @@ impl<'a> Neg for &'a Fr { #[inline] fn neg(self) -> Fr { - // Subtract `self` from `MODULUS` to negate. Ignore the final - // borrow because it cannot underflow; self is guaranteed to - // be in the field. - let (d0, borrow) = sbb(MODULUS.0[0], self.0[0], 0); - let (d1, borrow) = sbb(MODULUS.0[1], self.0[1], borrow); - let (d2, borrow) = sbb(MODULUS.0[2], self.0[2], borrow); - let (d3, _) = sbb(MODULUS.0[3], self.0[3], borrow); - - // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is - // zero if `self` was zero, and `u64::max_value()` if self was nonzero. - let mask = u64::from((self.0[0] | self.0[1] | self.0[2] | self.0[3]) == 0).wrapping_sub(1); - - Fr([d0 & mask, d1 & mask, d2 & mask, d3 & mask]) + self.neg() } } @@ -100,24 +93,16 @@ impl<'a, 'b> Sub<&'b Fr> for &'a Fr { #[inline] fn sub(self, rhs: &'b Fr) -> Fr { - self.subtract(rhs) + self.sub(rhs) } } impl<'a, 'b> Add<&'b Fr> for &'a Fr { type Output = Fr; - #[allow(clippy::suspicious_arithmetic_impl)] #[inline] fn add(self, rhs: &'b Fr) -> Fr { - let (d0, carry) = adc(self.0[0], rhs.0[0], 0); - let (d1, carry) = adc(self.0[1], rhs.0[1], carry); - let (d2, carry) = adc(self.0[2], rhs.0[2], carry); - let (d3, _) = adc(self.0[3], rhs.0[3], carry); - - // Attempt to subtract the modulus, to ensure the value - // is smaller than the modulus. - Fr([d0, d1, d2, d3]) - &MODULUS + self.add(rhs) } } @@ -128,7 +113,7 @@ impl<'a, 'b> Mul<&'b Fr> for &'a Fr { fn mul(self, rhs: &'b Fr) -> Fr { // Schoolbook multiplication - self.multiply(rhs) + self.mul(rhs) } } @@ -171,20 +156,20 @@ impl Default for Fr { impl Fr { /// Returns zero, the additive identity. #[inline] - pub fn zero() -> Fr { + pub const fn zero() -> Fr { Fr([0, 0, 0, 0]) } /// Returns one, the multiplicative identity. #[inline] - pub fn one() -> Fr { + pub const fn one() -> Fr { R } /// Doubles this field element. #[inline] - pub fn double(&self) -> Fr { - self + self + pub const fn double(&self) -> Fr { + self.add(self) } /// Attempts to convert a little-endian byte representation of @@ -268,9 +253,9 @@ impl Fr { } /// Converts from an integer represented in little endian - /// into its (congruent) representation in Fr. + /// into its (congruent) `Fr` representation. pub const fn from_raw(val: [u64; 4]) -> Self { - Fr(val).multiply(&R2) + (&Fr(val)).mul(&R2) } /// Squares this element. @@ -508,11 +493,12 @@ impl Fr { let (r7, _) = adc(r7, carry2, carry); // Result may be within MODULUS of the correct value - Fr([r4, r5, r6, r7]).subtract(&MODULUS) + (&Fr([r4, r5, r6, r7])).sub(&MODULUS) } + /// Multiplies this element by another element #[inline] - const fn multiply(&self, rhs: &Self) -> Self { + pub const fn mul(&self, rhs: &Self) -> Self { // Schoolbook multiplication let (r0, carry) = mac(0, self.0[0], rhs.0[0], 0); @@ -538,8 +524,9 @@ impl Fr { Fr::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) } + /// Subtracts another element from this element. #[inline] - const fn subtract(&self, rhs: &Self) -> Self { + pub const fn sub(&self, rhs: &Self) -> Self { let (d0, borrow) = sbb(self.0[0], rhs.0[0], 0); let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); @@ -554,6 +541,37 @@ impl Fr { Fr([d0, d1, d2, d3]) } + + /// Adds this element to another element. + #[inline] + pub const fn add(&self, rhs: &Self) -> Self { + let (d0, carry) = adc(self.0[0], rhs.0[0], 0); + let (d1, carry) = adc(self.0[1], rhs.0[1], carry); + let (d2, carry) = adc(self.0[2], rhs.0[2], carry); + let (d3, _) = adc(self.0[3], rhs.0[3], carry); + + // Attempt to subtract the modulus, to ensure the value + // is smaller than the modulus. + (&Fr([d0, d1, d2, d3])).sub(&MODULUS) + } + + /// Negates this element. + #[inline] + pub const fn neg(&self) -> Self { + // Subtract `self` from `MODULUS` to negate. Ignore the final + // borrow because it cannot underflow; self is guaranteed to + // be in the field. + let (d0, borrow) = sbb(MODULUS.0[0], self.0[0], 0); + let (d1, borrow) = sbb(MODULUS.0[1], self.0[1], borrow); + let (d2, borrow) = sbb(MODULUS.0[2], self.0[2], borrow); + let (d3, _) = sbb(MODULUS.0[3], self.0[3], borrow); + + // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is + // zero if `self` was zero, and `u64::max_value()` if self was nonzero. + let mask = (((self.0[0] | self.0[1] | self.0[2] | self.0[3]) == 0) as u64).wrapping_sub(1); + + Fr([d0 & mask, d1 & mask, d2 & mask, d3 & mask]) + } } impl<'a> From<&'a Fr> for [u8; 32] { diff --git a/src/lib.rs b/src/lib.rs index d8cf0bc..e226b12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,12 @@ #![deny(missing_docs)] #![deny(unsafe_code)] +// This lint is described at +// https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl +// In our library, some of the arithmetic will necessarily involve various binary +// operators, and so this lint is triggered unnecessarily. +#![allow(clippy::suspicious_arithmetic_impl)] + #[cfg(feature = "std")] #[macro_use] extern crate std; From 2e98dabcb83d3fc06acb9e82a8500e5d5996b080 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Dec 2019 18:31:04 -0700 Subject: [PATCH 3/4] Remove the std feature. --- Cargo.toml | 3 +-- README.md | 5 +---- src/fr.rs | 1 - src/lib.rs | 4 +--- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aa94db0..19ba0f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,5 +30,4 @@ version = "0.2" default-features = false [features] -default = ["std"] -std = [] +default = [] diff --git a/README.md b/README.md index 0697188..da5bd53 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,7 @@ This is a pure Rust implementation of the Jubjub elliptic curve group and its as * **This implementation has not been reviewed or audited. Use at your own risk.** * This implementation targets Rust `1.36` or later. * All operations are constant time unless explicitly noted. - -## Features - -* `std` (on by default): Enables APIs that leverage the Rust standard library. +* This implementation does not require the Rust standard library. ## [Documentation](https://docs.rs/jubjub) diff --git a/src/fr.rs b/src/fr.rs index 4e5aa51..4495e3b 100644 --- a/src/fr.rs +++ b/src/fr.rs @@ -595,7 +595,6 @@ fn test_inv() { assert_eq!(inv, INV); } -#[cfg(feature = "std")] #[test] fn test_debug() { assert_eq!( diff --git a/src/lib.rs b/src/lib.rs index e226b12..8419487 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,14 +22,13 @@ #![deny(missing_debug_implementations)] #![deny(missing_docs)] #![deny(unsafe_code)] - // This lint is described at // https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl // In our library, some of the arithmetic will necessarily involve various binary // operators, and so this lint is triggered unnecessarily. #![allow(clippy::suspicious_arithmetic_impl)] -#[cfg(feature = "std")] +#[cfg(test)] #[macro_use] extern crate std; @@ -974,7 +973,6 @@ fn test_assoc() { ); } -#[cfg(feature = "std")] #[test] fn test_batch_normalize() { let mut p = ExtendedPoint::from(AffinePoint { From 607958b8a24f2da03cd5e1c3ef38697a7d2d82ac Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Dec 2019 18:32:47 -0700 Subject: [PATCH 4/4] Bump version to 0.3 --- Cargo.toml | 2 +- RELEASES.md | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 19ba0f2..1bac857 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ homepage = "https://github.com/zkcrypto/jubjub" license = "MIT/Apache-2.0" name = "jubjub" repository = "https://github.com/zkcrypto/jubjub" -version = "0.2.0" +version = "0.3.0" edition = "2018" [dependencies.bls12_381] diff --git a/RELEASES.md b/RELEASES.md index 5af6b07..45db61c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,13 @@ +# 0.3.0 + +This release now depends on the `bls12_381` crate, which exposes the `Fq` field type that we re-export. + +* The `Fq` and `Fr` field types now have better constant function support for various operations and constructors. +* We no longer depend on the `byteorder` crate. +* We've bumped our `rand_core` dev-dependency up to 0.5. +* We've removed the `std` and `nightly` features. +* We've bumped our dependency of `subtle` up to `^2.2.1`. + # 0.2.0 This release switches to `subtle 2.1` to bring in the `CtOption` type, and also makes a few useful API changes.