From d684e13f092a337779679d90560770857939d94e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Tue, 27 Aug 2019 15:52:55 -0700 Subject: [PATCH 1/8] 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 --- Cargo.toml | 3 + src/backend/mod.rs | 3 +- src/backend/serial/fiat/field.rs | 243 ++++++++++++++++++++++++++++ src/backend/serial/fiat/mod.rs | 28 ++++ src/backend/serial/mod.rs | 11 +- src/backend/serial/u64/constants.rs | 10 +- src/constants.rs | 6 +- src/field.rs | 10 ++ src/lib.rs | 4 +- src/scalar.rs | 7 + 10 files changed, 314 insertions(+), 11 deletions(-) create mode 100644 src/backend/serial/fiat/field.rs create mode 100644 src/backend/serial/fiat/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 3426071bb..0ceb29db5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 diff --git a/src/backend/mod.rs b/src/backend/mod.rs index f761eaad9..9c0781617 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -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; diff --git a/src/backend/serial/fiat/field.rs b/src/backend/serial/fiat/field.rs new file mode 100644 index 000000000..a2f1a9086 --- /dev/null +++ b/src/backend/serial/fiat/field.rs @@ -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 +// - Henry de Valence + +//! 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 + } +} diff --git a/src/backend/serial/fiat/mod.rs b/src/backend/serial/fiat/mod.rs new file mode 100644 index 000000000..8c8306249 --- /dev/null +++ b/src/backend/serial/fiat/mod.rs @@ -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 +// - Henry de Valence + +//! 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; diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index fc6b32053..a4a03dd0c 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -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( diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index fc8c6daa8..0b2d50ac9 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -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. diff --git a/src/constants.rs b/src/constants.rs index e30d35ea4..5887c7ab8 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -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. /// diff --git a/src/field.rs b/src/field.rs index 54d048d5f..58127ec5b 100644 --- a/src/field.rs +++ b/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 diff --git a/src/lib.rs b/src/lib.rs index 912b62a8a..3f46bd1b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/scalar.rs b/src/scalar.rs index 6ead65adf..b7376ad00 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -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` From 4ce680d3aaec5d48e62213dd1942dfd3464aaccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 17 Feb 2020 09:42:41 -0500 Subject: [PATCH 2/8] Update the fiat backend to use the fiat-crypto package https://crates.io/crates/fiat-crypto --- Cargo.toml | 4 ++-- src/backend/serial/fiat/field.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0ceb29db5..124069c0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +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} +fiat-crypto = { version = "0.1.0", optional = true} [features] nightly = ["subtle/nightly"] @@ -62,7 +62,7 @@ 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"] +fiat_u64_backend = ["fiat-crypto"] # 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 diff --git a/src/backend/serial/fiat/field.rs b/src/backend/serial/fiat/field.rs index a2f1a9086..25e36497f 100644 --- a/src/backend/serial/fiat/field.rs +++ b/src/backend/serial/fiat/field.rs @@ -22,7 +22,7 @@ use subtle::ConditionallySelectable; use zeroize::Zeroize; -use curve25519_fiat::curve25519_64::*; +use fiat_crypto::curve25519_64::*; /// A `FieldElement51` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). diff --git a/src/lib.rs b/src/lib.rs index 3f46bd1b7..982d32347 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ extern crate rand_core; extern crate zeroize; #[cfg(feature = "fiat_u64_backend")] -extern crate curve25519_fiat; +extern crate fiat_crypto; // Used for traits related to constant-time code. extern crate subtle; From a9e50eab363897a3599d774e6426c9590ea465d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 11 May 2020 15:04:18 -0400 Subject: [PATCH 3/8] implement conditional assign with fiat__25519_cmovznz_u64 --- src/backend/serial/fiat/field.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/backend/serial/fiat/field.rs b/src/backend/serial/fiat/field.rs index 25e36497f..dbb9fb09b 100644 --- a/src/backend/serial/fiat/field.rs +++ b/src/backend/serial/fiat/field.rs @@ -141,11 +141,14 @@ impl ConditionallySelectable for FieldElement51 { } 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); + let mut output = [0u64; 5]; + let choicebit = choice.unwrap_u8() as fiat_25519_u1; + fiat_25519_cmovznz_u64(&mut output[0], choicebit, self.0[0], _rhs.0[0]); + fiat_25519_cmovznz_u64(&mut output[1], choicebit, self.0[1], _rhs.0[1]); + fiat_25519_cmovznz_u64(&mut output[2], choicebit, self.0[2], _rhs.0[2]); + fiat_25519_cmovznz_u64(&mut output[3], choicebit, self.0[3], _rhs.0[3]); + fiat_25519_cmovznz_u64(&mut output[4], choicebit, self.0[4], _rhs.0[4]); + *self = FieldElement51(output); } } From 3422872346ae88d812006dc4841e50279ba28832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 11 May 2020 14:41:02 -0400 Subject: [PATCH 4/8] bump fiat-crypto version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 124069c0b..be34e80f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +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 } -fiat-crypto = { version = "0.1.0", optional = true} +fiat-crypto = { version = "0.1.1", optional = true} [features] nightly = ["subtle/nightly"] From 756a921beefd8df3e7ec511bf36d2a2882568dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Fri, 29 May 2020 20:36:50 -0400 Subject: [PATCH 5/8] bump fiat-crypto version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index be34e80f3..239065cc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +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 } -fiat-crypto = { version = "0.1.1", optional = true} +fiat-crypto = { version = "0.1.5", optional = true} [features] nightly = ["subtle/nightly"] From ce2e3f6e69deddd400723866eaf8eb52e2f240b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 11 Jan 2021 09:32:54 -0800 Subject: [PATCH 6/8] bump fiat-crypto version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 239065cc9..44685e17d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +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 } -fiat-crypto = { version = "0.1.5", optional = true} +fiat-crypto = { version = "0.1.6", optional = true} [features] nightly = ["subtle/nightly"] From abd192245681d768c63f320aae9e7cbc0fe31495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 11 Jan 2021 13:20:55 -0800 Subject: [PATCH 7/8] Add a fiat_u32 backend based on fiat-crypto as well. Renames fiat backend directory to fiat_u64 and does the additional plumbing required to make fiat_{u32, u64}_backend equal alternatives. Adds a few comments. --- Cargo.toml | 4 +- src/backend/mod.rs | 3 +- src/backend/serial/fiat_u32/field.rs | 260 ++++++++++++++++++ src/backend/serial/fiat_u32/mod.rs | 26 ++ .../serial/{fiat => fiat_u64}/field.rs | 3 + src/backend/serial/{fiat => fiat_u64}/mod.rs | 0 src/backend/serial/mod.rs | 8 +- src/backend/serial/u32/constants.rs | 4 +- src/backend/serial/u64/constants.rs | 8 +- src/constants.rs | 8 +- src/field.rs | 9 +- src/lib.rs | 2 +- src/scalar.rs | 4 +- 13 files changed, 322 insertions(+), 17 deletions(-) create mode 100644 src/backend/serial/fiat_u32/field.rs create mode 100644 src/backend/serial/fiat_u32/mod.rs rename src/backend/serial/{fiat => fiat_u64}/field.rs (98%) rename src/backend/serial/{fiat => fiat_u64}/mod.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 44685e17d..d33703fe7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,8 +61,10 @@ 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 (with formally-verified field arith) uses u64s with u128 products. fiat_u64_backend = ["fiat-crypto"] +# fiat-u32 backend (with formally-verified field arith) uses u64s with u128 products. +fiat_u32_backend = ["fiat-crypto"] # 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 diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 9c0781617..2eef77478 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -36,12 +36,13 @@ #[cfg(not(any( feature = "u32_backend", feature = "u64_backend", + feature = "fiat_u32_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, fiat_u64_backend, simd_backend" + please enable one of: u32_backend, u64_backend, fiat_u32_backend, fiat_u64_backend, simd_backend" ); pub mod serial; diff --git a/src/backend/serial/fiat_u32/field.rs b/src/backend/serial/fiat_u32/field.rs new file mode 100644 index 000000000..2864c955e --- /dev/null +++ b/src/backend/serial/fiat_u32/field.rs @@ -0,0 +1,260 @@ +// -*- 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 +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit +//! limbs with \\(64\\)-bit products. +//! +//! This code was originally derived from Adam Langley's Golang ed25519 +//! implementation, and was then rewritten to use unsigned limbs instead +//! of signed limbs. +//! +//! This uses the formally-verified field arithmetic generated by the +//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto) + +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 fiat_crypto::curve25519_32::*; + +/// A `FieldElement2625` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// In the 32-bit implementation, a `FieldElement` is represented in +/// radix \\(2\^{25.5}\\) as ten `u32`s. This means that a field +/// element \\(x\\) is represented as +/// $$ +/// x = \sum\_{i=0}\^9 x\_i 2\^{\lceil i \frac {51} 2 \rceil} +/// = x\_0 + x\_1 2\^{26} + x\_2 2\^{51} + x\_3 2\^{77} + \cdots + x\_9 2\^{230}; +/// $$ +/// the coefficients are alternately bounded by \\(2\^{25}\\) and +/// \\(2\^{26}\\). The limbs are allowed to grow between reductions up +/// to \\(2\^{25+b}\\) or \\(2\^{26+b}\\), where \\(b = 1.75\\). +/// +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement51` +/// or `FieldElement2625`. +/// +/// The backend-specific type `FieldElement2625` should not be used +/// outside of the `curve25519_dalek::field` module. +#[derive(Copy, Clone)] +pub struct FieldElement2625(pub(crate) [u32; 10]); + +impl Debug for FieldElement2625 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "FieldElement2625({:?})", &self.0[..]) + } +} + +impl Zeroize for FieldElement2625 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 { + fn add_assign(&mut self, _rhs: &'b FieldElement2625) { + 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 FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn add(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + 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 FieldElement2625> for FieldElement2625 { + fn sub_assign(&mut self, _rhs: &'b FieldElement2625) { + 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 FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn sub(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + 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 FieldElement2625> for FieldElement2625 { + fn mul_assign(&mut self, _rhs: &'b FieldElement2625) { + let input = self.0; + fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0); + } +} + +impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn mul(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0); + output + } +} + +impl<'a> Neg for &'a FieldElement2625 { + type Output = FieldElement2625; + fn neg(self) -> FieldElement2625 { + 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 FieldElement2625 { + fn conditional_select( + a: &FieldElement2625, + b: &FieldElement2625, + choice: Choice, + ) -> FieldElement2625 { + let mut output = [0u32; 10]; + fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0); + FieldElement2625(output) + } + + fn conditional_assign(&mut self, other: &FieldElement2625, choice: Choice) { + let mut output = [0u32; 10]; + let choicebit = choice.unwrap_u8() as fiat_25519_u1; + fiat_25519_cmovznz_u32(&mut output[0], choicebit, self.0[0], other.0[0]); + fiat_25519_cmovznz_u32(&mut output[1], choicebit, self.0[1], other.0[1]); + fiat_25519_cmovznz_u32(&mut output[2], choicebit, self.0[2], other.0[2]); + fiat_25519_cmovznz_u32(&mut output[3], choicebit, self.0[3], other.0[3]); + fiat_25519_cmovznz_u32(&mut output[4], choicebit, self.0[4], other.0[4]); + fiat_25519_cmovznz_u32(&mut output[5], choicebit, self.0[5], other.0[5]); + fiat_25519_cmovznz_u32(&mut output[6], choicebit, self.0[6], other.0[6]); + fiat_25519_cmovznz_u32(&mut output[7], choicebit, self.0[7], other.0[7]); + fiat_25519_cmovznz_u32(&mut output[8], choicebit, self.0[8], other.0[8]); + fiat_25519_cmovznz_u32(&mut output[9], choicebit, self.0[9], other.0[9]); + *self = FieldElement2625(output); + } + + fn conditional_swap(a: &mut FieldElement2625, b: &mut FieldElement2625, choice: Choice) { + u32::conditional_swap(&mut a.0[0], &mut b.0[0], choice); + u32::conditional_swap(&mut a.0[1], &mut b.0[1], choice); + u32::conditional_swap(&mut a.0[2], &mut b.0[2], choice); + u32::conditional_swap(&mut a.0[3], &mut b.0[3], choice); + u32::conditional_swap(&mut a.0[4], &mut b.0[4], choice); + u32::conditional_swap(&mut a.0[5], &mut b.0[5], choice); + u32::conditional_swap(&mut a.0[6], &mut b.0[6], choice); + u32::conditional_swap(&mut a.0[7], &mut b.0[7], choice); + u32::conditional_swap(&mut a.0[8], &mut b.0[8], choice); + u32::conditional_swap(&mut a.0[9], &mut b.0[9], choice); + } +} + +impl FieldElement2625 { + /// Invert the sign of this field element + pub fn negate(&mut self) { + let neg = self.neg(); + self.0 = neg.0; + } + + /// Construct zero. + pub fn zero() -> FieldElement2625 { + FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + } + + /// Construct one. + pub fn one() -> FieldElement2625 { + FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + } + + /// Construct -1. + pub fn minus_one() -> FieldElement2625 { + FieldElement2625([ + 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, + 0x3ffffff, 0x1ffffff, + ]) + } + + /// Given `k > 0`, return `self^(2^k)`. + pub fn pow2k(&self, k: u32) -> FieldElement2625 { + debug_assert!(k > 0); + let mut z = self.square(); + for _ in 1..k { + z = z.square(); + } + z + } + + /// Load a `FieldElement2625` 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(data: &[u8; 32]) -> FieldElement2625 { + let mut temp = [0u8; 32]; + temp.copy_from_slice(data); + temp[31] &= 127u8; + let mut output = [0u32; 10]; + fiat_25519_from_bytes(&mut output, &temp); + FieldElement2625(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; + } + + /// Compute `self^2`. + pub fn square(&self) -> FieldElement2625 { + let mut output = *self; + fiat_25519_carry_square(&mut output.0, &self.0); + output + } + + /// Compute `2*self^2`. + pub fn square2(&self) -> FieldElement2625 { + 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 + } +} diff --git a/src/backend/serial/fiat_u32/mod.rs b/src/backend/serial/fiat_u32/mod.rs new file mode 100644 index 000000000..974316e56 --- /dev/null +++ b/src/backend/serial/fiat_u32/mod.rs @@ -0,0 +1,26 @@ +// -*- 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 +// - Henry de Valence + +//! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier. +//! +//! This code is intended to be portable, but it requires that +//! multiplication of two \\(32\\)-bit values to a \\(64\\)-bit result +//! is constant-time on the target platform. +//! +//! This uses the formally-verified field arithmetic generated by the +//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto) + +#[path = "../u32/scalar.rs"] +pub mod scalar; + +pub mod field; + +#[path = "../u32/constants.rs"] +pub mod constants; diff --git a/src/backend/serial/fiat/field.rs b/src/backend/serial/fiat_u64/field.rs similarity index 98% rename from src/backend/serial/fiat/field.rs rename to src/backend/serial/fiat_u64/field.rs index dbb9fb09b..7e381b6c4 100644 --- a/src/backend/serial/fiat/field.rs +++ b/src/backend/serial/fiat_u64/field.rs @@ -10,6 +10,9 @@ //! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit //! limbs with \\(128\\)-bit products. +//! +//! This uses the formally-verified field arithmetic generated by the +//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto) use core::fmt::Debug; use core::ops::Neg; diff --git a/src/backend/serial/fiat/mod.rs b/src/backend/serial/fiat_u64/mod.rs similarity index 100% rename from src/backend/serial/fiat/mod.rs rename to src/backend/serial/fiat_u64/mod.rs diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index a4a03dd0c..a01d4a3f6 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -25,11 +25,12 @@ #[cfg(not(any( feature = "u32_backend", feature = "u64_backend", + feature = "fiat_u32_backend", feature = "fiat_u64_backend" )))] compile_error!( "no curve25519-dalek backend cargo feature enabled! \ - please enable one of: u32_backend, u64_backend, fiat_u64_backend" + please enable one of: u32_backend, u64_backend, fiat_u32_backend, fiat_u64_backend" ); #[cfg(feature = "u32_backend")] @@ -38,8 +39,11 @@ pub mod u32; #[cfg(feature = "u64_backend")] pub mod u64; +#[cfg(feature = "fiat_u32_backend")] +pub mod fiat_u32; + #[cfg(feature = "fiat_u64_backend")] -pub mod fiat; +pub mod fiat_u64; pub mod curve_models; diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index 73f353f35..7c381d438 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -13,8 +13,8 @@ //! lookup tables of pre-computed points. use backend::serial::curve_models::AffineNielsPoint; -use backend::serial::u32::field::FieldElement2625; -use backend::serial::u32::scalar::Scalar29; +use super::field::FieldElement2625; +use super::scalar::Scalar29; use edwards::{EdwardsBasepointTable, EdwardsPoint}; use window::{LookupTable, NafLookupTable8}; diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index 0b2d50ac9..c941b2082 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -10,9 +10,9 @@ //! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. +use backend::serial::curve_models::AffineNielsPoint; use super::field::FieldElement51; use super::scalar::Scalar52; -use backend::serial::curve_models::AffineNielsPoint; 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. diff --git a/src/constants.rs b/src/constants.rs index 5887c7ab8..8831dda31 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -33,12 +33,14 @@ use ristretto::CompressedRistretto; use montgomery::MontgomeryPoint; use scalar::Scalar; +#[cfg(feature = "fiat_u32_backend")] +pub use backend::serial::fiat_u32::constants::*; #[cfg(feature = "fiat_u64_backend")] -pub use backend::serial::fiat::constants::*; -#[cfg(feature = "u32_backend")] -pub use backend::serial::u32::constants::*; +pub use backend::serial::fiat_u64::constants::*; #[cfg(feature = "u64_backend")] pub use backend::serial::u64::constants::*; +#[cfg(feature = "u32_backend")] +pub use backend::serial::u32::constants::*; /// The Ed25519 basepoint, in `CompressedEdwardsY` format. /// diff --git a/src/field.rs b/src/field.rs index 58127ec5b..40dcf7076 100644 --- a/src/field.rs +++ b/src/field.rs @@ -32,15 +32,20 @@ use subtle::ConstantTimeEq; use constants; use backend; +#[cfg(feature = "fiat_u32_backend")] +pub use backend::serial::fiat_u32::field::*; #[cfg(feature = "fiat_u64_backend")] -pub use backend::serial::fiat::field::*; +pub use backend::serial::fiat_u64::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. +/// Using formally-verified field arithmetic from fiat-crypto +#[cfg(feature = "fiat_u32_backend")] +pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; #[cfg(feature = "fiat_u64_backend")] -pub type FieldElement = backend::serial::fiat::field::FieldElement51; +pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; #[cfg(feature = "u64_backend")] pub use backend::serial::u64::field::*; diff --git a/src/lib.rs b/src/lib.rs index 982d32347..f3530850c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,7 @@ pub extern crate digest; extern crate rand_core; extern crate zeroize; -#[cfg(feature = "fiat_u64_backend")] +#[cfg(any(feature = "fiat_u64_backend", feature = "fiat_u32_backend"))] extern crate fiat_crypto; // Used for traits related to constant-time code. diff --git a/src/scalar.rs b/src/scalar.rs index b7376ad00..b1139069e 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -169,8 +169,10 @@ use constants; /// /// This is a type alias for one of the scalar types in the `backend` /// module. +#[cfg(feature = "fiat_u32_backend")] +type UnpackedScalar = backend::serial::fiat_u32::scalar::Scalar29; #[cfg(feature = "fiat_u64_backend")] -type UnpackedScalar = backend::serial::fiat::scalar::Scalar52; +type UnpackedScalar = backend::serial::fiat_u64::scalar::Scalar52; /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. /// From d1ed427af517cacf8dff8f8f950476a80c327194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 11 Jan 2021 13:39:48 -0800 Subject: [PATCH 8/8] add fiat backends to Travis tests --- .travis.yml | 4 ++++ Cargo.toml | 2 +- src/lib.rs | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4b61db34b..f2411e005 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,10 @@ env: - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u32_backend' # Tests the u64 backend - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend' + # Tests the fiat_u32 backend + - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std fiat_u32_backend' + # Tests the fiat_u64 backend + - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std fiat_u64_backend' # Tests the simd backend - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std simd_backend' # Tests serde support and default feature selection diff --git a/Cargo.toml b/Cargo.toml index d33703fe7..e39b73a45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ u32_backend = [] u64_backend = [] # fiat-u64 backend (with formally-verified field arith) uses u64s with u128 products. fiat_u64_backend = ["fiat-crypto"] -# fiat-u32 backend (with formally-verified field arith) uses u64s with u128 products. +# fiat-u32 backend (with formally-verified field arith) uses u32s with u64 products. fiat_u32_backend = ["fiat-crypto"] # The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA. simd_backend = ["nightly", "u64_backend", "packed_simd"] diff --git a/src/lib.rs b/src/lib.rs index f3530850c..e15ffa0ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ // 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")]