Merge branch 'feature/texify-formulas' into develop

This commit is contained in:
Henry de Valence 2017-12-01 11:54:12 -08:00
commit fce10f5736
15 changed files with 403 additions and 313 deletions

View file

@ -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

View file

@ -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;

View file

@ -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]);

View file

@ -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;

View file

@ -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;

View file

@ -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]);

View file

@ -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;

View file

@ -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]);

View file

@ -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

View file

@ -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;

View file

@ -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,

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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);