Make Fq/Fr similar to each other.

This commit is contained in:
Sean Bowe 2019-12-03 18:17:35 -07:00
parent e3766101f4
commit b54b846b50
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
2 changed files with 58 additions and 34 deletions

View File

@ -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::convert::TryInto;
use core::fmt; use core::fmt;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; 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}; 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 // The internal representation of this type is four 64-bit unsigned
// integers in little-endian order. Elements of Fr are always in // integers in little-endian order. Elements of Fr are always in
// Montgomery form; i.e., Fr(a) = aR mod r, with R = 2^256. // 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 { impl PartialEq for Fr {
#[inline]
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.ct_eq(other).unwrap_u8() == 1 self.ct_eq(other).unwrap_u8() == 1
} }
@ -70,19 +75,7 @@ impl<'a> Neg for &'a Fr {
#[inline] #[inline]
fn neg(self) -> Fr { fn neg(self) -> Fr {
// Subtract `self` from `MODULUS` to negate. Ignore the final self.neg()
// 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])
} }
} }
@ -100,24 +93,16 @@ impl<'a, 'b> Sub<&'b Fr> for &'a Fr {
#[inline] #[inline]
fn sub(self, rhs: &'b Fr) -> Fr { fn sub(self, rhs: &'b Fr) -> Fr {
self.subtract(rhs) self.sub(rhs)
} }
} }
impl<'a, 'b> Add<&'b Fr> for &'a Fr { impl<'a, 'b> Add<&'b Fr> for &'a Fr {
type Output = Fr; type Output = Fr;
#[allow(clippy::suspicious_arithmetic_impl)]
#[inline] #[inline]
fn add(self, rhs: &'b Fr) -> Fr { fn add(self, rhs: &'b Fr) -> Fr {
let (d0, carry) = adc(self.0[0], rhs.0[0], 0); self.add(rhs)
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
} }
} }
@ -128,7 +113,7 @@ impl<'a, 'b> Mul<&'b Fr> for &'a Fr {
fn mul(self, rhs: &'b Fr) -> Fr { fn mul(self, rhs: &'b Fr) -> Fr {
// Schoolbook multiplication // Schoolbook multiplication
self.multiply(rhs) self.mul(rhs)
} }
} }
@ -171,20 +156,20 @@ impl Default for Fr {
impl Fr { impl Fr {
/// Returns zero, the additive identity. /// Returns zero, the additive identity.
#[inline] #[inline]
pub fn zero() -> Fr { pub const fn zero() -> Fr {
Fr([0, 0, 0, 0]) Fr([0, 0, 0, 0])
} }
/// Returns one, the multiplicative identity. /// Returns one, the multiplicative identity.
#[inline] #[inline]
pub fn one() -> Fr { pub const fn one() -> Fr {
R R
} }
/// Doubles this field element. /// Doubles this field element.
#[inline] #[inline]
pub fn double(&self) -> Fr { pub const fn double(&self) -> Fr {
self + self self.add(self)
} }
/// Attempts to convert a little-endian byte representation of /// Attempts to convert a little-endian byte representation of
@ -268,9 +253,9 @@ impl Fr {
} }
/// Converts from an integer represented in little endian /// 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 { pub const fn from_raw(val: [u64; 4]) -> Self {
Fr(val).multiply(&R2) (&Fr(val)).mul(&R2)
} }
/// Squares this element. /// Squares this element.
@ -508,11 +493,12 @@ impl Fr {
let (r7, _) = adc(r7, carry2, carry); let (r7, _) = adc(r7, carry2, carry);
// Result may be within MODULUS of the correct value // 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] #[inline]
const fn multiply(&self, rhs: &Self) -> Self { pub const fn mul(&self, rhs: &Self) -> Self {
// Schoolbook multiplication // Schoolbook multiplication
let (r0, carry) = mac(0, self.0[0], rhs.0[0], 0); 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) Fr::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7)
} }
/// Subtracts another element from this element.
#[inline] #[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 (d0, borrow) = sbb(self.0[0], rhs.0[0], 0);
let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow);
let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow);
@ -554,6 +541,37 @@ impl Fr {
Fr([d0, d1, d2, d3]) 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] { impl<'a> From<&'a Fr> for [u8; 32] {

View File

@ -23,6 +23,12 @@
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(unsafe_code)] #![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(feature = "std")]
#[macro_use] #[macro_use]
extern crate std; extern crate std;