diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 3947fb9..be3a347 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -22,11 +22,9 @@ //! `32bit` since identifiers can't start with letters, and the backends //! do use `u32`/`u64`, so this seems like a least-bad option. -/// Code using `u32`s and a `(u32, u32) -> u64` multiplier. #[cfg(not(feature="radix_51"))] pub mod u32; -/// Code using `u64`s and a `(u64, u64) -> u128` multiplier. #[cfg(feature="radix_51")] pub mod u64; diff --git a/src/backend/u32/field.rs b/src/backend/u32/field.rs index 10c17e1..fb6b36f 100644 --- a/src/backend/u32/field.rs +++ b/src/backend/u32/field.rs @@ -8,19 +8,12 @@ // - Isis Agora Lovecruft // - Henry de Valence -//! Field arithmetic for ℤ/(2²⁵⁵-19), using 32-bit arithmetic with -//! 64-bit products. +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit +//! limbs with \\(64\\)-bit products. //! -//! This code was originally derived from Adam Langley's -//! curve25519-donna and (Golang) ed25519 implementations. -//! -//! This implementation is intended for platforms that can multiply -//! 32-bit inputs to produce 64-bit outputs. -//! -//! This implementation is not preferred for use on x86_64, since the -//! 64-bit implementation is both much simpler and much faster. -//! However, that implementation requires Rust's `u128`, which is not -//! yet stable. +//! This code was originally derived from Adam Langley's Golang ed25519 +//! implementation, and was then rewritten to use unsigned limbs instead +//! of signed limbs. use core::fmt::Debug; use core::ops::{Add, AddAssign}; @@ -30,28 +23,28 @@ use core::ops::Neg; use subtle::ConditionallyAssignable; -/// A `FieldElement32` represents an element of the field GF(2^255 - 19). +/// A `FieldElement32` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). /// -/// In the 32-bit implementation, a `FieldElement32` is represented in -/// radix 2^25.5 as ten `u32`s, so that an element t, entries -/// t[0],...,t[9], represents `sum(t[i]*2^ceil(i*51/2))`. +/// 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\\). /// -/// The coefficients t[i] are allowed to grow between multiplications. -/// -/// XXX document by how much -/// -/// # Warning -/// -/// You almost certainly do not want to use `FieldElement32` directly. Consider -/// using `curve25519_dalek::field::FieldElement`, which will automatically -/// select between `FieldElement32` and `FieldElement64` depending on whether -/// curve25519-dalek was compiled with `--features="nightly"`. -/// -/// This implementation, `FieldElement32`, is intended for platforms that can -/// multiply 32-bit inputs to produce 64-bit outputs, and is not preferred for -/// use on x86_64, since the 64-bit implementation is both much simpler and much -/// faster. However, the `FieldElement64` implementation requires Rust's -/// `u128`, which is not yet stable. +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement64` +/// or `FieldElement32`. +/// +/// The backend-specific type `FieldElement32` should not be used +/// outside of the `curve25519_dalek::field` module. #[derive(Copy, Clone)] pub struct FieldElement32(pub (crate) [u32; 10]); diff --git a/src/backend/u32/mod.rs b/src/backend/u32/mod.rs index fa54a15..bd4cb75 100644 --- a/src/backend/u32/mod.rs +++ b/src/backend/u32/mod.rs @@ -8,8 +8,14 @@ // - 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. + pub mod field; pub mod scalar; -pub mod constants; \ No newline at end of file +pub mod constants; diff --git a/src/backend/u64/constants.rs b/src/backend/u64/constants.rs index 3af570c..a51ee81 100644 --- a/src/backend/u64/constants.rs +++ b/src/backend/u64/constants.rs @@ -8,9 +8,7 @@ // - Isis Agora Lovecruft // - Henry de Valence -//! This module contains various constants (such as curve parameters -//! and useful field elements like `sqrt(-1)`), as well as -//! lookup tables of pre-computed points. +//! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. use backend::u64::field::FieldElement64; use backend::u64::scalar::Scalar64; diff --git a/src/backend/u64/field.rs b/src/backend/u64/field.rs index 3c6d4f0..e5b152e 100644 --- a/src/backend/u64/field.rs +++ b/src/backend/u64/field.rs @@ -8,14 +8,8 @@ // - Isis Agora Lovecruft // - Henry de Valence -//! Field arithmetic for ℤ/(2²⁵⁵-19), using 64-bit arithmetic wuth -//! 128-bit products. -//! -//! On x86_64, the multiplications lower 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 instruction set provides `MULX` and friends, which gives even -//! better performance. +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit +//! limbs with \\(128\\)-bit products. use core::fmt::Debug; use core::ops::{Add, AddAssign}; @@ -25,25 +19,21 @@ use core::ops::Neg; use subtle::ConditionallyAssignable; -/// A `FieldElement64` represents an element of the field GF(2^255 - 19). +/// A `FieldElement64` 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 mod `p`. +/// radix \\(2\^{51}\\) as five `u64`s; the coefficients are allowed to +/// grow up to \\(2\^{54}\\) between reductions modulo \\(p\\). /// -/// # Warning -/// -/// You almost certainly do not want to use `FieldElement64` directly. Consider -/// using `curve25519_dalek::field::FieldElement`, which will automatically -/// select between `FieldElement32` and `FieldElement64` depending on whether -/// curve25519-dalek was compiled with `--features="nightly"`. -/// -/// This implementation, `FieldElement64`, is intended for x64_64 platforms, -/// which have the `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 instruction set provides `MULX` and friends, -/// which gives even better performance. This implementation requires Rust's -/// `u128`, which is not yet stable. +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement64` +/// or `FieldElement32`. +/// +/// The backend-specific type `FieldElement64` should not be used +/// outside of the `curve25519_dalek::field` module. #[derive(Copy, Clone)] pub struct FieldElement64(pub (crate) [u64; 5]); diff --git a/src/backend/u64/mod.rs b/src/backend/u64/mod.rs index fa54a15..51980d8 100644 --- a/src/backend/u64/mod.rs +++ b/src/backend/u64/mod.rs @@ -8,8 +8,19 @@ // - 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. + pub mod field; pub mod scalar; -pub mod constants; \ No newline at end of file +pub mod constants; diff --git a/src/backend/u64/scalar.rs b/src/backend/u64/scalar.rs index a6d14ad..12da445 100644 --- a/src/backend/u64/scalar.rs +++ b/src/backend/u64/scalar.rs @@ -1,19 +1,23 @@ -//! Arithmetic mod 2^252 + 27742317777372353535851937790883648493 -//! with 5 52-bit unsigned limbs. 51-bit limbs would cover the -//! desired bit range (253 bits), but isn't large enough to reduce -//! a 512 bit number with Montgomery multiplication, so 52 bits is -//! used instead +//! Arithmetic mod \\(2\^{252} + 27742317777372353535851937790883648493\\) +//! with five \\(52\\)-bit unsigned limbs. //! -//! To see that this is safe for intermediate results, note that -//! the largest limb in a 5 by 5 product of 52-bit limbs will be +//! \\(51\\)-bit limbs would cover the desired bit range (\\(253\\) +//! bits), but isn't large enough to reduce a \\(512\\)-bit number with +//! Montgomery multiplication, so \\(52\\) bits is used instead. To see +//! that this is safe for intermediate results, note that the largest +//! limb in a \\(5\times 5\\) product of \\(52\\)-bit limbs will be +//! +//! ```text //! (0xfffffffffffff^2) * 5 = 0x4ffffffffffff60000000000005 (107 bits). +//! ``` use core::fmt::Debug; use core::ops::{Index, IndexMut}; use constants; -/// The `Scalar64` struct represents an element in ℤ/lℤ as 5 52-bit limbs +/// The `Scalar64` struct represents an element in +/// \\(\mathbb Z / \ell \mathbb Z\\) as 5 \\(52\\)-bit limbs. #[derive(Copy,Clone)] pub struct Scalar64(pub [u64; 5]); diff --git a/src/field.rs b/src/field.rs index 86f9aad..4532820 100644 --- a/src/field.rs +++ b/src/field.rs @@ -8,15 +8,19 @@ // - Isis Agora Lovecruft // - Henry de Valence -//! Field arithmetic for ℤ/(2²⁵⁵-19). +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\). //! -//! Partially based on Adam Langley's curve25519-donna and (Golang) -//! ed25519 implementations, with other techniques inspired by Mike -//! Hamburg's code. +//! The `curve25519_dalek::field` module provides a type alias +//! `curve25519_dalek::field::FieldElement` to a field element type +//! defined in the `backend` module; either `FieldElement64` or +//! `FieldElement32`. //! -//! This module re-exports either the 32-bit or 64-bit implementation, -//! and implements functions that are generic with respect to the -//! basic operations, such as inverses and square roots. +//! Field operations defined in terms of machine +//! operations, such as field multiplication or squaring, are defined in +//! the backend implementation. +//! +//! Field operations defined in terms of other field operations, such as +//! field inversion or square roots, are defined here. use core::cmp::{Eq, PartialEq}; @@ -31,13 +35,21 @@ use backend; #[cfg(feature="radix_51")] pub use backend::u64::field::*; -/// A `FieldElement` represents an element of the field GF(2^255 - 19). +/// 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="radix_51")] pub type FieldElement = backend::u64::field::FieldElement64; #[cfg(not(feature="radix_51"))] pub use backend::u32::field::*; -/// A `FieldElement` represents an element of the field GF(2^255 - 19). +/// 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(not(feature="radix_51"))] pub type FieldElement = backend::u32::field::FieldElement32;