mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Add a fiat_u64_backend option to curve25519-dalek
This uses https://github.com/calibra/rust-curve25519-fiat/ to implement a new 64bit serial backend for dalek. Co-authored-by: Zoe Parakevopoulou <zoopar@fb.com>
This commit is contained in:
parent
73100b74ff
commit
d684e13f09
10 changed files with 314 additions and 11 deletions
|
|
@ -49,6 +49,7 @@ serde = { version = "1.0", default-features = false, optional = true, features =
|
|||
# https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161
|
||||
packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true }
|
||||
zeroize = { version = "1", default-features = false }
|
||||
curve25519-fiat = { git="https://github.com/calibra/rust-curve25519-fiat.git", version = "0.1.0", optional = true}
|
||||
|
||||
[features]
|
||||
nightly = ["subtle/nightly"]
|
||||
|
|
@ -60,6 +61,8 @@ alloc = ["zeroize/alloc"]
|
|||
u32_backend = []
|
||||
# The u64 backend uses u64s with u128 products.
|
||||
u64_backend = []
|
||||
# The fiat-u64 backend uses u64s with u128 products.
|
||||
fiat_u64_backend = ["curve25519-fiat"]
|
||||
# The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA.
|
||||
simd_backend = ["nightly", "u64_backend", "packed_simd"]
|
||||
# DEPRECATED: this is now an alias for `simd_backend` and may be removed
|
||||
|
|
|
|||
|
|
@ -36,11 +36,12 @@
|
|||
#[cfg(not(any(
|
||||
feature = "u32_backend",
|
||||
feature = "u64_backend",
|
||||
feature = "fiat_u64_backend",
|
||||
feature = "simd_backend",
|
||||
)))]
|
||||
compile_error!(
|
||||
"no curve25519-dalek backend cargo feature enabled! \
|
||||
please enable one of: u32_backend, u64_backend, simd_backend"
|
||||
please enable one of: u32_backend, u64_backend, fiat_u64_backend, simd_backend"
|
||||
);
|
||||
|
||||
pub mod serial;
|
||||
|
|
|
|||
243
src/backend/serial/fiat/field.rs
Normal file
243
src/backend/serial/fiat/field.rs
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
// -*- mode: rust; coding: utf-8; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit
|
||||
//! limbs with \\(128\\)-bit products.
|
||||
|
||||
use core::fmt::Debug;
|
||||
use core::ops::Neg;
|
||||
use core::ops::{Add, AddAssign};
|
||||
use core::ops::{Mul, MulAssign};
|
||||
use core::ops::{Sub, SubAssign};
|
||||
|
||||
use subtle::Choice;
|
||||
use subtle::ConditionallySelectable;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use curve25519_fiat::curve25519_64::*;
|
||||
|
||||
/// A `FieldElement51` represents an element of the field
|
||||
/// \\( \mathbb Z / (2\^{255} - 19)\\).
|
||||
///
|
||||
/// In the 64-bit implementation, a `FieldElement` is represented in
|
||||
/// radix \\(2\^{51}\\) as five `u64`s; the coefficients are allowed to
|
||||
/// grow up to \\(2\^{54}\\) between reductions modulo \\(p\\).
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The `curve25519_dalek::field` module provides a type alias
|
||||
/// `curve25519_dalek::field::FieldElement` to either `FieldElement51`
|
||||
/// or `FieldElement2625`.
|
||||
///
|
||||
/// The backend-specific type `FieldElement51` should not be used
|
||||
/// outside of the `curve25519_dalek::field` module.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct FieldElement51(pub(crate) [u64; 5]);
|
||||
|
||||
impl Debug for FieldElement51 {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
write!(f, "FieldElement51({:?})", &self.0[..])
|
||||
}
|
||||
}
|
||||
|
||||
impl Zeroize for FieldElement51 {
|
||||
fn zeroize(&mut self) {
|
||||
self.0.zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 {
|
||||
fn add_assign(&mut self, _rhs: &'b FieldElement51) {
|
||||
let input = self.0;
|
||||
fiat_25519_add(&mut self.0, &input, &_rhs.0);
|
||||
let input = self.0;
|
||||
fiat_25519_carry(&mut self.0, &input);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Add<&'b FieldElement51> for &'a FieldElement51 {
|
||||
type Output = FieldElement51;
|
||||
fn add(self, _rhs: &'b FieldElement51) -> FieldElement51 {
|
||||
let mut output = *self;
|
||||
fiat_25519_add(&mut output.0, &self.0, &_rhs.0);
|
||||
let input = output.0;
|
||||
fiat_25519_carry(&mut output.0, &input);
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> SubAssign<&'b FieldElement51> for FieldElement51 {
|
||||
fn sub_assign(&mut self, _rhs: &'b FieldElement51) {
|
||||
let input = self.0;
|
||||
fiat_25519_sub(&mut self.0, &input, &_rhs.0);
|
||||
let input = self.0;
|
||||
fiat_25519_carry(&mut self.0, &input);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Sub<&'b FieldElement51> for &'a FieldElement51 {
|
||||
type Output = FieldElement51;
|
||||
fn sub(self, _rhs: &'b FieldElement51) -> FieldElement51 {
|
||||
let mut output = *self;
|
||||
fiat_25519_sub(&mut output.0, &self.0, &_rhs.0);
|
||||
let input = output.0;
|
||||
fiat_25519_carry(&mut output.0, &input);
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 {
|
||||
fn mul_assign(&mut self, _rhs: &'b FieldElement51) {
|
||||
let input = self.0;
|
||||
fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 {
|
||||
type Output = FieldElement51;
|
||||
fn mul(self, _rhs: &'b FieldElement51) -> FieldElement51 {
|
||||
let mut output = *self;
|
||||
fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0);
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a FieldElement51 {
|
||||
type Output = FieldElement51;
|
||||
fn neg(self) -> FieldElement51 {
|
||||
let mut output = *self;
|
||||
fiat_25519_opp(&mut output.0, &self.0);
|
||||
let input = output.0;
|
||||
fiat_25519_carry(&mut output.0, &input);
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl ConditionallySelectable for FieldElement51 {
|
||||
fn conditional_select(
|
||||
a: &FieldElement51,
|
||||
b: &FieldElement51,
|
||||
choice: Choice,
|
||||
) -> FieldElement51 {
|
||||
let mut output = [0u64; 5];
|
||||
fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0);
|
||||
FieldElement51(output)
|
||||
}
|
||||
|
||||
fn conditional_swap(a: &mut FieldElement51, b: &mut FieldElement51, choice: Choice) {
|
||||
u64::conditional_swap(&mut a.0[0], &mut b.0[0], choice);
|
||||
u64::conditional_swap(&mut a.0[1], &mut b.0[1], choice);
|
||||
u64::conditional_swap(&mut a.0[2], &mut b.0[2], choice);
|
||||
u64::conditional_swap(&mut a.0[3], &mut b.0[3], choice);
|
||||
u64::conditional_swap(&mut a.0[4], &mut b.0[4], choice);
|
||||
}
|
||||
|
||||
fn conditional_assign(&mut self, _rhs: &FieldElement51, choice: Choice) {
|
||||
self.0[0].conditional_assign(&_rhs.0[0], choice);
|
||||
self.0[1].conditional_assign(&_rhs.0[1], choice);
|
||||
self.0[2].conditional_assign(&_rhs.0[2], choice);
|
||||
self.0[3].conditional_assign(&_rhs.0[3], choice);
|
||||
self.0[4].conditional_assign(&_rhs.0[4], choice);
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldElement51 {
|
||||
/// Construct zero.
|
||||
pub fn zero() -> FieldElement51 {
|
||||
FieldElement51([0, 0, 0, 0, 0])
|
||||
}
|
||||
|
||||
/// Construct one.
|
||||
pub fn one() -> FieldElement51 {
|
||||
FieldElement51([1, 0, 0, 0, 0])
|
||||
}
|
||||
|
||||
/// Construct -1.
|
||||
pub fn minus_one() -> FieldElement51 {
|
||||
FieldElement51([
|
||||
2251799813685228,
|
||||
2251799813685247,
|
||||
2251799813685247,
|
||||
2251799813685247,
|
||||
2251799813685247,
|
||||
])
|
||||
}
|
||||
|
||||
/// Given 64-bit input limbs, reduce to enforce the bound 2^(51 + epsilon).
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)] // Need this to not complain about reduce not being used
|
||||
fn reduce(mut limbs: [u64; 5]) -> FieldElement51 {
|
||||
let input = limbs;
|
||||
fiat_25519_carry(&mut limbs, &input);
|
||||
FieldElement51(limbs)
|
||||
}
|
||||
|
||||
/// Load a `FieldElement51` from the low 255 bits of a 256-bit
|
||||
/// input.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This function does not check that the input used the canonical
|
||||
/// representative. It masks the high bit, but it will happily
|
||||
/// decode 2^255 - 18 to 1. Applications that require a canonical
|
||||
/// encoding of every field element should decode, re-encode to
|
||||
/// the canonical encoding, and check that the input was
|
||||
/// canonical.
|
||||
///
|
||||
pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement51 {
|
||||
let mut temp = [0u8; 32];
|
||||
temp.copy_from_slice(bytes);
|
||||
temp[31] &= 127u8;
|
||||
let mut output = [0u64; 5];
|
||||
fiat_25519_from_bytes(&mut output, &temp);
|
||||
FieldElement51(output)
|
||||
}
|
||||
|
||||
/// Serialize this `FieldElement51` to a 32-byte array. The
|
||||
/// encoding is canonical.
|
||||
pub fn to_bytes(&self) -> [u8; 32] {
|
||||
let mut bytes = [0u8; 32];
|
||||
fiat_25519_to_bytes(&mut bytes, &self.0);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// Given `k > 0`, return `self^(2^k)`.
|
||||
pub fn pow2k(&self, mut k: u32) -> FieldElement51 {
|
||||
let mut output = *self;
|
||||
loop {
|
||||
let input = output.0;
|
||||
fiat_25519_carry_square(&mut output.0, &input);
|
||||
k -= 1;
|
||||
if k == 0 {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the square of this field element.
|
||||
pub fn square(&self) -> FieldElement51 {
|
||||
let mut output = *self;
|
||||
fiat_25519_carry_square(&mut output.0, &self.0);
|
||||
output
|
||||
}
|
||||
|
||||
/// Returns 2 times the square of this field element.
|
||||
pub fn square2(&self) -> FieldElement51 {
|
||||
let mut output = *self;
|
||||
let mut temp = *self;
|
||||
// Void vs return type, measure cost of copying self
|
||||
fiat_25519_carry_square(&mut temp.0, &self.0);
|
||||
fiat_25519_add(&mut output.0, &temp.0, &temp.0);
|
||||
let input = output.0;
|
||||
fiat_25519_carry(&mut output.0, &input);
|
||||
output
|
||||
}
|
||||
}
|
||||
28
src/backend/serial/fiat/mod.rs
Normal file
28
src/backend/serial/fiat/mod.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// This file is part of curve25519-dalek.
|
||||
// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence
|
||||
// See LICENSE for licensing information.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier.
|
||||
//!
|
||||
//! On x86_64, the idiom `(x as u128) * (y as u128)` lowers to `MUL`
|
||||
//! instructions taking 64-bit inputs and producing 128-bit outputs. On
|
||||
//! other platforms, this implementation is not recommended.
|
||||
//!
|
||||
//! On Haswell and newer, the BMI2 extension provides `MULX`, and on
|
||||
//! Broadwell and newer, the ADX extension provides `ADCX` and `ADOX`
|
||||
//! (allowing the CPU to compute two carry chains in parallel). These
|
||||
//! will be used if available.
|
||||
|
||||
#[path = "../u64/scalar.rs"]
|
||||
pub mod scalar;
|
||||
|
||||
pub mod field;
|
||||
|
||||
#[path = "../u64/constants.rs"]
|
||||
pub mod constants;
|
||||
|
|
@ -22,10 +22,14 @@
|
|||
//! Note: at this time the `u32` and `u64` backends cannot be built
|
||||
//! together.
|
||||
|
||||
#[cfg(not(any(feature = "u32_backend", feature = "u64_backend")))]
|
||||
#[cfg(not(any(
|
||||
feature = "u32_backend",
|
||||
feature = "u64_backend",
|
||||
feature = "fiat_u64_backend"
|
||||
)))]
|
||||
compile_error!(
|
||||
"no curve25519-dalek backend cargo feature enabled! \
|
||||
please enable one of: u32_backend, u64_backend"
|
||||
please enable one of: u32_backend, u64_backend, fiat_u64_backend"
|
||||
);
|
||||
|
||||
#[cfg(feature = "u32_backend")]
|
||||
|
|
@ -34,6 +38,9 @@ pub mod u32;
|
|||
#[cfg(feature = "u64_backend")]
|
||||
pub mod u64;
|
||||
|
||||
#[cfg(feature = "fiat_u64_backend")]
|
||||
pub mod fiat;
|
||||
|
||||
pub mod curve_models;
|
||||
|
||||
#[cfg(not(all(
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
//! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants.
|
||||
|
||||
use super::field::FieldElement51;
|
||||
use super::scalar::Scalar52;
|
||||
use backend::serial::curve_models::AffineNielsPoint;
|
||||
use backend::serial::u64::field::FieldElement51;
|
||||
use backend::serial::u64::scalar::Scalar52;
|
||||
use edwards::{EdwardsBasepointTable, EdwardsPoint};
|
||||
use window::{LookupTable, NafLookupTable8};
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([
|
|||
2251799813685247,
|
||||
2251799813685247,
|
||||
2251799813685247,
|
||||
2251799813685247
|
||||
2251799813685247,
|
||||
]);
|
||||
|
||||
/// Edwards `d` value, equal to `-121665/121666 mod p`.
|
||||
|
|
@ -49,7 +49,7 @@ pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement51 = FieldElement51([
|
|||
1998550399581263,
|
||||
496427632559748,
|
||||
118527312129759,
|
||||
45110755273534
|
||||
45110755273534,
|
||||
]);
|
||||
|
||||
/// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2`
|
||||
|
|
@ -58,7 +58,7 @@ pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement51 = FieldElement51([
|
|||
1572317787530805,
|
||||
683053064812840,
|
||||
317374165784489,
|
||||
1572899562415810
|
||||
1572899562415810,
|
||||
]);
|
||||
|
||||
/// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters.
|
||||
|
|
|
|||
|
|
@ -33,10 +33,12 @@ use ristretto::CompressedRistretto;
|
|||
use montgomery::MontgomeryPoint;
|
||||
use scalar::Scalar;
|
||||
|
||||
#[cfg(feature = "u64_backend")]
|
||||
pub use backend::serial::u64::constants::*;
|
||||
#[cfg(feature = "fiat_u64_backend")]
|
||||
pub use backend::serial::fiat::constants::*;
|
||||
#[cfg(feature = "u32_backend")]
|
||||
pub use backend::serial::u32::constants::*;
|
||||
#[cfg(feature = "u64_backend")]
|
||||
pub use backend::serial::u64::constants::*;
|
||||
|
||||
/// The Ed25519 basepoint, in `CompressedEdwardsY` format.
|
||||
///
|
||||
|
|
|
|||
10
src/field.rs
10
src/field.rs
|
|
@ -32,6 +32,16 @@ use subtle::ConstantTimeEq;
|
|||
use constants;
|
||||
use backend;
|
||||
|
||||
#[cfg(feature = "fiat_u64_backend")]
|
||||
pub use backend::serial::fiat::field::*;
|
||||
/// A `FieldElement` represents an element of the field
|
||||
/// \\( \mathbb Z / (2\^{255} - 19)\\).
|
||||
///
|
||||
/// The `FieldElement` type is an alias for one of the platform-specific
|
||||
/// implementations.
|
||||
#[cfg(feature = "fiat_u64_backend")]
|
||||
pub type FieldElement = backend::serial::fiat::field::FieldElement51;
|
||||
|
||||
#[cfg(feature = "u64_backend")]
|
||||
pub use backend::serial::u64::field::*;
|
||||
/// A `FieldElement` represents an element of the field
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
// This means that missing docs will still fail CI, but means we can use
|
||||
// README.md as the crate documentation.
|
||||
#![cfg_attr(feature = "nightly", deny(missing_docs))]
|
||||
|
||||
#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
|
||||
#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")]
|
||||
#![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.0.2")]
|
||||
|
|
@ -46,6 +45,9 @@ pub extern crate digest;
|
|||
extern crate rand_core;
|
||||
extern crate zeroize;
|
||||
|
||||
#[cfg(feature = "fiat_u64_backend")]
|
||||
extern crate curve25519_fiat;
|
||||
|
||||
// Used for traits related to constant-time code.
|
||||
extern crate subtle;
|
||||
|
||||
|
|
|
|||
|
|
@ -165,6 +165,13 @@ use zeroize::Zeroize;
|
|||
use backend;
|
||||
use constants;
|
||||
|
||||
/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed.
|
||||
///
|
||||
/// This is a type alias for one of the scalar types in the `backend`
|
||||
/// module.
|
||||
#[cfg(feature = "fiat_u64_backend")]
|
||||
type UnpackedScalar = backend::serial::fiat::scalar::Scalar52;
|
||||
|
||||
/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed.
|
||||
///
|
||||
/// This is a type alias for one of the scalar types in the `backend`
|
||||
|
|
|
|||
Loading…
Reference in a new issue