Compare commits
23 Commits
Author | SHA1 | Date |
---|---|---|
str4d | 38d38af3b7 | |
str4d | af5598dac6 | |
Deirdre Connolly | 109ec40d2a | |
decentralisedkev | 8e9c5fe6aa | |
ebfull | 8e9337ee1b | |
Dimitris Apostolou | 5f4374c836 | |
ebfull | ec85333e44 | |
Sean Bowe | 607958b8a2 | |
Sean Bowe | 2e98dabcb8 | |
Sean Bowe | b54b846b50 | |
Sean Bowe | e3766101f4 | |
ebfull | e83f7d2bd1 | |
str4d | cd510aa696 | |
Henry de Valence | b12ceb5623 | |
Henry de Valence | 62937011f7 | |
Jack Grigg | 00f028d5b3 | |
Jack Grigg | 71ab0bb707 | |
Jack Grigg | 5a3dea32c5 | |
Jack Grigg | 4c1da9d8bc | |
str4d | e2e0f5089f | |
Jack Grigg | d8f35139c5 | |
Jack Grigg | ab8293935a | |
Jack Grigg | 92b3e6a9b6 |
|
@ -0,0 +1,95 @@
|
|||
name: CI checks
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: 1.36.0
|
||||
override: true
|
||||
|
||||
# Ensure all code has been formatted with rustfmt
|
||||
- run: rustup component add rustfmt
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: -- --check --color always
|
||||
|
||||
test:
|
||||
name: Test on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: 1.36.0
|
||||
override: true
|
||||
- name: cargo fetch
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fetch
|
||||
- name: Build tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --verbose --release --tests
|
||||
- name: Run tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --verbose --release
|
||||
|
||||
no-std:
|
||||
name: Check no-std compatibility
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: 1.36.0
|
||||
override: true
|
||||
- run: rustup target add thumbv6m-none-eabi
|
||||
- name: cargo fetch
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fetch
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --verbose --target thumbv6m-none-eabi --no-default-features
|
||||
|
||||
doc-links:
|
||||
name: Nightly lint
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
override: true
|
||||
- name: cargo fetch
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fetch
|
||||
|
||||
# Ensure intra-documentation links all resolve correctly
|
||||
# Requires #![deny(intra_doc_link_resolution_failure)] in crate.
|
||||
- name: Check intra-doc links
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: doc
|
||||
args: --document-private-items
|
32
Cargo.toml
32
Cargo.toml
|
@ -10,26 +10,24 @@ 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.byteorder]
|
||||
version = "1"
|
||||
default-features = false
|
||||
|
||||
[dependencies.subtle]
|
||||
version = "2.1"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.rand_core]
|
||||
version = "0.4"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.rand_xorshift]
|
||||
[dependencies.bls12_381]
|
||||
version = "0.1"
|
||||
default-features = false
|
||||
|
||||
[dependencies.subtle]
|
||||
version = "^2.2.1"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.rand_core]
|
||||
version = "0.5"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.rand_xorshift]
|
||||
version = "0.2"
|
||||
default-features = false
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
nightly = ["subtle/nightly"]
|
||||
std = []
|
||||
default = []
|
||||
|
|
|
@ -8,13 +8,9 @@
|
|||
This is a pure Rust implementation of the Jubjub elliptic curve group and its associated fields.
|
||||
|
||||
* **This implementation has not been reviewed or audited. Use at your own risk.**
|
||||
* This implementation targets Rust `1.33` or later.
|
||||
* 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.
|
||||
* `nightly`: Enables `subtle/nightly` which prevents compiler optimizations that could jeopardize constant time operations.
|
||||
* This implementation does not require the Rust standard library.
|
||||
|
||||
## [Documentation](https://docs.rs/jubjub)
|
||||
|
||||
|
|
10
RELEASES.md
10
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.
|
||||
|
|
124
src/fr.rs
124
src/fr.rs
|
@ -1,12 +1,16 @@
|
|||
//! 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};
|
||||
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
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,7 +93,7 @@ impl<'a, 'b> Sub<&'b Fr> for &'a Fr {
|
|||
|
||||
#[inline]
|
||||
fn sub(self, rhs: &'b Fr) -> Fr {
|
||||
self.subtract(rhs)
|
||||
self.sub(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,14 +102,7 @@ impl<'a, 'b> Add<&'b Fr> for &'a Fr {
|
|||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,7 +139,7 @@ const R2: Fr = Fr([
|
|||
0x04f6547b8d127688,
|
||||
]);
|
||||
|
||||
/// R^2 = 2^768 mod r
|
||||
/// R^3 = 2^768 mod r
|
||||
const R3: Fr = Fr([
|
||||
0xe0d6c6563d830544,
|
||||
0x323e3883598d0f85,
|
||||
|
@ -170,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
|
||||
|
@ -192,10 +178,10 @@ impl Fr {
|
|||
pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<Fr> {
|
||||
let mut tmp = Fr([0, 0, 0, 0]);
|
||||
|
||||
tmp.0[0] = LittleEndian::read_u64(&bytes[0..8]);
|
||||
tmp.0[1] = LittleEndian::read_u64(&bytes[8..16]);
|
||||
tmp.0[2] = LittleEndian::read_u64(&bytes[16..24]);
|
||||
tmp.0[3] = LittleEndian::read_u64(&bytes[24..32]);
|
||||
tmp.0[0] = u64::from_le_bytes(bytes[0..8].try_into().unwrap());
|
||||
tmp.0[1] = u64::from_le_bytes(bytes[8..16].try_into().unwrap());
|
||||
tmp.0[2] = u64::from_le_bytes(bytes[16..24].try_into().unwrap());
|
||||
tmp.0[3] = u64::from_le_bytes(bytes[24..32].try_into().unwrap());
|
||||
|
||||
// Try to subtract the modulus
|
||||
let (_, borrow) = sbb(tmp.0[0], MODULUS.0[0], 0);
|
||||
|
@ -223,10 +209,10 @@ impl Fr {
|
|||
let tmp = Fr::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
|
||||
|
||||
let mut res = [0; 32];
|
||||
LittleEndian::write_u64(&mut res[0..8], tmp.0[0]);
|
||||
LittleEndian::write_u64(&mut res[8..16], tmp.0[1]);
|
||||
LittleEndian::write_u64(&mut res[16..24], tmp.0[2]);
|
||||
LittleEndian::write_u64(&mut res[24..32], tmp.0[3]);
|
||||
res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
|
||||
res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
|
||||
res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
|
||||
res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
|
||||
|
||||
res
|
||||
}
|
||||
|
@ -235,14 +221,14 @@ impl Fr {
|
|||
/// an element of Fr by reducing modulo r.
|
||||
pub fn from_bytes_wide(bytes: &[u8; 64]) -> Fr {
|
||||
Fr::from_u512([
|
||||
LittleEndian::read_u64(&bytes[0..8]),
|
||||
LittleEndian::read_u64(&bytes[8..16]),
|
||||
LittleEndian::read_u64(&bytes[16..24]),
|
||||
LittleEndian::read_u64(&bytes[24..32]),
|
||||
LittleEndian::read_u64(&bytes[32..40]),
|
||||
LittleEndian::read_u64(&bytes[40..48]),
|
||||
LittleEndian::read_u64(&bytes[48..56]),
|
||||
LittleEndian::read_u64(&bytes[56..64]),
|
||||
u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
|
||||
u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -255,7 +241,7 @@ impl Fr {
|
|||
//
|
||||
// and computing their sum in the field. It remains to see that arbitrary 256-bit
|
||||
// numbers can be placed into Montgomery form safely using the reduction. The
|
||||
// reduction works so long as the product is less than R=2^256 multipled by
|
||||
// reduction works so long as the product is less than R=2^256 multiplied by
|
||||
// the modulus. This holds because for any `c` smaller than the modulus, we have
|
||||
// that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the
|
||||
// reduction always works so long as `c` is in the field; in this case it is either the
|
||||
|
@ -267,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.
|
||||
|
@ -507,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);
|
||||
|
@ -537,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);
|
||||
|
@ -553,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] {
|
||||
|
@ -576,7 +595,6 @@ fn test_inv() {
|
|||
assert_eq!(inv, INV);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_debug() {
|
||||
assert_eq!(
|
||||
|
|
98
src/lib.rs
98
src/lib.rs
|
@ -14,24 +14,21 @@
|
|||
//! All operations are constant time unless explicitly noted; these functions will contain
|
||||
//! "vartime" in their name and they will be documented as variable time.
|
||||
//!
|
||||
//! This crate relies on the `subtle` crate for achieving constant time arithmetic. It is
|
||||
//! recommended to enable the `nightly` feature on this crate (which enables the `nightly`
|
||||
//! feature in the `subtle` crate) to defend against compiler optimizations that may
|
||||
//! compromise constant time arithmetic. However, this requires use of the nightly version
|
||||
//! of the Rust compiler.
|
||||
//!
|
||||
//! # Features
|
||||
//!
|
||||
//! * `nightly`: This enables `subtle/nightly` which attempts to prevent the compiler from
|
||||
//! performing optimizations that could compromise constant time arithmetic. It is
|
||||
//! recommended to enable this if you are able to use a nightly version of the Rust compiler.
|
||||
//! This crate uses the `subtle` crate to perform constant-time operations.
|
||||
|
||||
#![no_std]
|
||||
// Catch documentation errors caused by code changes.
|
||||
#![deny(intra_doc_link_resolution_failure)]
|
||||
#![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;
|
||||
|
||||
|
@ -41,11 +38,13 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
|||
#[macro_use]
|
||||
mod util;
|
||||
|
||||
mod fq;
|
||||
mod fr;
|
||||
pub use fq::Fq;
|
||||
pub use bls12_381::Scalar as Fq;
|
||||
pub use fr::Fr;
|
||||
|
||||
/// A better name than Fr.
|
||||
pub type Scalar = Fr;
|
||||
|
||||
const FR_MODULUS_BYTES: [u8; 32] = [
|
||||
183, 44, 247, 214, 94, 14, 151, 208, 130, 16, 200, 204, 147, 32, 104, 166, 0, 59, 52, 1, 1, 59,
|
||||
103, 6, 169, 175, 51, 101, 234, 180, 125, 14,
|
||||
|
@ -461,9 +460,9 @@ impl AffinePoint {
|
|||
/// for use in multiple additions.
|
||||
pub const fn to_niels(&self) -> AffineNielsPoint {
|
||||
AffineNielsPoint {
|
||||
v_plus_u: self.v.field_add(&self.u),
|
||||
v_minus_u: self.v.subtract(&self.u),
|
||||
t2d: self.u.multiply(&self.v).multiply(&EDWARDS_D2),
|
||||
v_plus_u: Fq::add(&self.v, &self.u),
|
||||
v_minus_u: Fq::sub(&self.v, &self.u),
|
||||
t2d: Fq::mul(&Fq::mul(&self.u, &self.v), &EDWARDS_D2),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -668,6 +667,7 @@ impl_binops_multiplicative!(ExtendedPoint, Fr);
|
|||
impl<'a, 'b> Add<&'b ExtendedNielsPoint> for &'a ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
#[allow(clippy::suspicious_arithmetic_impl)]
|
||||
fn add(self, other: &'b ExtendedNielsPoint) -> ExtendedPoint {
|
||||
// We perform addition in the extended coordinates. Here we use
|
||||
// a formula presented by Hisil, Wong, Carter and Dawson in
|
||||
|
@ -706,6 +706,7 @@ impl<'a, 'b> Add<&'b ExtendedNielsPoint> for &'a ExtendedPoint {
|
|||
impl<'a, 'b> Sub<&'b ExtendedNielsPoint> for &'a ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
#[allow(clippy::suspicious_arithmetic_impl)]
|
||||
fn sub(self, other: &'b ExtendedNielsPoint) -> ExtendedPoint {
|
||||
let a = (&self.v - &self.u) * &other.v_plus_u;
|
||||
let b = (&self.v + &self.u) * &other.v_minus_u;
|
||||
|
@ -727,6 +728,7 @@ impl_binops_additive!(ExtendedPoint, ExtendedNielsPoint);
|
|||
impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
#[allow(clippy::suspicious_arithmetic_impl)]
|
||||
fn add(self, other: &'b AffineNielsPoint) -> ExtendedPoint {
|
||||
// This is identical to the addition formula for `ExtendedNielsPoint`,
|
||||
// except we can assume that `other.z` is one, so that we perform
|
||||
|
@ -752,6 +754,7 @@ impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint {
|
|||
impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
#[allow(clippy::suspicious_arithmetic_impl)]
|
||||
fn sub(self, other: &'b AffineNielsPoint) -> ExtendedPoint {
|
||||
let a = (&self.v - &self.u) * &other.v_plus_u;
|
||||
let b = (&self.v + &self.u) * &other.v_minus_u;
|
||||
|
@ -951,17 +954,17 @@ fn test_extended_niels_point_identity() {
|
|||
#[test]
|
||||
fn test_assoc() {
|
||||
let p = ExtendedPoint::from(AffinePoint {
|
||||
u: Fq([
|
||||
0xc0115cb656ae4839,
|
||||
0x623dc3ff81d64c26,
|
||||
0x5868e739b5794f2c,
|
||||
0x23bd4fbb18d39c9c,
|
||||
u: Fq::from_raw([
|
||||
0x81c571e5d883cfb0,
|
||||
0x049f7a686f147029,
|
||||
0xf539c860bc3ea21f,
|
||||
0x4284715b7ccc8162,
|
||||
]),
|
||||
v: Fq([
|
||||
0x7588ee6d6dd40deb,
|
||||
0x9d6d7a23ebdb7c4c,
|
||||
0x46462e26d4edb8c7,
|
||||
0x10b4c1517ca82e9b,
|
||||
v: Fq::from_raw([
|
||||
0xbf096275684bb8ca,
|
||||
0xc7ba245890af256d,
|
||||
0x59119f3e86380eb0,
|
||||
0x3793de182f9fb1d2,
|
||||
]),
|
||||
})
|
||||
.mul_by_cofactor();
|
||||
|
@ -973,21 +976,20 @@ fn test_assoc() {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_batch_normalize() {
|
||||
let mut p = ExtendedPoint::from(AffinePoint {
|
||||
u: Fq([
|
||||
0xc0115cb656ae4839,
|
||||
0x623dc3ff81d64c26,
|
||||
0x5868e739b5794f2c,
|
||||
0x23bd4fbb18d39c9c,
|
||||
u: Fq::from_raw([
|
||||
0x81c571e5d883cfb0,
|
||||
0x049f7a686f147029,
|
||||
0xf539c860bc3ea21f,
|
||||
0x4284715b7ccc8162,
|
||||
]),
|
||||
v: Fq([
|
||||
0x7588ee6d6dd40deb,
|
||||
0x9d6d7a23ebdb7c4c,
|
||||
0x46462e26d4edb8c7,
|
||||
0x10b4c1517ca82e9b,
|
||||
v: Fq::from_raw([
|
||||
0xbf096275684bb8ca,
|
||||
0xc7ba245890af256d,
|
||||
0x59119f3e86380eb0,
|
||||
0x3793de182f9fb1d2,
|
||||
]),
|
||||
})
|
||||
.mul_by_cofactor();
|
||||
|
@ -1212,17 +1214,17 @@ fn test_mul_consistency() {
|
|||
]);
|
||||
assert_eq!(a * b, c);
|
||||
let p = ExtendedPoint::from(AffinePoint {
|
||||
u: Fq([
|
||||
0xc0115cb656ae4839,
|
||||
0x623dc3ff81d64c26,
|
||||
0x5868e739b5794f2c,
|
||||
0x23bd4fbb18d39c9c,
|
||||
u: Fq::from_raw([
|
||||
0x81c571e5d883cfb0,
|
||||
0x049f7a686f147029,
|
||||
0xf539c860bc3ea21f,
|
||||
0x4284715b7ccc8162,
|
||||
]),
|
||||
v: Fq([
|
||||
0x7588ee6d6dd40deb,
|
||||
0x9d6d7a23ebdb7c4c,
|
||||
0x46462e26d4edb8c7,
|
||||
0x10b4c1517ca82e9b,
|
||||
v: Fq::from_raw([
|
||||
0xbf096275684bb8ca,
|
||||
0xc7ba245890af256d,
|
||||
0x59119f3e86380eb0,
|
||||
0x3793de182f9fb1d2,
|
||||
]),
|
||||
})
|
||||
.mul_by_cofactor();
|
||||
|
|
117
src/util.rs
117
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);
|
||||
|
|
Loading…
Reference in New Issue