mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Merge branch 'feature/texify-formulas' into develop
This commit is contained in:
commit
fce10f5736
15 changed files with 403 additions and 313 deletions
5
Makefile
5
Makefile
|
|
@ -1,7 +1,8 @@
|
|||
FEATURES := nightly yolocrypto
|
||||
|
||||
doc:
|
||||
cargo rustdoc --features "nightly yolocrypto" -- --html-in-header rustdoc-include-katex-header.html
|
||||
cargo rustdoc --features "$(FEATURES)" -- --html-in-header rustdoc-include-katex-header.html
|
||||
|
||||
doc-internal:
|
||||
cargo rustdoc --features "nightly yolocrypto" -- --html-in-header rustdoc-include-katex-header.html --no-defaults --passes "collapse-docs" --passes "unindent-comments"
|
||||
cargo rustdoc --features "$(FEATURES)" -- --html-in-header rustdoc-include-katex-header.html --document-private-items
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,19 +8,12 @@
|
|||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! 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]);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,14 @@
|
|||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! 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;
|
||||
pub mod constants;
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@
|
|||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! 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;
|
||||
|
|
|
|||
|
|
@ -8,14 +8,8 @@
|
|||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! 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]);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,19 @@
|
|||
// - 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.
|
||||
|
||||
pub mod field;
|
||||
|
||||
pub mod scalar;
|
||||
|
||||
pub mod constants;
|
||||
pub mod constants;
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@
|
|||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! 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 various constants, such as the Ristretto and Ed25519 basepoints.
|
||||
//!
|
||||
//! Most of the constants are given with
|
||||
//! `LONG_DESCRIPTIVE_UPPER_CASE_NAMES`, but they can be brought into
|
||||
|
|
|
|||
|
|
@ -15,59 +15,112 @@
|
|||
//!
|
||||
//! Internally, we use several different models for the curve. Here
|
||||
//! is a sketch of the relationship between the models, following [a
|
||||
//! post](https://moderncrypto.org/mail-archive/curves/2016/000807.html)
|
||||
//! by Ben Smith on the moderncrypto mailing list.
|
||||
//! post][smith-moderncrypto]
|
||||
//! by Ben Smith on the `moderncrypto` mailing list. This is also briefly
|
||||
//! discussed in section 2.5 of [_Montgomery curves and their
|
||||
//! arithmetic_][costello-smith-2017] by Costello and Smith.
|
||||
//!
|
||||
//! Begin with the affine equation for the curve,
|
||||
//! $$
|
||||
//! -x\^2 + y\^2 = 1 + dx\^2y\^2.
|
||||
//! $$
|
||||
//! Next, pass to the projective closure \\(\mathbb P\^1 \times \mathbb
|
||||
//! P\^1 \\) by setting \\(x=X/Z\\), \\(y=Y/T.\\) Clearing denominators
|
||||
//! gives the model
|
||||
//! $$
|
||||
//! -X\^2T\^2 + Y\^2Z\^2 = Z\^2T\^2 + dX\^2Y\^2.
|
||||
//! $$
|
||||
//! In `curve25519-dalek`, this is represented as the `CompletedPoint`
|
||||
//! struct.
|
||||
//! To map from \\(\mathbb P\^1 \times \mathbb P\^1 \\), a product of
|
||||
//! two lines, to \\(\mathbb P\^3\\), we use the [Segre
|
||||
//! embedding](https://en.wikipedia.org/wiki/Segre_embedding)
|
||||
//! $$
|
||||
//! \sigma : ((X:Z),(Y:T)) \mapsto (XY:XT:ZY:ZT).
|
||||
//! $$
|
||||
//! Using coordinates \\( (W_0:W_1:W_2:W_3) \\) for \\(\mathbb P\^3\\),
|
||||
//! the image \\(\sigma (\mathbb P\^1 \times \mathbb P\^1) \\) is the
|
||||
//! surface defined by \\( W_0 W_3 = W_1 W_2 \\), and under \\(
|
||||
//! \sigma\\), the equation above becomes
|
||||
//! $$
|
||||
//! -W\_1\^2 + W\_2\^2 = W\_3\^2 + dW\_0\^2,
|
||||
//! $$
|
||||
//! so that the curve is given by the pair of equations
|
||||
//! $$
|
||||
//! \begin{aligned}
|
||||
//! -W\_1\^2 + W\_2\^2 &= W\_3\^2 + dW\_0\^2, \\\\
|
||||
//! W_0 W_3 &= W_1 W_2.
|
||||
//! \end{aligned}
|
||||
//! $$
|
||||
//! Up to variable naming, this is exactly the "extended" curve model
|
||||
//! introduced in [_Twisted Edwards Curves
|
||||
//! Revisited_][hisil-wong-carter-dawson-2008] by Hisil, Wong, Carter,
|
||||
//! and Dawson. In `curve25519-dalek`, it is represented as the
|
||||
//! `ExtendedPoint` struct. We can map from \\(\mathbb P\^3 \\) to
|
||||
//! \\(\mathbb P\^2 \\) by sending \\( (W\_0:W\_1:W\_2:W\_3) \\) to \\(
|
||||
//! (W\_1:W\_2:W\_3) \\). Notice that
|
||||
//! $$
|
||||
//! \frac {W\_1} {W\_3} = \frac {XT} {ZT} = \frac X Z = x,
|
||||
//! $$
|
||||
//! and
|
||||
//! $$
|
||||
//! \frac {W\_2} {W\_3} = \frac {YZ} {ZT} = \frac Y T = y,
|
||||
//! $$
|
||||
//! so this is the same as if we had started with the affine model
|
||||
//! and passed to \\( \mathbb P\^2 \\) by setting \\( x = W\_1 / W\_3
|
||||
//! \\), \\(y = W\_2 / W\_3 \\).
|
||||
//! Up to variable naming, this is the projective representation
|
||||
//! introduced in in [_Twisted Edwards
|
||||
//! Curves_][bernstein-birkner-joye-lange-peters-2008] by Bernstein,
|
||||
//! Birkner, Joye, Lange, and Peters. In `curve25519-dalek`, it is
|
||||
//! represented by the `ProjectivePoint` struct.
|
||||
//!
|
||||
//! -x² + y² = 1 + dx²y². <span style="float: right">(1)</span>
|
||||
//! # Passing between curve models
|
||||
//!
|
||||
//! Next, pass to the projective closure 𝗣^1 x 𝗣^1 by setting x=X/Z,
|
||||
//! y=Y/T. Clearing denominators gives the model
|
||||
//! Although the \\( \mathbb P\^3 \\) model provides faster addition
|
||||
//! formulas, the \\( \mathbb P\^2 \\) model provides faster doubling
|
||||
//! formulas. Hisil, Wong, Carter, and Dawson therefore suggest mixing
|
||||
//! coordinate systems for scalar multiplication, attributing the idea
|
||||
//! to [a 1998 paper][cohen-miyaji-ono-1998] of Cohen, Miyagi, and Ono.
|
||||
//!
|
||||
//! -X²T² + Y²Z² = Z²T² + dX²Y². <span style="float: right">(2)<span>
|
||||
//! Their suggestion is to vary the formulas used by context, using a
|
||||
//! \\( \mathbb P\^2 \rightarrow \mathbb P\^2 \\) doubling formula when
|
||||
//! a doubling is followed
|
||||
//! by another doubling, a \\( \mathbb P\^2 \rightarrow \mathbb P\^3 \\)
|
||||
//! doubling formula when a doubling is followed by an addition, and
|
||||
//! computing point additions using a \\( \mathbb P\^3 \times \mathbb P\^3
|
||||
//! \rightarrow \mathbb P\^2 \\) formula.
|
||||
//!
|
||||
//! To map from 𝗣^1 x 𝗣^1, a product of two lines, to 𝗣^3, we use the
|
||||
//! Segre embedding,
|
||||
//! The `ref10` reference implementation of [Ed25519][ed25519], by
|
||||
//! Bernstein, Duif, Lange, Schwabe, and Yang, tweaks
|
||||
//! this strategy, factoring the addition formulas through the
|
||||
//! completion \\( \mathbb P\^1 \times \mathbb P\^1 \\), so that the
|
||||
//! output of an addition or doubling always lies in \\( \mathbb P\^1 \times
|
||||
//! \mathbb P\^1\\), and the choice of which formula to use is replaced
|
||||
//! by a choice of whether to convert the result to \\( \mathbb P\^2 \\)
|
||||
//! or \\(\mathbb P\^2 \\). However, this tweak is not described in
|
||||
//! their paper, only in their software.
|
||||
//!
|
||||
//! σ : ((X:Z),(Y:T)) ↦ (XY:XT:ZY:ZT). <span style="float: right">(3)</span>
|
||||
//! Our naming for the `CompletedPoint` (\\(\mathbb P\^1 \times \mathbb
|
||||
//! P\^1 \\)), `ProjectivePoint` (\\(\mathbb P\^2 \\)), and
|
||||
//! `ExtendedPoint` (\\(\mathbb P\^3 \\)) structs follows the naming in
|
||||
//! Adam Langley's [Golang ed25519][agl-ed25519] implementation, which
|
||||
//! `curve25519-dalek` was originally derived from.
|
||||
//!
|
||||
//! Using coordinates (W₀:W₁:W₂:W₃) for 𝗣^3, the image of σ(𝗣^1 x 𝗣^1)
|
||||
//! is the surface defined by W₀W₃=W₁W₂, and under σ, equation (2)
|
||||
//! becomes
|
||||
//! Finally, to accelerate readditions, we use two cached point formats
|
||||
//! in "Niels coordinates", named for Niels Duif,
|
||||
//! one for the affine model and one for the \\( \mathbb P\^3 \\) model:
|
||||
//!
|
||||
//! -W₁² + W₂² = W₃² + dW₀². <span style="float: right">(4)</span>
|
||||
//! * `AffineNielsPoint`: \\( (y+x, y-x, 2dxy) \\)
|
||||
//! * `ProjectiveNielsPoint`: \\( (Y+X, Y-X, Z, 2dXY) \\)
|
||||
//!
|
||||
//! Up to variable naming, this is exactly the curve model introduced
|
||||
//! in ["Twisted Edwards Curves
|
||||
//! Revisited"](https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf)
|
||||
//! by Hisil, Wong, Carter, and Dawson. We can map from 𝗣^3 to 𝗣² by
|
||||
//! sending (W₀:W₁:W₂:W₃) to (W₁:W₂:W₃). Notice that
|
||||
//!
|
||||
//! W₁/W₃ = XT/ZT = X/Z = x <span style="float: right">(5)</span>
|
||||
//!
|
||||
//! W₂/W₃ = ZY/ZT = Y/T = y, <span style="float: right">(6)</span>
|
||||
//!
|
||||
//! so this is the same as if we had started with the affine model (1)
|
||||
//! and passed to 𝗣^2 by setting `x = W₁/W₃`, `y = W₂/W₃`. Up to
|
||||
//! variable naming, this is the projective representation introduced
|
||||
//! in ["Twisted Edwards Curves"](https://eprint.iacr.org/2008/013).
|
||||
//!
|
||||
//! Following the implementation strategy in the ref10 reference
|
||||
//! implementation for [Ed25519](https://ed25519.cr.yp.to/ed25519-20110926.pdf),
|
||||
//! we use several different models for curve points:
|
||||
//!
|
||||
//! * `CompletedPoint`: points in 𝗣^1 x 𝗣^1;
|
||||
//! * `ExtendedPoint`: points in 𝗣^3;
|
||||
//! * `ProjectivePoint`: points in 𝗣^2.
|
||||
//!
|
||||
//! Finally, to accelerate additions, we use two cached point formats,
|
||||
//! one for the affine model and one for the 𝗣^3 model:
|
||||
//!
|
||||
//! * `AffineNielsPoint`: `(y+x, y-x, 2dxy)`
|
||||
//! * `ProjectiveNielsPoint`: `(Y+X, Y-X, Z, 2dXY)`
|
||||
//!
|
||||
//! [1]: https://moderncrypto.org/mail-archive/curves/2016/000807.html
|
||||
//! [smith-moderncrypto]: https://moderncrypto.org/mail-archive/curves/2016/000807.html
|
||||
//! [costello-smith-2017]: https://eprint.iacr.org/2017/212
|
||||
//! [hisil-wong-carter-dawson-2008]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf
|
||||
//! [bernstein-birkner-joye-lange-peters-2008]: https://eprint.iacr.org/2008/013
|
||||
//! [cohen-miyaji-ono-1998]: https://link.springer.com/content/pdf/10.1007%2F3-540-49649-1_6.pdf
|
||||
//! [ed25519]: https://eprint.iacr.org/2011/368
|
||||
//! [agl-ed25519]: https://github.com/agl/ed25519
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
|
|
@ -85,8 +138,13 @@ use traits::ValidityCheck;
|
|||
// Internal point representations
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/// A `ProjectivePoint` is a point on the curve in 𝗣²(𝔽ₚ).
|
||||
/// A point (x,y) in the affine model corresponds to (x:y:1).
|
||||
/// A `ProjectivePoint` is a point \\((X:Y:Z)\\) on the \\(\mathbb
|
||||
/// P\^2\\) model of the curve.
|
||||
/// A point \\((x,y)\\) in the affine model corresponds to
|
||||
/// \\((x:y:1)\\).
|
||||
///
|
||||
/// More details on the relationships between the different curve models
|
||||
/// can be found in the module-level documentation.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ProjectivePoint {
|
||||
pub X: FieldElement,
|
||||
|
|
@ -94,8 +152,13 @@ pub struct ProjectivePoint {
|
|||
pub Z: FieldElement,
|
||||
}
|
||||
|
||||
/// A `CompletedPoint` is a point ((X:Z), (Y:T)) in 𝗣¹(𝔽ₚ)×𝗣¹(𝔽ₚ).
|
||||
/// A point (x,y) in the affine model corresponds to ((x:1),(y:1)).
|
||||
/// A `CompletedPoint` is a point \\(((X:Z), (Y:T))\\) on the \\(\mathbb
|
||||
/// P\^1 \times \mathbb P\^1 \\) model of the curve.
|
||||
/// A point (x,y) in the affine model corresponds to \\( ((x:1),(y:1))
|
||||
/// \\).
|
||||
///
|
||||
/// More details on the relationships between the different curve models
|
||||
/// can be found in the module-level documentation.
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct CompletedPoint {
|
||||
|
|
@ -106,9 +169,10 @@ pub struct CompletedPoint {
|
|||
}
|
||||
|
||||
/// A pre-computed point in the affine model for the curve, represented as
|
||||
/// (y+x, y-x, 2dxy). These precomputations accelerate addition and
|
||||
/// subtraction, and were introduced by Niels Duif in the ed25519 paper
|
||||
/// ["High-Speed High-Security Signatures"](https://ed25519.cr.yp.to/ed25519-20110926.pdf).
|
||||
/// \\((y+x, y-x, 2dxy)\\) in "Niels coordinates".
|
||||
///
|
||||
/// More details on the relationships between the different curve models
|
||||
/// can be found in the module-level documentation.
|
||||
// Safe to derive Eq because affine coordinates.
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
#[allow(missing_docs)]
|
||||
|
|
@ -118,10 +182,11 @@ pub struct AffineNielsPoint {
|
|||
pub xy2d: FieldElement,
|
||||
}
|
||||
|
||||
/// A pre-computed point in the P³(𝔽ₚ) model for the curve, represented as
|
||||
/// (Y+X, Y-X, Z, 2dXY). These precomputations accelerate addition and
|
||||
/// subtraction, and were introduced by Niels Duif in the ed25519 paper
|
||||
/// ["High-Speed High-Security Signatures"](https://ed25519.cr.yp.to/ed25519-20110926.pdf).
|
||||
/// A pre-computed point on the \\( \mathbb P\^3 \\) model for the
|
||||
/// curve, represented as \\((Y+X, Y-X, Z, 2dXY)\\) in "Niels coordinates".
|
||||
///
|
||||
/// More details on the relationships between the different curve models
|
||||
/// can be found in the module-level documentation.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ProjectiveNielsPoint {
|
||||
pub Y_plus_X: FieldElement,
|
||||
|
|
@ -213,14 +278,10 @@ impl ConditionallyAssignable for AffineNielsPoint {
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
impl ProjectivePoint {
|
||||
/// Convert to the extended twisted Edwards representation of this
|
||||
/// point.
|
||||
/// Convert this point from the \\( \mathbb P\^2 \\) model to the
|
||||
/// \\( \mathbb P\^3 \\) model.
|
||||
///
|
||||
/// From §3 in [0]:
|
||||
///
|
||||
/// Given (X:Y:Z) in Ɛ, passing to Ɛₑ can be performed in 3M+1S by
|
||||
/// computing (XZ,YZ,XY,Z²). (Note that in that paper, points are
|
||||
/// (X:Y:T:Z) so this really does match the code below).
|
||||
/// This costs \\(3 \mathrm M + 1 \mathrm S\\).
|
||||
pub fn to_extended(&self) -> ExtendedPoint {
|
||||
ExtendedPoint{
|
||||
X: &self.X * &self.Z,
|
||||
|
|
@ -232,7 +293,10 @@ impl ProjectivePoint {
|
|||
}
|
||||
|
||||
impl CompletedPoint {
|
||||
/// Convert to a ProjectivePoint
|
||||
/// Convert this point from the \\( \mathbb P\^1 \times \mathbb P\^1
|
||||
/// \\) model to the \\( \mathbb P\^2 \\) model.
|
||||
///
|
||||
/// This costs \\(3 \mathrm M \\).
|
||||
pub fn to_projective(&self) -> ProjectivePoint {
|
||||
ProjectivePoint{
|
||||
X: &self.X * &self.T,
|
||||
|
|
@ -241,7 +305,10 @@ impl CompletedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert to an ExtendedPoint
|
||||
/// Convert this point from the \\( \mathbb P\^1 \times \mathbb P\^1
|
||||
/// \\) model to the \\( \mathbb P\^3 \\) model.
|
||||
///
|
||||
/// This costs \\(4 \mathrm M \\).
|
||||
pub fn to_extended(&self) -> ExtendedPoint {
|
||||
ExtendedPoint{
|
||||
X: &self.X * &self.T,
|
||||
|
|
@ -280,8 +347,13 @@ impl ProjectivePoint {
|
|||
// Addition and Subtraction
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// These are doc(hidden) so they don't appear in the public API docs.
|
||||
#[doc(hidden)]
|
||||
// XXX(hdevalence) These were doc(hidden) so they don't appear in the
|
||||
// public API docs.
|
||||
// However, that prevents them being used with --document-private-items,
|
||||
// so comment out the doc(hidden) for now until this is resolved
|
||||
//
|
||||
// upstream rust issue: https://github.com/rust-lang/rust/issues/46380
|
||||
//#[doc(hidden)]
|
||||
impl<'a, 'b> Add<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
|
||||
type Output = CompletedPoint;
|
||||
|
||||
|
|
@ -303,7 +375,7 @@ impl<'a, 'b> Add<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
//#[doc(hidden)]
|
||||
impl<'a, 'b> Sub<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
|
||||
type Output = CompletedPoint;
|
||||
|
||||
|
|
@ -325,7 +397,7 @@ impl<'a, 'b> Sub<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
//#[doc(hidden)]
|
||||
impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint {
|
||||
type Output = CompletedPoint;
|
||||
|
||||
|
|
@ -346,7 +418,7 @@ impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
//#[doc(hidden)]
|
||||
impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint {
|
||||
type Output = CompletedPoint;
|
||||
|
||||
|
|
|
|||
184
src/edwards.rs
184
src/edwards.rs
|
|
@ -52,12 +52,11 @@ use traits::select_precomputed_point;
|
|||
// Compressed points
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/// In "Edwards y" format, the point `(x,y)` on the curve is
|
||||
/// determined by the `y`-coordinate and the sign of `x`, marshalled
|
||||
/// into a 32-byte array.
|
||||
/// In "Edwards y" / "Ed25519" format, the curve point \\((x,y)\\) is
|
||||
/// determined by the \\(y\\)-coordinate and the sign of \\(x\\).
|
||||
///
|
||||
/// The first 255 bits of a `CompressedEdwardsY` represent the
|
||||
/// y-coordinate. The high bit of the 32nd byte gives the sign of `x`.
|
||||
/// \\(y\\)-coordinate. The high bit of the 32nd byte gives the sign of \\(x\\).
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct CompressedEdwardsY(pub [u8; 32]);
|
||||
|
||||
|
|
@ -80,9 +79,9 @@ impl CompressedEdwardsY {
|
|||
|
||||
/// Attempt to decompress to an `ExtendedPoint`.
|
||||
///
|
||||
/// Returns `None` if the input is not the `y`-coordinate of a
|
||||
/// Returns `None` if the input is not the \\(y\\)-coordinate of a
|
||||
/// curve point.
|
||||
pub fn decompress(&self) -> Option<ExtendedPoint> { // FromBytes()
|
||||
pub fn decompress(&self) -> Option<ExtendedPoint> {
|
||||
let Y = FieldElement::from_bytes(self.as_bytes());
|
||||
let Z = FieldElement::one();
|
||||
let YY = Y.square();
|
||||
|
|
@ -160,8 +159,11 @@ impl<'de> Deserialize<'de> for ExtendedPoint {
|
|||
// Internal point representations
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/// An `ExtendedPoint` is a point on the curve in 𝗣³(𝔽ₚ).
|
||||
/// A point (x,y) in the affine model corresponds to (x:y:1:xy).
|
||||
/// An `ExtendedPoint` represents a point on the Edwards form of Curve25519.
|
||||
///
|
||||
/// The name refers to the extended twisted Edwards coordinates of
|
||||
/// Hisil, Wong, Carter, and Dawson, and more details on curve models
|
||||
/// can be found in the `curve25519-dalek` internal documentation.
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct ExtendedPoint {
|
||||
|
|
@ -233,7 +235,7 @@ impl Equal for ExtendedPoint {
|
|||
// ------------------------------------------------------------------------
|
||||
|
||||
impl ExtendedPoint {
|
||||
/// Convert to a ProjectiveNielsPoint
|
||||
/// Convert to a `ProjectiveNielsPoint`
|
||||
pub(crate) fn to_projective_niels(&self) -> ProjectiveNielsPoint {
|
||||
ProjectiveNielsPoint{
|
||||
Y_plus_X: &self.Y + &self.X,
|
||||
|
|
@ -243,11 +245,10 @@ impl ExtendedPoint {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert the representation of this point from extended Twisted Edwards
|
||||
/// coodinates to projective coordinates.
|
||||
/// Convert the representation of this point from extended
|
||||
/// coordinates to projective coordinates.
|
||||
///
|
||||
/// Given a point in Ɛₑ, we can convert to projective coordinates
|
||||
/// cost-free by simply ignoring T.
|
||||
/// Free.
|
||||
pub(crate) fn to_projective(&self) -> ProjectivePoint {
|
||||
ProjectivePoint{
|
||||
X: self.X,
|
||||
|
|
@ -428,8 +429,8 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint {
|
|||
type Output = ExtendedPoint;
|
||||
/// Scalar multiplication: compute `scalar * self`.
|
||||
///
|
||||
/// Uses a window of size 4. Note: for scalar multiplication of
|
||||
/// the basepoint, `basepoint_mult` is approximately 4x faster.
|
||||
/// For scalar multiplication of a basepoint,
|
||||
/// `EdwardsBasepointTable` is approximately 4x faster.
|
||||
fn mul(self, scalar: &'b Scalar) -> ExtendedPoint {
|
||||
// Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P]
|
||||
let P = self.to_projective_niels();
|
||||
|
|
@ -469,27 +470,32 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint {
|
|||
impl<'a, 'b> Mul<&'b ExtendedPoint> for &'a Scalar {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
/// Scalar multiplication: compute `self * point`.
|
||||
/// Scalar multiplication: compute `scalar * self`.
|
||||
///
|
||||
/// Uses a window of size 4. Note: for scalar multiplication of
|
||||
/// the basepoint, `basepoint_mult` is approximately 4x faster.
|
||||
/// For scalar multiplication of a basepoint,
|
||||
/// `EdwardsBasepointTable` is approximately 4x faster.
|
||||
fn mul(self, point: &'b ExtendedPoint) -> ExtendedPoint {
|
||||
point * &self
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a vector of (possibly secret) scalars and a vector of
|
||||
/// (possibly secret) points, compute `c_1 P_1 + ... + c_n P_n`.
|
||||
/// Given an iterator of (possibly secret) scalars and an iterator of
|
||||
/// (possibly secret) points, compute
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||
/// $$
|
||||
///
|
||||
/// This function has the same behaviour as
|
||||
/// `vartime::multiscalar_mult` but is constant-time.
|
||||
///
|
||||
/// # Input
|
||||
///
|
||||
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
|
||||
/// error to call this function with two vectors of different lengths.
|
||||
/// A iterable of `Scalar`s and a iterable of `ExtendedPoints`. It is an
|
||||
/// error to call this function with two iterators of different lengths.
|
||||
///
|
||||
/// XXX need to clear memory
|
||||
// XXX later when we do more fancy multiscalar mults, we can delegate
|
||||
// based on the iter's size hint -- hdevalence
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
|
||||
where I: IntoIterator<Item = &'a Scalar>,
|
||||
|
|
@ -550,68 +556,76 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
|
|||
Q
|
||||
}
|
||||
|
||||
/// Precomputation
|
||||
/// A precomputed table of multiples of a basepoint, for accelerating
|
||||
/// fixed-base scalar multiplication. One table, for the Ed25519
|
||||
/// basepoint, is provided in the `constants` module.
|
||||
///
|
||||
/// XXX we should box the internals
|
||||
/// The basepoint tables are reasonably large (30KB), so they should
|
||||
/// probably be boxed.
|
||||
#[derive(Clone)]
|
||||
pub struct EdwardsBasepointTable(pub(crate) [[AffineNielsPoint; 8]; 32]);
|
||||
|
||||
impl EdwardsBasepointTable {
|
||||
/// The computation uses Pippeneger's algorithm, as described on
|
||||
/// page 13 of the Ed25519 paper. Write the scalar \\(a\\) in radix \\(16\\) with
|
||||
/// coefficients in \\([-8,8)\\), i.e.,
|
||||
/// $$
|
||||
/// a = a\_0 + a\_1 16\^1 + \cdots + a\_{63} 16\^{63},
|
||||
/// $$
|
||||
/// with \\(-8 \leq a_i < 8\\). Then
|
||||
/// $$
|
||||
/// a B = a\_0 B + a\_1 16\^1 B + \cdots + a\_{63} 16\^{63} B.
|
||||
/// $$
|
||||
/// Grouping even and odd coefficients gives
|
||||
/// $$
|
||||
/// \begin{aligned}
|
||||
/// a B = \quad a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B \\\\
|
||||
/// + a\_1 16\^1 B +& a\_3 16\^3 B + \cdots + a\_{63} 16\^{63} B \\\\
|
||||
/// = \quad(a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B) \\\\
|
||||
/// + 16(a\_1 16\^0 B +& a\_3 16\^2 B + \cdots + a\_{63} 16\^{62} B). \\\\
|
||||
/// \end{aligned}
|
||||
/// $$
|
||||
/// We then use the `select_precomputed_point` function, which
|
||||
/// takes \\(-8 \leq x < 8\\) and \\([16\^{2i} B, \ldots, 8\cdot16\^{2i} B]\\),
|
||||
/// and returns \\(x \cdot 16\^{2i} \cdot B\\) in constant time.
|
||||
///
|
||||
/// The radix-\\(16\\) representation requires that the scalar is bounded
|
||||
/// by \\(2\^{255}\\), which is always the case.
|
||||
fn basepoint_mul(&self, scalar: &Scalar) -> ExtendedPoint {
|
||||
let a = scalar.to_radix_16();
|
||||
|
||||
let mut P = ExtendedPoint::identity();
|
||||
|
||||
for i in (0..64).filter(|x| x % 2 == 1) {
|
||||
P = (&P + &select_precomputed_point(a[i], &self.0[i/2])).to_extended();
|
||||
}
|
||||
|
||||
P = P.mult_by_pow_2(4);
|
||||
|
||||
for i in (0..64).filter(|x| x % 2 == 0) {
|
||||
P = (&P + &select_precomputed_point(a[i], &self.0[i/2])).to_extended();
|
||||
}
|
||||
|
||||
P
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
/// Construct an `ExtendedPoint` from a `Scalar`, `scalar`, by
|
||||
/// computing the multiple `aB` of the basepoint `B`.
|
||||
///
|
||||
/// Precondition: the scalar must be reduced.
|
||||
///
|
||||
/// The computation proceeds as follows, as described on page 13
|
||||
/// of the Ed25519 paper. Write the scalar `a` in radix 16 with
|
||||
/// coefficients in [-8,8), i.e.,
|
||||
///
|
||||
/// a = a_0 + a_1*16^1 + ... + a_63*16^63,
|
||||
///
|
||||
/// with -8 ≤ a_i < 8. Then
|
||||
///
|
||||
/// a*B = a_0*B + a_1*16^1*B + ... + a_63*16^63*B.
|
||||
///
|
||||
/// Grouping even and odd coefficients gives
|
||||
///
|
||||
/// a*B = a_0*16^0*B + a_2*16^2*B + ... + a_62*16^62*B
|
||||
/// + a_1*16^1*B + a_3*16^3*B + ... + a_63*16^63*B
|
||||
/// = (a_0*16^0*B + a_2*16^2*B + ... + a_62*16^62*B)
|
||||
/// + 16*(a_1*16^0*B + a_3*16^2*B + ... + a_63*16^62*B).
|
||||
///
|
||||
/// We then use the `select_precomputed_point` function, which
|
||||
/// takes `-8 ≤ x < 8` and `[16^2i * B, ..., 8 * 16^2i * B]`,
|
||||
/// and returns `x * 16^2i * B` in constant time.
|
||||
/// Construct an `ExtendedPoint` from a `Scalar` \\(a\\) by
|
||||
/// computing the multiple \\(aB\\) of this basepoint \\(B\\).
|
||||
fn mul(self, scalar: &'b Scalar) -> ExtendedPoint {
|
||||
let e = scalar.to_radix_16();
|
||||
let mut h = ExtendedPoint::identity();
|
||||
let mut t: CompletedPoint;
|
||||
|
||||
for i in (0..64).filter(|x| x % 2 == 1) {
|
||||
t = &h + &select_precomputed_point(e[i], &self.0[i/2]);
|
||||
h = t.to_extended();
|
||||
}
|
||||
|
||||
h = h.mult_by_pow_2(4);
|
||||
|
||||
for i in (0..64).filter(|x| x % 2 == 0) {
|
||||
t = &h + &select_precomputed_point(e[i], &self.0[i/2]);
|
||||
h = t.to_extended();
|
||||
}
|
||||
|
||||
h
|
||||
// delegate to a private function so that its documentation appears in internal docs
|
||||
self.basepoint_mul(scalar)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar {
|
||||
type Output = ExtendedPoint;
|
||||
|
||||
/// Construct an `ExtendedPoint` by via this `Scalar` times
|
||||
/// a the basepoint, `B` included in a precomputed `basepoint_table`.
|
||||
///
|
||||
/// Precondition: this scalar must be reduced.
|
||||
/// Construct an `ExtendedPoint` from a `Scalar` \\(a\\) by
|
||||
/// computing the multiple \\(aB\\) of this basepoint \\(B\\).
|
||||
fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> ExtendedPoint {
|
||||
basepoint_table * &self
|
||||
}
|
||||
|
|
@ -666,13 +680,20 @@ impl ExtendedPoint {
|
|||
|
||||
/// Determine if this point is of small order.
|
||||
///
|
||||
/// The order of the group of points on the curve Ɛ is |Ɛ| = 8q. Thus, to
|
||||
/// check if a point P is of small order, we multiply by 8 and then test
|
||||
/// if the result is equal to the identity.
|
||||
/// The order of the group of points on the curve \\(\mathcal E\\)
|
||||
/// is \\(|\mathcal E| = 8\ell \\), so its structure is \\( \mathcal
|
||||
/// E = \mathcal E[8] \times \mathcal E[\ell]\\). The torsion
|
||||
/// subgroup \\( \mathcal E[8] \\) consists of eight points of small
|
||||
/// order. (Technically all of \\(\mathcal E\\) is torsion, but we
|
||||
/// use the word only to refer to the \\(\mathcal E[8]\\) part, not
|
||||
/// the prime-order subgroup \\(\mathcal E[\ell]\\).
|
||||
///
|
||||
/// For more information on cofactors and the group structure, see
|
||||
/// the internal `curve25519-dalek` documentation on Ristretto.
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// True if it is of small order; false otherwise.
|
||||
/// True if `self` is of small order; false otherwise.
|
||||
pub fn is_small_order(&self) -> bool {
|
||||
self.mult_by_cofactor().is_identity()
|
||||
}
|
||||
|
|
@ -756,13 +777,16 @@ pub mod vartime {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given a vector of public scalars and a vector of (possibly secret)
|
||||
/// points, compute `c_1 P_1 + ... + c_n P_n`.
|
||||
/// Given an iterable of public scalars and an iterable of public
|
||||
/// points, compute
|
||||
/// $$
|
||||
/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
|
||||
/// $$
|
||||
///
|
||||
/// # Input
|
||||
///
|
||||
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
|
||||
/// error to call this function with two vectors of different lengths.
|
||||
/// A iterable of `Scalar`s and a iterable of `ExtendedPoints`. It is an
|
||||
/// error to call this function with two iterators of different lengths.
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
|
||||
where I: IntoIterator<Item = &'a Scalar>,
|
||||
|
|
@ -794,8 +818,8 @@ pub mod vartime {
|
|||
r.to_extended()
|
||||
}
|
||||
|
||||
/// Given a point `A` and scalars `a` and `b`, compute the point
|
||||
/// `aA+bB`, where `B` is the Ed25519 basepoint (i.e., `B = (x,4/5)`
|
||||
/// Given a point \\(A\\) and scalars \\(a\\) and \\(b\\), compute the point
|
||||
/// \\(aA+bB\\), where \\(B\\) is the Ed25519 basepoint (i.e., \\(B = (x,4/5)\\)
|
||||
/// with x positive).
|
||||
#[cfg(feature="precomputed_tables")]
|
||||
pub fn double_scalar_mult_basepoint(a: &Scalar,
|
||||
|
|
|
|||
30
src/field.rs
30
src/field.rs
|
|
@ -8,15 +8,19 @@
|
|||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
|
||||
//! # curve25519-dalek
|
||||
//!
|
||||
//! **A Rust implementation of field and group operations on an Edwards curve
|
||||
//! over GF(2^255 - 19).**
|
||||
//! **A high-performance, pure-Rust implementation of group operations for Ristretto and Curve25519.**
|
||||
//!
|
||||
//! **[SPOILER ALERT]** The Twelfth Doctor's first encounter with the Daleks is
|
||||
//! in his second full episode, "Into the Dalek". A beleaguered ship of the
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! Montgomery arithmetic.
|
||||
//! Group operations for Curve25519, in Montgomery form.
|
||||
//!
|
||||
//! Apart from the compressed point implementation
|
||||
//! (i.e. `CompressedMontgomeryU`), this module is a "clean room" implementation
|
||||
|
|
|
|||
138
src/scalar.rs
138
src/scalar.rs
|
|
@ -10,29 +10,7 @@
|
|||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
// - Brian Smith <brian@briansmith.org>
|
||||
|
||||
//! Arithmetic for scalar multiplication.
|
||||
//!
|
||||
//! Both the Ristretto group and the Ed25519 basepoint have prime order
|
||||
//! \\( \ell = 2\^{252} + 27742317777372353535851937790883648493 \\).
|
||||
//!
|
||||
//! The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which
|
||||
//! represents an element of \\(\mathbb Z / \ell\\).
|
||||
//!
|
||||
//! The code is intended to be useful with both the Ristretto group
|
||||
//! (where everything is done modulo \\( \ell \\), and the X/Ed25519
|
||||
//! setting, which mandates specific bit-twiddles that are not
|
||||
//! well-defined modulo \\( \ell \\).
|
||||
//!
|
||||
//! To create a `Scalar` from a supposedly canonical encoding, use
|
||||
//! `Scalar::from_canonical_bytes`.
|
||||
//!
|
||||
//! To create a `Scalar` by reducing a 256-bit integer mod \\( \ell \\),
|
||||
//! use `Scalar::from_bytes_mod_order`.
|
||||
//!
|
||||
//! To create a `Scalar` with a specific bit-pattern (e.g., for
|
||||
//! compatibility with X25519 "clamping"), use `Scalar::from_bits`.
|
||||
//!
|
||||
//! All arithmetic on `Scalars` is done modulo \\( \ell \\).
|
||||
//! Arithmetic on scalars (integers mod the group order).
|
||||
|
||||
use core::fmt::Debug;
|
||||
use core::ops::Neg;
|
||||
|
|
@ -70,26 +48,46 @@ type UnpackedScalar = backend::u64::scalar::Scalar64;
|
|||
type UnpackedScalar = backend::u32::scalar::Scalar32;
|
||||
|
||||
|
||||
/// The `Scalar` struct represents an element in ℤ/lℤ, where
|
||||
/// The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which
|
||||
/// represents an element of \\(\mathbb Z / \ell\\).
|
||||
///
|
||||
/// l = 2^252 + 27742317777372353535851937790883648493
|
||||
/// Both the Ristretto group and the Ed25519 basepoint have prime order
|
||||
/// \\( \ell = 2\^{252} + 27742317777372353535851937790883648493 \\).
|
||||
///
|
||||
/// is the order of the basepoint. The `Scalar` is stored as bytes.
|
||||
/// The code is intended to be useful with both the Ristretto group
|
||||
/// (where everything is done modulo \\( \ell \\)), and the X/Ed25519
|
||||
/// setting, which mandates specific bit-twiddles that are not
|
||||
/// well-defined modulo \\( \ell \\).
|
||||
///
|
||||
/// To create a `Scalar` from a supposedly canonical encoding, use
|
||||
/// `Scalar::from_canonical_bytes`.
|
||||
///
|
||||
/// To create a `Scalar` by reducing a \\(256\\)-bit integer mod \\( \ell \\),
|
||||
/// use `Scalar::from_bytes_mod_order`.
|
||||
///
|
||||
/// To create a `Scalar` by reducing a \\(512\\)-bit integer mod \\( \ell \\),
|
||||
/// use `Scalar::from_bytes_mod_order_wide`.
|
||||
///
|
||||
/// To create a `Scalar` with a specific bit-pattern (e.g., for
|
||||
/// compatibility with X25519 "clamping"), use `Scalar::from_bits`.
|
||||
///
|
||||
/// All arithmetic on `Scalars` is done modulo \\( \ell \\).
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Scalar {
|
||||
/// `bytes` is a little-endian byte encoding of an integer representing a scalar modulo the group order.
|
||||
///
|
||||
/// # Invariant
|
||||
///
|
||||
/// The integer representing this scalar must be bounded above by 2^255, or equivalently the high bit of `bytes[31]` must be zero.
|
||||
/// The integer representing this scalar must be bounded above by \\(2\^{255}\\), or equivalently the high bit of `bytes[31]` must be zero.
|
||||
///
|
||||
// XXX This is pub(crate) so we can write literal constants. If const fns were stable, we could make the Scalar constructors const fns and use those instead.
|
||||
pub(crate) bytes: [u8; 32],
|
||||
}
|
||||
|
||||
impl Scalar {
|
||||
/// Construct a `Scalar` by reducing a 256-bit integer modulo the group order.
|
||||
pub fn from_bytes_mod_order(bytes: [u8;32]) -> Scalar {
|
||||
/// Construct a `Scalar` by reducing a 256-bit little-endian integer
|
||||
/// modulo the group order \\( \ell \\).
|
||||
pub fn from_bytes_mod_order(bytes: [u8; 32]) -> Scalar {
|
||||
// Temporarily allow s_unreduced.bytes > 2^255 ...
|
||||
let s_unreduced = Scalar{bytes: bytes};
|
||||
|
||||
|
|
@ -100,6 +98,12 @@ impl Scalar {
|
|||
s
|
||||
}
|
||||
|
||||
/// Construct a `Scalar` by reducing a 512-bit little-endian integer
|
||||
/// modulo the group order \\( \ell \\).
|
||||
pub fn from_bytes_mod_order_wide(input: &[u8; 64]) -> Scalar {
|
||||
UnpackedScalar::from_bytes_wide(input).pack()
|
||||
}
|
||||
|
||||
/// Attempt to construct a `Scalar` from a canonical byte representation.
|
||||
///
|
||||
/// # Return
|
||||
|
|
@ -323,7 +327,7 @@ impl Scalar {
|
|||
pub fn random<T: Rng>(rng: &mut T) -> Self {
|
||||
let mut scalar_bytes = [0u8; 64];
|
||||
rng.fill_bytes(&mut scalar_bytes);
|
||||
Scalar::reduce_wide(&scalar_bytes)
|
||||
Scalar::from_bytes_mod_order_wide(&scalar_bytes)
|
||||
}
|
||||
|
||||
/// Hash a slice of bytes into a scalar.
|
||||
|
|
@ -368,7 +372,7 @@ impl Scalar {
|
|||
// XXX this seems clumsy
|
||||
let mut output = [0u8; 64];
|
||||
output.copy_from_slice(hash.result().as_slice());
|
||||
Scalar::reduce_wide(&output)
|
||||
Scalar::from_bytes_mod_order_wide(&output)
|
||||
}
|
||||
|
||||
/// Convert this `Scalar` to its underlying sequence of bytes.
|
||||
|
|
@ -381,12 +385,12 @@ impl Scalar {
|
|||
&self.bytes
|
||||
}
|
||||
|
||||
/// Construct the additive identity
|
||||
/// Construct the scalar \\( 0 \\).
|
||||
pub fn zero() -> Self {
|
||||
Scalar { bytes: [0u8; 32]}
|
||||
}
|
||||
|
||||
/// Construct the multiplicative identity
|
||||
/// Construct the scalar \\( 1 \\).
|
||||
pub fn one() -> Self {
|
||||
Scalar {
|
||||
bytes: [
|
||||
|
|
@ -423,14 +427,17 @@ impl Scalar {
|
|||
|
||||
/// Compute a width-5 "Non-Adjacent Form" of this scalar.
|
||||
///
|
||||
/// A width-`w` NAF of a positive integer `k` is an expression
|
||||
/// `k = sum(k[i]*2^i for i in range(l))`, where each nonzero
|
||||
/// coefficient `k[i]` is odd and bounded by `|k[i]| < 2^(w-1)`,
|
||||
/// `k[l-1]` is nonzero, and at most one of any `w` consecutive
|
||||
/// A width-\\(w\\) NAF of a positive integer \\(k\\) is an expression
|
||||
/// $$
|
||||
/// k = \sum_{i=0}\^n k\_i 2\^i,
|
||||
/// $$
|
||||
/// where each nonzero
|
||||
/// coefficient \\(k\_i\\) is odd and bounded by \\(|k\_i| < 2\^{w-1}\\),
|
||||
/// \\(k\_{n-1}\\) is nonzero, and at most one of any \\(w\\) consecutive
|
||||
/// coefficients is nonzero. (Hankerson, Menezes, Vanstone; def 3.32).
|
||||
///
|
||||
/// Intuitively, this is like a binary expansion, except that we
|
||||
/// allow some coefficients to grow up to `2^(w-1)` so that the
|
||||
/// allow some coefficients to grow up to \\(2\^{w-1}\\) so that the
|
||||
/// nonzero coefficients are as sparse as possible.
|
||||
pub(crate) fn non_adjacent_form(&self) -> [i8; 256] {
|
||||
// Step 1: write out bits of the scalar
|
||||
|
|
@ -468,15 +475,12 @@ impl Scalar {
|
|||
naf
|
||||
}
|
||||
|
||||
/// Write this scalar in radix 16, with coefficients in `[-8,8)`,
|
||||
/// i.e., compute `a_i` such that
|
||||
///
|
||||
/// a = a_0 + a_1*16^1 + ... + a_63*16^63,
|
||||
///
|
||||
/// with `-8 ≤ a_i < 8` for `0 ≤ i < 63` and `-8 ≤ a_63 ≤ 8`.
|
||||
///
|
||||
/// Precondition: self[31] <= 127. This is the case whenever
|
||||
/// `self` is reduced.
|
||||
/// Write this scalar in radix 16, with coefficients in \\([-8,8)\\),
|
||||
/// i.e., compute \\(a\_i\\) such that
|
||||
/// $$
|
||||
/// a = a\_0 + a\_1 16\^1 + \cdots + a_{63} 16\^{63},
|
||||
/// $$
|
||||
/// with \\(-8 \leq a_i < 8\\) for \\(0 \leq i < 63\\) and \\(-8 \leq a_63 \leq 8\\).
|
||||
pub(crate) fn to_radix_16(&self) -> [i8; 64] {
|
||||
debug_assert!(self[31] <= 127);
|
||||
let mut output = [0i8; 64];
|
||||
|
|
@ -506,17 +510,12 @@ impl Scalar {
|
|||
output
|
||||
}
|
||||
|
||||
/// Unpack this `Scalar` to an `UnpackedScalar`
|
||||
/// Unpack this `Scalar` to an `UnpackedScalar` for faster arithmetic.
|
||||
pub(crate) fn unpack(&self) -> UnpackedScalar {
|
||||
UnpackedScalar::from_bytes(&self.bytes)
|
||||
}
|
||||
|
||||
/// Compute `(a * b) + c` (mod l).
|
||||
pub fn multiply_add(a: &Scalar, b: &Scalar, c: &Scalar) -> Scalar {
|
||||
UnpackedScalar::add(&UnpackedScalar::mul(&a.unpack(), &b.unpack()), &c.unpack()).pack()
|
||||
}
|
||||
|
||||
/// Reduce this `Scalar` mod l.
|
||||
/// Reduce this `Scalar` modulo \\(\ell\\).
|
||||
pub fn reduce(&self) -> Scalar {
|
||||
let x = self.unpack();
|
||||
let xR = UnpackedScalar::mul_internal(&x, &constants::R);
|
||||
|
|
@ -545,11 +544,6 @@ impl Scalar {
|
|||
pub fn is_canonical(&self) -> bool {
|
||||
*self == self.reduce()
|
||||
}
|
||||
|
||||
/// Reduce a 512-bit little endian number mod l
|
||||
pub fn reduce_wide(input: &[u8; 64]) -> Scalar {
|
||||
UnpackedScalar::from_bytes_wide(input).pack()
|
||||
}
|
||||
}
|
||||
|
||||
impl UnpackedScalar {
|
||||
|
|
@ -726,11 +720,11 @@ mod test {
|
|||
|
||||
// also_a = (a mod l)
|
||||
tmp[0..32].copy_from_slice(&a_bytes[..]);
|
||||
let also_a = Scalar::reduce_wide(&tmp);
|
||||
let also_a = Scalar::from_bytes_mod_order_wide(&tmp);
|
||||
|
||||
// also_b = (b mod l)
|
||||
tmp[0..32].copy_from_slice(&b_bytes[..]);
|
||||
let also_b = Scalar::reduce_wide(&tmp);
|
||||
let also_b = Scalar::from_bytes_mod_order_wide(&tmp);
|
||||
|
||||
let expected_c = &a * &b;
|
||||
let also_expected_c = &also_a * &also_b;
|
||||
|
|
@ -763,9 +757,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn scalar_multiply_by_one() {
|
||||
let one = Scalar::one();
|
||||
let zero = Scalar::zero();
|
||||
let test_scalar = Scalar::multiply_add(&X, &one, &zero);
|
||||
let test_scalar = &X * &Scalar::one();
|
||||
for i in 0..32 {
|
||||
assert!(test_scalar[i] == X[i]);
|
||||
}
|
||||
|
|
@ -792,17 +784,9 @@ mod test {
|
|||
assert_eq!(should_be_X_times_Y, X_TIMES_Y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scalar_multiply_add() {
|
||||
let test_scalar = Scalar::multiply_add(&X, &Y, &Z);
|
||||
for i in 0..32 {
|
||||
assert!(test_scalar[i] == W[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn square() {
|
||||
let expected = Scalar::multiply_add(&X, &X, &Scalar::zero());
|
||||
let expected = &X * &X;
|
||||
let actual = X.unpack().square().pack();
|
||||
for i in 0..32 {
|
||||
assert!(expected[i] == actual[i]);
|
||||
|
|
@ -816,7 +800,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn reduce_wide() {
|
||||
fn from_bytes_mod_order_wide() {
|
||||
let mut bignum = [0u8; 64];
|
||||
// set bignum = x + 2^256x
|
||||
for i in 0..32 {
|
||||
|
|
@ -833,7 +817,7 @@ mod test {
|
|||
28, 82, 31, 197, 100, 165, 192, 8,
|
||||
],
|
||||
};
|
||||
let test_red = Scalar::reduce_wide(&bignum);
|
||||
let test_red = Scalar::from_bytes_mod_order_wide(&bignum);
|
||||
for i in 0..32 {
|
||||
assert!(test_red[i] == reduced[i]);
|
||||
}
|
||||
|
|
@ -868,7 +852,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn montgomery_reduce_matches_reduce_wide() {
|
||||
fn montgomery_reduce_matches_from_bytes_mod_order_wide() {
|
||||
let mut bignum = [0u8; 64];
|
||||
|
||||
// set bignum = x + 2^256x
|
||||
|
|
@ -886,7 +870,7 @@ mod test {
|
|||
28, 82, 31, 197, 100, 165, 192, 8
|
||||
],
|
||||
};
|
||||
let reduced = Scalar::reduce_wide(&bignum);
|
||||
let reduced = Scalar::from_bytes_mod_order_wide(&bignum);
|
||||
|
||||
// The reduced scalar should match the expected
|
||||
assert_eq!(reduced.bytes, expected.bytes);
|
||||
|
|
|
|||
Loading…
Reference in a new issue