Merge remote-tracking branch 'hdevalence/feature/refactor-internal-code' into develop

This commit is contained in:
Isis Lovecruft 2017-11-25 23:07:23 +00:00
commit 6e96e49eea
Failed to extract signature
21 changed files with 809 additions and 666 deletions

View file

@ -27,9 +27,6 @@ travis-ci = { repository = "isislovecruft/curve25519-dalek", branch = "master"}
version = "1.0"
optional = true
[dependencies.arrayref]
version = "0.3.4"
[dependencies.rand]
optional = true
version = "0.3"

View file

@ -1,3 +1,3 @@
doc:
cargo rustdoc --features "nightly yolocrypto" -- --html-in-header katex-header.html
cargo rustdoc --features "nightly yolocrypto" -- --html-in-header rustdoc-include-katex-header.html

View file

@ -8,8 +8,6 @@ extern crate subtle;
extern crate rand;
extern crate digest;
extern crate generic_array;
#[macro_use]
extern crate arrayref;
use std::env;
use std::fs::File;
@ -24,39 +22,29 @@ use std::path::Path;
#[cfg(feature = "serde")]
extern crate serde;
#[path="src/field.rs"]
mod field;
#[cfg(not(feature="radix_51"))]
#[path="src/field_32bit.rs"]
mod field_32bit;
#[cfg(feature="radix_51")]
#[path="src/field_64bit.rs"]
mod field_64bit;
// Public modules
#[path="src/scalar.rs"]
mod scalar;
#[cfg(not(feature="radix_51"))]
#[path="src/scalar_32bit.rs"]
mod scalar_32bit;
#[cfg(feature="radix_51")]
#[path="src/scalar_64bit.rs"]
mod scalar_64bit;
#[path="src/montgomery.rs"]
mod montgomery;
#[path="src/edwards.rs"]
mod edwards;
#[path="src/ristretto.rs"]
mod ristretto;
#[path="src/constants.rs"]
mod constants;
#[cfg(not(feature="radix_51"))]
#[path="src/constants_32bit.rs"]
mod constants_32bit;
#[cfg(feature="radix_51")]
#[path="src/constants_64bit.rs"]
mod constants_64bit;
#[path="src/traits.rs"]
mod traits;
// Internal modules
#[path="src/field.rs"]
mod field;
#[path="src/curve_models/mod.rs"]
mod curve_models;
#[path="src/backend/mod.rs"]
mod backend;
use edwards::EdwardsBasepointTable;
@ -73,14 +61,15 @@ fn main() {
f.write_all(format!("\n
#[cfg(feature=\"radix_51\")]
use field_64bit::FieldElement64;
use backend::u64::field::FieldElement64;
#[cfg(not(feature=\"radix_51\"))]
use field_32bit::FieldElement32;
use backend::u32::field::FieldElement32;
use edwards::AffineNielsPoint;
use edwards::EdwardsBasepointTable;
use curve_models::AffineNielsPoint;
/// Table containing precomputed multiples of the basepoint `B = (x,4/5)`.
///
/// The table is defined so `constants::base[i][j-1] = j*(16^2i)*B`,

32
src/backend/mod.rs Normal file
View file

@ -0,0 +1,32 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! This module contains "backends" that contain different
//! implementations of common code for different architectures.
//!
//! The naming of the `u32` and `u64` modules is somewhat unfortunate,
//! since these are also the names of primitive types. Since types have
//! a different namespace than modules, this isn't a problem to the
//! compiler, but it could cause confusion.
//!
//! However, it's unlikely that the names of those modules would be
//! brought into scope directly, instead of used as
//! `backend::u32::field` or similar. Unfortunately we can't use
//! `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

@ -12,8 +12,8 @@
//! and useful field elements like `sqrt(-1)`), as well as
//! lookup tables of pre-computed points.
use field_32bit::FieldElement32;
use scalar_32bit::Scalar32;
use backend::u32::field::FieldElement32;
use backend::u32::scalar::Scalar32;
use edwards::ExtendedPoint;
/// Edwards `d` value, equal to `-121665/121666 mod p`.

15
src/backend/u32/mod.rs Normal file
View file

@ -0,0 +1,15 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
pub mod field;
pub mod scalar;
pub mod constants;

View file

@ -12,8 +12,8 @@
//! and useful field elements like `sqrt(-1)`), as well as
//! lookup tables of pre-computed points.
use field_64bit::FieldElement64;
use scalar_64bit::Scalar64;
use backend::u64::field::FieldElement64;
use backend::u64::scalar::Scalar64;
use edwards::ExtendedPoint;
/// Edwards `d` value, equal to `-121665/121666 mod p`.

View file

@ -25,10 +25,6 @@ use core::ops::Neg;
use subtle::ConditionallyAssignable;
/// In the 64-bit implementation, field elements are represented in
/// radix 2^51 as five `u64`s.
pub type Limb = u64;
/// A `FieldElement64` represents an element of the field GF(2^255 - 19).
///
/// In the 64-bit implementation, a `FieldElement` is represented in

15
src/backend/u64/mod.rs Normal file
View file

@ -0,0 +1,15 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
pub mod field;
pub mod scalar;
pub mod constants;

View file

@ -18,7 +18,7 @@
//!
//! ```
//! use curve25519_dalek::constants;
//! use curve25519_dalek::edwards::IsIdentity;
//! use curve25519_dalek::traits::IsIdentity;
//!
//! let B = &constants::RISTRETTO_BASEPOINT_TABLE;
//! let l = &constants::BASEPOINT_ORDER;
@ -36,9 +36,9 @@ use montgomery::CompressedMontgomeryU;
use scalar::Scalar;
#[cfg(feature="radix_51")]
pub use constants_64bit::*;
pub use backend::u64::constants::*;
#[cfg(not(feature="radix_51"))]
pub use constants_32bit::*;
pub use backend::u32::constants::*;
/// Basepoint has y = 4/5.
///
@ -102,8 +102,7 @@ pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable
#[cfg(test)]
mod test {
use field::FieldElement;
use edwards::IsIdentity;
use edwards::ValidityCheck;
use traits::{IsIdentity, ValidityCheck};
use constants;
#[test]
@ -138,7 +137,7 @@ mod test {
#[test]
#[cfg(feature="radix_51")]
fn sqrt_minus_aplus2() {
use field_64bit::FieldElement64;
use backend::u64::field::FieldElement64;
let minus_aplus2 = -&FieldElement64([486664,0,0,0,0]);
let sqrt = constants::SQRT_MINUS_APLUS2;
let sq = &sqrt * &sqrt;
@ -150,7 +149,7 @@ mod test {
#[test]
#[cfg(not(feature="radix_51"))]
fn sqrt_minus_aplus2() {
use field_32bit::FieldElement32;
use backend::u32::field::FieldElement32;
let minus_aplus2 = -&FieldElement32([486664,0,0,0,0,0,0,0,0,0]);
let sqrt = constants::SQRT_MINUS_APLUS2;
let sq = &sqrt * &sqrt;
@ -180,7 +179,7 @@ mod test {
#[cfg(not(feature="radix_51"))]
#[test]
fn test_d_vs_ratio() {
use field_32bit::FieldElement32;
use backend::u32::field::FieldElement32;
let a = -&FieldElement32([121665,0,0,0,0,0,0,0,0,0]);
let b = FieldElement32([121666,0,0,0,0,0,0,0,0,0]);
let d = &a * &b.invert();
@ -193,7 +192,7 @@ mod test {
#[cfg(feature="radix_51")]
#[test]
fn test_d_vs_ratio() {
use field_64bit::FieldElement64;
use backend::u64::field::FieldElement64;
let a = -&FieldElement64([121665,0,0,0,0]);
let b = FieldElement64([121666,0,0,0,0]);
let d = &a * &b.invert();

431
src/curve_models/mod.rs Normal file
View file

@ -0,0 +1,431 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! This module contains internal curve representations which are not part
//! of the public API.
//!
//! # Curve representations
//!
//! 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.
//!
//! Begin with the affine equation for the curve,
//!
//! -x² + y² = 1 + dx²y². <span style="float: right">(1)</span>
//!
//! Next, pass to the projective closure 𝗣^1 x 𝗣^1 by setting x=X/Z,
//! y=Y/T. Clearing denominators gives the model
//!
//! -X²T² + Y²Z² = Z²T² + dX²Y².<span style="float: right">(2)<span>
//!
//! To map from 𝗣^1 x 𝗣^1, a product of two lines, to 𝗣^3, we use the
//! Segre embedding,
//!
//! σ : ((X:Z),(Y:T)) ↦ (XY:XT:ZY:ZT). <span style="float: right">(3)</span>
//!
//! 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
//!
//! -W₁² + W₂² = W₃² + dW₀². <span style="float: right">(4)</span>
//!
//! 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
#![allow(non_snake_case)]
use core::fmt::Debug;
use core::ops::{Add, Sub, Neg};
use constants;
use field::FieldElement;
use edwards::ExtendedPoint;
use subtle::ConditionallyAssignable;
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).
#[derive(Copy, Clone)]
pub struct ProjectivePoint {
pub X: FieldElement,
pub Y: FieldElement,
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)).
#[derive(Copy, Clone)]
#[allow(missing_docs)]
pub struct CompletedPoint {
pub X: FieldElement,
pub Y: FieldElement,
pub Z: FieldElement,
pub T: FieldElement,
}
/// 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).
// Safe to derive Eq because affine coordinates.
#[derive(Copy, Clone, Eq, PartialEq)]
#[allow(missing_docs)]
pub struct AffineNielsPoint {
pub y_plus_x: FieldElement,
pub y_minus_x: FieldElement,
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).
#[derive(Copy, Clone)]
pub struct ProjectiveNielsPoint {
pub Y_plus_X: FieldElement,
pub Y_minus_X: FieldElement,
pub Z: FieldElement,
pub T2d: FieldElement,
}
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
use traits::Identity;
impl Identity for ProjectivePoint {
fn identity() -> ProjectivePoint {
ProjectivePoint{
X: FieldElement::zero(),
Y: FieldElement::one(),
Z: FieldElement::one(),
}
}
}
impl Identity for ProjectiveNielsPoint {
fn identity() -> ProjectiveNielsPoint {
ProjectiveNielsPoint{
Y_plus_X: FieldElement::one(),
Y_minus_X: FieldElement::one(),
Z: FieldElement::one(),
T2d: FieldElement::zero(),
}
}
}
impl Identity for AffineNielsPoint {
fn identity() -> AffineNielsPoint {
AffineNielsPoint{
y_plus_x: FieldElement::one(),
y_minus_x: FieldElement::one(),
xy2d: FieldElement::zero(),
}
}
}
// ------------------------------------------------------------------------
// Validity checks (for debugging, not CT)
// ------------------------------------------------------------------------
impl ValidityCheck for ProjectivePoint {
fn is_valid(&self) -> bool {
// Curve equation is -x^2 + y^2 = 1 + d*x^2*y^2,
// homogenized as (-X^2 + Y^2)*Z^2 = Z^4 + d*X^2*Y^2
let XX = self.X.square();
let YY = self.Y.square();
let ZZ = self.Z.square();
let ZZZZ = ZZ.square();
let lhs = &(&YY - &XX) * &ZZ;
let rhs = &ZZZZ + &(&constants::EDWARDS_D * &(&XX * &YY));
lhs == rhs
}
}
// ------------------------------------------------------------------------
// Constant-time assignment
// ------------------------------------------------------------------------
impl ConditionallyAssignable for ProjectiveNielsPoint {
fn conditional_assign(&mut self, other: &ProjectiveNielsPoint, choice: u8) {
self.Y_plus_X.conditional_assign(&other.Y_plus_X, choice);
self.Y_minus_X.conditional_assign(&other.Y_minus_X, choice);
self.Z.conditional_assign(&other.Z, choice);
self.T2d.conditional_assign(&other.T2d, choice);
}
}
impl ConditionallyAssignable for AffineNielsPoint {
fn conditional_assign(&mut self, other: &AffineNielsPoint, choice: u8) {
// PreComputedGroupElementCMove()
self.y_plus_x.conditional_assign(&other.y_plus_x, choice);
self.y_minus_x.conditional_assign(&other.y_minus_x, choice);
self.xy2d.conditional_assign(&other.xy2d, choice);
}
}
// ------------------------------------------------------------------------
// Point conversions
// ------------------------------------------------------------------------
impl ProjectivePoint {
/// Convert to the extended twisted Edwards representation of this
/// point.
///
/// 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).
pub fn to_extended(&self) -> ExtendedPoint {
ExtendedPoint{
X: &self.X * &self.Z,
Y: &self.Y * &self.Z,
Z: self.Z.square(),
T: &self.X * &self.Y,
}
}
}
impl CompletedPoint {
/// Convert to a ProjectivePoint
pub fn to_projective(&self) -> ProjectivePoint {
ProjectivePoint{
X: &self.X * &self.T,
Y: &self.Y * &self.Z,
Z: &self.Z * &self.T,
}
}
/// Convert to an ExtendedPoint
pub fn to_extended(&self) -> ExtendedPoint {
ExtendedPoint{
X: &self.X * &self.T,
Y: &self.Y * &self.Z,
Z: &self.Z * &self.T,
T: &self.X * &self.Y,
}
}
}
// ------------------------------------------------------------------------
// Doubling
// ------------------------------------------------------------------------
impl ProjectivePoint {
/// Double this point: return self + self
pub fn double(&self) -> CompletedPoint { // Double()
let XX = self.X.square();
let YY = self.Y.square();
let ZZ2 = self.Z.square2();
let X_plus_Y = &self.X + &self.Y;
let X_plus_Y_sq = X_plus_Y.square();
let YY_plus_XX = &YY + &XX;
let YY_minus_XX = &YY - &XX;
CompletedPoint{
X: &X_plus_Y_sq - &YY_plus_XX,
Y: YY_plus_XX,
Z: YY_minus_XX,
T: &ZZ2 - &YY_minus_XX
}
}
}
// ------------------------------------------------------------------------
// Addition and Subtraction
// ------------------------------------------------------------------------
// These are doc(hidden) so they don't appear in the public API docs.
#[doc(hidden)]
impl<'a, 'b> Add<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint;
fn add(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint {
let Y_plus_X = &self.Y + &self.X;
let Y_minus_X = &self.Y - &self.X;
let PP = &Y_plus_X * &other.Y_plus_X;
let MM = &Y_minus_X * &other.Y_minus_X;
let TT2d = &self.T * &other.T2d;
let ZZ = &self.Z * &other.Z;
let ZZ2 = &ZZ + &ZZ;
CompletedPoint{
X: &PP - &MM,
Y: &PP + &MM,
Z: &ZZ2 + &TT2d,
T: &ZZ2 - &TT2d
}
}
}
#[doc(hidden)]
impl<'a, 'b> Sub<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint;
fn sub(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint {
let Y_plus_X = &self.Y + &self.X;
let Y_minus_X = &self.Y - &self.X;
let PM = &Y_plus_X * &other.Y_minus_X;
let MP = &Y_minus_X * &other.Y_plus_X;
let TT2d = &self.T * &other.T2d;
let ZZ = &self.Z * &other.Z;
let ZZ2 = &ZZ + &ZZ;
CompletedPoint{
X: &PM - &MP,
Y: &PM + &MP,
Z: &ZZ2 - &TT2d,
T: &ZZ2 + &TT2d
}
}
}
#[doc(hidden)]
impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint;
fn add(self, other: &'b AffineNielsPoint) -> CompletedPoint {
let Y_plus_X = &self.Y + &self.X;
let Y_minus_X = &self.Y - &self.X;
let PP = &Y_plus_X * &other.y_plus_x;
let MM = &Y_minus_X * &other.y_minus_x;
let Txy2d = &self.T * &other.xy2d;
let Z2 = &self.Z + &self.Z;
CompletedPoint{
X: &PP - &MM,
Y: &PP + &MM,
Z: &Z2 + &Txy2d,
T: &Z2 - &Txy2d
}
}
}
#[doc(hidden)]
impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint;
fn sub(self, other: &'b AffineNielsPoint) -> CompletedPoint {
let Y_plus_X = &self.Y + &self.X;
let Y_minus_X = &self.Y - &self.X;
let PM = &Y_plus_X * &other.y_minus_x;
let MP = &Y_minus_X * &other.y_plus_x;
let Txy2d = &self.T * &other.xy2d;
let Z2 = &self.Z + &self.Z;
CompletedPoint{
X: &PM - &MP,
Y: &PM + &MP,
Z: &Z2 - &Txy2d,
T: &Z2 + &Txy2d
}
}
}
// ------------------------------------------------------------------------
// Negation
// ------------------------------------------------------------------------
impl<'a> Neg for &'a ProjectiveNielsPoint {
type Output = ProjectiveNielsPoint;
fn neg(self) -> ProjectiveNielsPoint {
ProjectiveNielsPoint{
Y_plus_X: self.Y_minus_X,
Y_minus_X: self.Y_plus_X,
Z: self.Z,
T2d: -(&self.T2d),
}
}
}
impl<'a> Neg for &'a AffineNielsPoint {
type Output = AffineNielsPoint;
fn neg(self) -> AffineNielsPoint {
AffineNielsPoint{
y_plus_x: self.y_minus_x,
y_minus_x: self.y_plus_x,
xy2d: -(&self.xy2d)
}
}
}
// ------------------------------------------------------------------------
// Debug traits
// ------------------------------------------------------------------------
impl Debug for ProjectivePoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "ProjectivePoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?}\n}}",
&self.X, &self.Y, &self.Z)
}
}
impl Debug for CompletedPoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "CompletedPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}",
&self.X, &self.Y, &self.Z, &self.T)
}
}
impl Debug for AffineNielsPoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "AffineNielsPoint{{\n\ty_plus_x: {:?},\n\ty_minus_x: {:?},\n\txy2d: {:?}\n}}",
&self.y_plus_x, &self.y_minus_x, &self.xy2d)
}
}
impl Debug for ProjectiveNielsPoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "ProjectiveNielsPoint{{\n\tY_plus_X: {:?},\n\tY_minus_X: {:?},\n\tZ: {:?},\n\tT2d: {:?}\n}}",
&self.Y_plus_X, &self.Y_minus_X, &self.Z, &self.T2d)
}
}

View file

@ -8,67 +8,7 @@
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Group operations for Curve25519, in the form of the twisted
//! Edwards curve -x²+y²=1+dx²y² modulo p=2²⁵⁵-19 with
//! parameter d=-121665/121666.
//!
//! # Curve representations
//!
//! 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.
//!
//! Begin with the affine equation for the curve,
//!
//! -x² + y² = 1 + dx²y². <span style="float: right">(1)</span>
//!
//! Next, pass to the projective closure 𝗣^1 x 𝗣^1 by setting x=X/Z,
//! y=Y/T. Clearing denominators gives the model
//!
//! -X²T² + Y²Z² = Z²T² + dX²Y².<span style="float: right">(2)<span>
//!
//! To map from 𝗣^1 x 𝗣^1, a product of two lines, to 𝗣^3, we use the
//! Segre embedding,
//!
//! σ : ((X:Z),(Y:T)) ↦ (XY:XT:ZY:ZT). <span style="float: right">(3)</span>
//!
//! 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
//!
//! -W₁² + W₂² = W₃² + dW₀². <span style="float: right">(4)</span>
//!
//! 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
//! Group operations for Curve25519, in Edwards form.
// We allow non snake_case names because coordinates in projective space are
// traditionally denoted by the capitalisation of their respective
@ -86,17 +26,28 @@ use core::ops::{AddAssign, SubAssign};
use core::ops::{Mul, MulAssign};
use core::ops::Index;
use constants;
use field::FieldElement;
use scalar::Scalar;
use montgomery::MontgomeryPoint;
use subtle::slices_equal;
use subtle::bytes_equal;
use subtle::ConditionallyAssignable;
use subtle::ConditionallyNegatable;
// XXX subtle::Equal
use subtle::Equal;
use constants;
use field::FieldElement;
use scalar::Scalar;
use montgomery::MontgomeryPoint;
use curve_models::ProjectivePoint;
use curve_models::CompletedPoint;
use curve_models::AffineNielsPoint;
use curve_models::ProjectiveNielsPoint;
use traits::{Identity, IsIdentity};
use traits::ValidityCheck;
use traits::select_precomputed_point;
// ------------------------------------------------------------------------
// Compressed points
// ------------------------------------------------------------------------
@ -190,8 +141,9 @@ impl<'de> Deserialize<'de> for ExtendedPoint {
where E: serde::de::Error
{
if v.len() == 32 {
let arr32 = array_ref!(v, 0, 32); // &[u8;32] from &[u8]
CompressedEdwardsY(*arr32)
let mut arr32 = [0u8; 32];
arr32[0..32].copy_from_slice(v);
CompressedEdwardsY(arr32)
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
} else {
@ -210,74 +162,19 @@ impl<'de> Deserialize<'de> for ExtendedPoint {
/// An `ExtendedPoint` is a point on the curve in 𝗣³(𝔽ₚ).
/// A point (x,y) in the affine model corresponds to (x:y:1:xy).
// XXX members should not be public, but that's needed for the
// constants module. Fix when RFC #1422 lands:
// https://github.com/rust-lang/rust/issues/32409
#[derive(Copy, Clone)]
#[allow(missing_docs)]
pub struct ExtendedPoint {
pub X: FieldElement,
pub Y: FieldElement,
pub Z: FieldElement,
pub T: FieldElement,
}
/// A `ProjectivePoint` is a point on the curve in 𝗣²(𝔽ₚ).
/// A point (x,y) in the affine model corresponds to (x:y:1).
#[derive(Copy, Clone)]
pub struct ProjectivePoint {
X: FieldElement,
Y: FieldElement,
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)).
#[derive(Copy, Clone)]
#[allow(missing_docs)]
pub struct CompletedPoint {
pub X: FieldElement,
pub Y: FieldElement,
pub Z: FieldElement,
pub T: FieldElement,
}
/// 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).
// Safe to derive Eq because affine coordinates.
#[derive(Copy, Clone, Eq, PartialEq)]
#[allow(missing_docs)]
pub struct AffineNielsPoint {
pub y_plus_x: FieldElement,
pub y_minus_x: FieldElement,
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).
#[derive(Copy, Clone)]
pub struct ProjectiveNielsPoint {
Y_plus_X: FieldElement,
Y_minus_X: FieldElement,
Z: FieldElement,
T2d: FieldElement,
pub(crate) X: FieldElement,
pub(crate) Y: FieldElement,
pub(crate) Z: FieldElement,
pub(crate) T: FieldElement,
}
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/// Trait for curve point types which have an identity constructor.
pub trait Identity {
/// Returns the identity element of the curve.
/// Can be used as a constructor.
fn identity() -> Self;
}
impl Identity for CompressedEdwardsY {
fn identity() -> CompressedEdwardsY {
CompressedEdwardsY([1, 0, 0, 0, 0, 0, 0, 0,
@ -296,58 +193,10 @@ impl Identity for ExtendedPoint {
}
}
impl Identity for ProjectivePoint {
fn identity() -> ProjectivePoint {
ProjectivePoint{ X: FieldElement::zero(),
Y: FieldElement::one(),
Z: FieldElement::one() }
}
}
impl Identity for ProjectiveNielsPoint {
fn identity() -> ProjectiveNielsPoint {
ProjectiveNielsPoint{ Y_plus_X: FieldElement::one(),
Y_minus_X: FieldElement::one(),
Z: FieldElement::one(),
T2d: FieldElement::zero() }
}
}
impl Identity for AffineNielsPoint {
fn identity() -> AffineNielsPoint {
AffineNielsPoint{
y_plus_x: FieldElement::one(),
y_minus_x: FieldElement::one(),
xy2d: FieldElement::zero(),
}
}
}
// ------------------------------------------------------------------------
// Validity checks (for debugging, not CT)
// ------------------------------------------------------------------------
/// Trait for checking whether a point is on the curve
pub trait ValidityCheck {
/// Checks whether the point is on the curve. Not CT.
fn is_valid(&self) -> bool;
}
impl ValidityCheck for ProjectivePoint {
fn is_valid(&self) -> bool {
// Curve equation is -x^2 + y^2 = 1 + d*x^2*y^2,
// homogenized as (-X^2 + Y^2)*Z^2 = Z^4 + d*X^2*Y^2
let XX = self.X.square();
let YY = self.Y.square();
let ZZ = self.Z.square();
let ZZZZ = ZZ.square();
let lhs = &(&YY - &XX) * &ZZ;
let rhs = &ZZZZ + &(&constants::EDWARDS_D * &(&XX * &YY));
lhs == rhs
}
}
impl ValidityCheck for ExtendedPoint {
// XXX this should also check that T is correct
fn is_valid(&self) -> bool {
@ -359,24 +208,6 @@ impl ValidityCheck for ExtendedPoint {
// Constant-time assignment
// ------------------------------------------------------------------------
impl ConditionallyAssignable for ProjectiveNielsPoint {
fn conditional_assign(&mut self, other: &ProjectiveNielsPoint, choice: u8) {
self.Y_plus_X.conditional_assign(&other.Y_plus_X, choice);
self.Y_minus_X.conditional_assign(&other.Y_minus_X, choice);
self.Z.conditional_assign(&other.Z, choice);
self.T2d.conditional_assign(&other.T2d, choice);
}
}
impl ConditionallyAssignable for AffineNielsPoint {
fn conditional_assign(&mut self, other: &AffineNielsPoint, choice: u8) {
// PreComputedGroupElementCMove()
self.y_plus_x.conditional_assign(&other.y_plus_x, choice);
self.y_minus_x.conditional_assign(&other.y_minus_x, choice);
self.xy2d.conditional_assign(&other.xy2d, choice);
}
}
impl ConditionallyAssignable for ExtendedPoint {
fn conditional_assign(&mut self, other: &ExtendedPoint, choice: u8) {
self.X.conditional_assign(&other.X, choice);
@ -397,123 +228,13 @@ impl Equal for ExtendedPoint {
}
}
/// Trait for testing if a curve point is equivalent to the identity point.
pub trait IsIdentity {
/// Return true if this element is the identity element of the curve.
fn is_identity(&self) -> bool;
}
/// Implement generic identity equality testing for a point representations
/// which have constant-time equality testing and a defined identity
/// constructor.
impl<T> IsIdentity for T where T: Equal + Identity {
fn is_identity(&self) -> bool {
self.ct_eq(&T::identity()) == 1u8
}
}
// ------------------------------------------------------------------------
// Point conversions
// ------------------------------------------------------------------------
impl ProjectivePoint {
/// Convert to the extended twisted Edwards representation of this
/// point.
///
/// 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).
pub fn to_extended(&self) -> ExtendedPoint {
ExtendedPoint{
X: &self.X * &self.Z,
Y: &self.Y * &self.Z,
Z: self.Z.square(),
T: &self.X * &self.Y,
}
}
/// Convert this point to a `CompressedEdwardsY`
pub fn compress(&self) -> CompressedEdwardsY {
let recip = self.Z.invert();
let x = &self.X * &recip;
let y = &self.Y * &recip;
let mut s: [u8; 32];
s = y.to_bytes();
s[31] ^= (x.is_negative() << 7) as u8;
CompressedEdwardsY(s)
}
/// Convert this projective point in the Edwards model to its equivalent
/// projective point on the Montgomery form of the curve.
///
/// Taking the Montgomery curve equation in affine coordinates:
///
/// E_(A,B) = Bv² = u³ + Au² + u <span style="float: right">(1)</span>
///
/// and given its relations to the coordinates of the Edwards model:
///
/// u = (1+y)/(1-y) <span style="float: right">(2)</span>
/// v = (λu)/(x)
///
/// Converting from affine to projective coordinates in the Montgomery
/// model, we arrive at:
///
/// u = (Z+Y)/(Z-Y) <span style="float: right">(3)</span>
/// v = λ * ((Z+Y)/(Z-Y)) * (Z/X)
///
/// The transition between affine and projective is given by
///
/// u → U/W <span style="float: right">(4)</span>
/// v → V/W
///
/// thus the Montgomery curve equation (1) becomes
///
/// E_(A,B) : BV²W = U³ + AU²W + UW² ⊆ 𝗣^2 <span style="float: right">(5)</span>
///
/// Here, again, to differentiate from points in the twisted Edwards model, we
/// call the point `(x,y)` in affine coordinates `(u,v)` and similarly in projective
/// space we use `(U:V:W)`. However, since (as per Montgomery's original work) the
/// v-coordinate is superfluous to the definition of the group law, we merely
/// use `(U:W)`.
///
/// Therefore, the direct translation between projective Montgomery points
/// and projective twisted Edwards points is
///
/// (U:W) = (Z+Y:Z-Y) <span style="float: right">(6)</span>
///
/// Note, however, that there appears to be an exception where `Z=Y`,
/// since—from equation 2—this would imply that `y=1` (thus causing the
/// denominator to be zero). If this is the case, then it follows from the
/// twisted Edwards curve equation
///
/// -x² + y² = 1 + dx²y² <span style="float: right">(7)</span>
///
/// that
///
/// -x² + 1 = 1 + dx²
///
/// and, assuming that `d ≠ -1`,
///
/// -x² = x²
/// x = 0
///
/// Therefore, the only valid point with `y=1` is the twisted Edwards
/// identity point, which correctly becomes `(1:0)`, that is, the identity,
/// in the Montgomery model.
pub fn to_montgomery(&self) -> MontgomeryPoint {
MontgomeryPoint{
U: &self.Z + &self.Y,
W: &self.Z - &self.Y,
}
}
}
impl ExtendedPoint {
/// Convert to a ProjectiveNielsPoint
pub fn to_projective_niels(&self) -> ProjectiveNielsPoint {
pub(crate) fn to_projective_niels(&self) -> ProjectiveNielsPoint {
ProjectiveNielsPoint{
Y_plus_X: &self.Y + &self.X,
Y_minus_X: &self.Y - &self.X,
@ -527,7 +248,7 @@ impl ExtendedPoint {
///
/// Given a point in Ɛₑ, we can convert to projective coordinates
/// cost-free by simply ignoring T.
fn to_projective(&self) -> ProjectivePoint {
pub(crate) fn to_projective(&self) -> ProjectivePoint {
ProjectivePoint{
X: self.X,
Y: self.Y,
@ -537,7 +258,7 @@ impl ExtendedPoint {
/// Dehomogenize to a AffineNielsPoint.
/// Mainly for testing.
pub fn to_affine_niels(&self) -> AffineNielsPoint {
pub(crate) fn to_affine_niels(&self) -> AffineNielsPoint {
let recip = self.Z.invert();
let x = &self.X * &recip;
let y = &self.Y * &recip;
@ -549,36 +270,88 @@ impl ExtendedPoint {
}
}
/// Convert this point to its equivalent on the Montgomery form of the
/// curve.
/// Convert this `ExtendedPoint` on the Edwards model to the
/// corresponding `MontgomeryPoint` on the Montgomery model.
///
/// Note that this is a one-way conversion, since the Montgomery
/// model does not retain sign information.
///
// XXX need to figure out how to keep this in internal docs, and
// also to rewrite it to use tex
//
// # Implementation notes
//
// Taking the Montgomery curve equation in affine coordinates:
//
// E_(A,B) = Bv² = u³ + Au² + u <span style="float: right">(1)</span>
//
// and given its relations to the coordinates of the Edwards model:
//
// u = (1+y)/(1-y) <span style="float: right">(2)</span>
// v = (λu)/(x)
//
// Converting from affine to projective coordinates in the Montgomery
// model, we arrive at:
//
// u = (Z+Y)/(Z-Y) <span style="float: right">(3)</span>
// v = λ * ((Z+Y)/(Z-Y)) * (Z/X)
//
// The transition between affine and projective is given by
//
// u → U/W <span style="float: right">(4)</span>
// v → V/W
//
// thus the Montgomery curve equation (1) becomes
//
// E_(A,B) : BV²W = U³ + AU²W + UW² ⊆ 𝗣^2 <span style="float: right">(5)</span>
//
// Here, again, to differentiate from points in the twisted Edwards model, we
// call the point `(x,y)` in affine coordinates `(u,v)` and similarly in projective
// space we use `(U:V:W)`. However, since (as per Montgomery's original work) the
// v-coordinate is not required to perform scalar multiplication, we merely
// use `(U:W)`.
//
// Therefore, the direct translation between projective Montgomery points
// and projective twisted Edwards points is
//
// (U:W) = (Z+Y:Z-Y) <span style="float: right">(6)</span>
//
// Note, however, that there appears to be an exception where `Z=Y`,
// since—from equation 2—this would imply that `y=1` (thus causing the
// denominator to be zero). If this is the case, then it follows from the
// twisted Edwards curve equation
//
// -x² + y² = 1 + dx²y² <span style="float: right">(7)</span>
//
// that
//
// -x² + 1 = 1 + dx²
//
// and, assuming that `d ≠ -1`,
//
// -x² = x²
// x = 0
//
// Therefore, the only valid point with `y=1` is the twisted Edwards
// identity point, which correctly becomes `(1:0)`, that is, the identity,
// in the Montgomery model.
pub fn to_montgomery(&self) -> MontgomeryPoint {
self.to_projective().to_montgomery()
MontgomeryPoint{
U: &self.Z + &self.Y,
W: &self.Z - &self.Y,
}
}
/// Compress this point to `CompressedEdwardsY` format.
pub fn compress(&self) -> CompressedEdwardsY {
self.to_projective().compress()
}
}
let recip = self.Z.invert();
let x = &self.X * &recip;
let y = &self.Y * &recip;
let mut s: [u8; 32];
impl CompletedPoint {
/// Convert to a ProjectivePoint
pub fn to_projective(&self) -> ProjectivePoint {
ProjectivePoint{
X: &self.X * &self.T,
Y: &self.Y * &self.Z,
Z: &self.Z * &self.T,
}
}
/// Convert to an ExtendedPoint
pub fn to_extended(&self) -> ExtendedPoint {
ExtendedPoint{
X: &self.X * &self.T,
Y: &self.Y * &self.Z,
Z: &self.Z * &self.T,
T: &self.X * &self.Y,
}
s = y.to_bytes();
s[31] ^= (x.is_negative() << 7) as u8;
CompressedEdwardsY(s)
}
}
@ -586,29 +359,9 @@ impl CompletedPoint {
// Doubling
// ------------------------------------------------------------------------
impl ProjectivePoint {
/// Double this point: return self + self
pub fn double(&self) -> CompletedPoint { // Double()
let XX = self.X.square();
let YY = self.Y.square();
let ZZ2 = self.Z.square2();
let X_plus_Y = &self.X + &self.Y;
let X_plus_Y_sq = X_plus_Y.square();
let YY_plus_XX = &YY + &XX;
let YY_minus_XX = &YY - &XX;
CompletedPoint{
X: &X_plus_Y_sq - &YY_plus_XX,
Y: YY_plus_XX,
Z: YY_minus_XX,
T: &ZZ2 - &YY_minus_XX
}
}
}
impl ExtendedPoint {
/// Add this point to itself.
pub fn double(&self) -> ExtendedPoint {
pub(crate) fn double(&self) -> ExtendedPoint {
self.to_projective().double().to_extended()
}
}
@ -617,88 +370,6 @@ impl ExtendedPoint {
// Addition and Subtraction
// ------------------------------------------------------------------------
impl<'a, 'b> Add<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint;
fn add(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint {
let Y_plus_X = &self.Y + &self.X;
let Y_minus_X = &self.Y - &self.X;
let PP = &Y_plus_X * &other.Y_plus_X;
let MM = &Y_minus_X * &other.Y_minus_X;
let TT2d = &self.T * &other.T2d;
let ZZ = &self.Z * &other.Z;
let ZZ2 = &ZZ + &ZZ;
CompletedPoint{
X: &PP - &MM,
Y: &PP + &MM,
Z: &ZZ2 + &TT2d,
T: &ZZ2 - &TT2d
}
}
}
impl<'a, 'b> Sub<&'b ProjectiveNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint;
fn sub(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint {
let Y_plus_X = &self.Y + &self.X;
let Y_minus_X = &self.Y - &self.X;
let PM = &Y_plus_X * &other.Y_minus_X;
let MP = &Y_minus_X * &other.Y_plus_X;
let TT2d = &self.T * &other.T2d;
let ZZ = &self.Z * &other.Z;
let ZZ2 = &ZZ + &ZZ;
CompletedPoint{
X: &PM - &MP,
Y: &PM + &MP,
Z: &ZZ2 - &TT2d,
T: &ZZ2 + &TT2d
}
}
}
impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint;
fn add(self, other: &'b AffineNielsPoint) -> CompletedPoint {
let Y_plus_X = &self.Y + &self.X;
let Y_minus_X = &self.Y - &self.X;
let PP = &Y_plus_X * &other.y_plus_x;
let MM = &Y_minus_X * &other.y_minus_x;
let Txy2d = &self.T * &other.xy2d;
let Z2 = &self.Z + &self.Z;
CompletedPoint{
X: &PP - &MM,
Y: &PP + &MM,
Z: &Z2 + &Txy2d,
T: &Z2 - &Txy2d
}
}
}
impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint {
type Output = CompletedPoint;
fn sub(self, other: &'b AffineNielsPoint) -> CompletedPoint {
let Y_plus_X = &self.Y + &self.X;
let Y_minus_X = &self.Y - &self.X;
let PM = &Y_plus_X * &other.y_minus_x;
let MP = &Y_minus_X * &other.y_plus_x;
let Txy2d = &self.T * &other.xy2d;
let Z2 = &self.Z + &self.Z;
CompletedPoint{
X: &PM - &MP,
Y: &PM + &MP,
Z: &Z2 - &Txy2d,
T: &Z2 + &Txy2d
}
}
}
impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint {
type Output = ExtendedPoint;
fn add(self, other: &'b ExtendedPoint) -> ExtendedPoint {
@ -742,32 +413,6 @@ impl<'a> Neg for &'a ExtendedPoint {
}
}
impl<'a> Neg for &'a ProjectiveNielsPoint {
type Output = ProjectiveNielsPoint;
fn neg(self) -> ProjectiveNielsPoint {
ProjectiveNielsPoint{
Y_plus_X: self.Y_minus_X,
Y_minus_X: self.Y_plus_X,
Z: self.Z,
T2d: -(&self.T2d),
}
}
}
impl<'a> Neg for &'a AffineNielsPoint {
type Output = AffineNielsPoint;
fn neg(self) -> AffineNielsPoint {
AffineNielsPoint{
y_plus_x: self.y_minus_x,
y_minus_x: self.y_plus_x,
xy2d: -(&self.xy2d)
}
}
}
// ------------------------------------------------------------------------
// Scalar multiplication
// ------------------------------------------------------------------------
@ -843,6 +488,8 @@ impl<'a, 'b> Mul<&'b ExtendedPoint> for &'a Scalar {
///
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
/// error to call this function with two vectors of different lengths.
///
/// XXX need to clear memory
#[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>,
@ -889,7 +536,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
// mults: we perform 63 multiplications by 16 instead of 63*n
// multiplications, saving 252*(n-1) doublings.
let mut Q = ExtendedPoint::identity();
// XXX this algorithm makes no effort to be cache-aware; maybe it could be improved?
// XXX this impl makes no effort to be cache-aware; maybe it could be improved?
for j in (0..64).rev() {
Q = Q.mult_by_pow_2(4);
let it = scalar_digits_list.iter().zip(lookup_tables.iter());
@ -904,8 +551,10 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
}
/// Precomputation
///
/// XXX we should box the internals
#[derive(Clone)]
pub struct EdwardsBasepointTable(pub [[AffineNielsPoint; 8]; 32]);
pub struct EdwardsBasepointTable(pub(crate) [[AffineNielsPoint; 8]; 32]);
impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable {
type Output = ExtendedPoint;
@ -963,27 +612,6 @@ impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar {
/// a the basepoint, `B` included in a precomputed `basepoint_table`.
///
/// Precondition: this scalar must be reduced.
///
/// The computation proceeds as follows, as described on page 13
/// of the Ed25519 paper. Write this 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.
fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> ExtendedPoint {
basepoint_table * &self
}
@ -1020,17 +648,13 @@ impl EdwardsBasepointTable {
impl ExtendedPoint {
/// Multiply by the cofactor: compute `8 * self`.
///
/// Convenience wrapper around `mult_by_pow_2`.
#[inline]
pub fn mult_by_cofactor(&self) -> ExtendedPoint {
self.mult_by_pow_2(3)
}
/// Compute `2^k * self` by successive doublings.
/// Requires `k > 0`.
#[inline]
pub fn mult_by_pow_2(&self, k: u32) -> ExtendedPoint {
pub(crate) fn mult_by_pow_2(&self, k: u32) -> ExtendedPoint {
let mut r: CompletedPoint;
let mut s = self.to_projective();
for _ in 0..(k-1) {
@ -1054,38 +678,12 @@ impl ExtendedPoint {
}
}
/// Given precomputed points `[P, 2P, 3P, ..., 8P]`, as well as `-8 ≤
/// x ≤ 8`, compute `x * B` in constant time, i.e., without branching
/// on x or using it as an array index.
fn select_precomputed_point<T>(x: i8, points: &[T; 8]) -> T
where T: Identity + ConditionallyAssignable, for<'a> &'a T: Neg<Output=T>
{
debug_assert!(x >= -8); debug_assert!(x <= 8);
// Compute xabs = |x|
let xmask = x >> 7;
let xabs = (x + xmask) ^ xmask;
// Set t = 0 * P = identity
let mut t = T::identity();
for j in 1..9 {
// Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`.
t.conditional_assign(&points[j-1],
bytes_equal(xabs as u8, j as u8));
}
// Now t == |x| * P.
let neg_mask = (xmask & 1) as u8;
t.conditional_negate(neg_mask);
// Now t == x * P.
t
}
// ------------------------------------------------------------------------
// Elligator2 (uniform encoding/decoding of curve points)
// ------------------------------------------------------------------------
// XXX should this be in another module, with types and `From` impls, like `CompressedEdwardsY`?
impl ExtendedPoint {
/// Use Elligator2 to try to convert `self` to a uniformly random
/// string.
@ -1093,14 +691,14 @@ impl ExtendedPoint {
/// Returns `Some<[u8;32]>` if `self` is in the image of the
/// Elligator2 map. For a random point on the curve, this happens
/// with probability 1/2. Otherwise, returns `None`.
pub fn to_uniform_representative(&self) -> Option<[u8; 32]> {
fn to_uniform_representative(&self) -> Option<[u8; 32]> {
unimplemented!();
}
/// Use Elligator2 to convert a uniformly random string to a curve
/// point.
#[allow(unused_variables)] // REMOVE WHEN IMPLEMENTED
pub fn from_uniform_representative(bytes: &[u8; 32]) -> ExtendedPoint {
fn from_uniform_representative(bytes: &[u8; 32]) -> ExtendedPoint {
unimplemented!();
}
}
@ -1116,34 +714,6 @@ impl Debug for ExtendedPoint {
}
}
impl Debug for ProjectivePoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "ProjectivePoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?}\n}}",
&self.X, &self.Y, &self.Z)
}
}
impl Debug for CompletedPoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "CompletedPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}",
&self.X, &self.Y, &self.Z, &self.T)
}
}
impl Debug for AffineNielsPoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "AffineNielsPoint{{\n\ty_plus_x: {:?},\n\ty_minus_x: {:?},\n\txy2d: {:?}\n}}",
&self.y_plus_x, &self.y_minus_x, &self.xy2d)
}
}
impl Debug for ProjectiveNielsPoint {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "ProjectiveNielsPoint{{\n\tY_plus_X: {:?},\n\tY_minus_X: {:?},\n\tZ: {:?},\n\tT2d: {:?}\n}}",
&self.Y_plus_X, &self.Y_minus_X, &self.Z, &self.T2d)
}
}
impl Debug for EdwardsBasepointTable {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "EdwardsBasepointTable([\n")?;
@ -1154,7 +724,6 @@ impl Debug for EdwardsBasepointTable {
}
}
// ------------------------------------------------------------------------
// Variable-time functions
// ------------------------------------------------------------------------

View file

@ -27,17 +27,19 @@ use subtle::ConditionallyNegatable;
use subtle::Equal;
use constants;
use backend;
#[cfg(feature="radix_51")]
pub use backend::u64::field::*;
/// A `FieldElement` represents an element of the field GF(2^255 - 19).
#[cfg(feature="radix_51")]
pub type FieldElement = FieldElement64;
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).
#[cfg(not(feature="radix_51"))]
pub type FieldElement = FieldElement32;
#[cfg(feature="radix_51")]
pub use field_64bit::*;
#[cfg(not(feature="radix_51"))]
pub use field_32bit::*;
pub type FieldElement = backend::u32::field::FieldElement32;
impl Eq for FieldElement {}
impl PartialEq for FieldElement {

View file

@ -35,22 +35,9 @@
//! hatred of the Daleks. Rusty destroys the other Daleks and departs the
//! ship, determined to track down and bring an end to the Dalek race.
#[cfg(all(test, feature = "bench"))]
extern crate test;
// this appears to only be used for serde support right now?
#[cfg(feature = "serde")]
#[macro_use]
extern crate arrayref;
extern crate generic_array;
extern crate digest;
extern crate subtle;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(all(test, feature = "serde"))]
extern crate serde_cbor;
//------------------------------------------------------------------------
// External dependencies:
//------------------------------------------------------------------------
#[cfg(feature = "std")]
extern crate core;
@ -61,29 +48,47 @@ extern crate rand;
#[cfg(feature = "alloc")]
extern crate alloc;
// Modules for low-level operations directly on field elements and curve points.
#[cfg(all(test, feature = "bench"))]
extern crate test;
pub mod field;
#[cfg(not(feature="radix_51"))]
mod field_32bit;
#[cfg(feature="radix_51")]
mod field_64bit;
// The `Digest` trait is implemented using `generic_array`, so we need it too. Hopefully we can eliminate `generic_array` from `Digest` once const generics land.
extern crate digest;
extern crate generic_array;
// Used for traits related to constant-time code.
extern crate subtle;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(all(test, feature = "serde"))]
extern crate serde_cbor;
//------------------------------------------------------------------------
// curve25519-dalek public modules
//------------------------------------------------------------------------
// Scalar arithmetic mod l = 2^252 + ..., the order of the Ristretto group
pub mod scalar;
#[cfg(not(feature="radix_51"))]
mod scalar_32bit;
#[cfg(feature="radix_51")]
mod scalar_64bit;
pub mod edwards;
// Point operations on the Montgomery form of Curve25519
pub mod montgomery;
// Point operations on the Edwards form of Curve25519
pub mod edwards;
// Group operations on the Ristretto group
pub mod ristretto;
// Low-level curve and point constants, as well as pre-computed curve group elements.
// Useful constants, like the Ed25519 basepoint
pub mod constants;
#[cfg(not(feature="radix_51"))]
mod constants_32bit;
#[cfg(feature="radix_51")]
mod constants_64bit;
// External (and internal) traits.
pub mod traits;
//------------------------------------------------------------------------
// curve25519-dalek internal modules
//------------------------------------------------------------------------
// Finite field arithmetic mod p = 2^255 - 19
pub(crate) mod field;
// Arithmetic backends (using u32, u64, etc) live here
pub(crate) mod backend;
// Internal curve models which are not part of the public API.
pub(crate) mod curve_models;

View file

@ -38,7 +38,9 @@ use scalar::Scalar;
// XXX Move these to a common "group" module? At the same time, we should
// XXX probably make a `trait Group` once const generics are implemented in
// XXX Rust. —isis
use edwards::{Identity, ValidityCheck};
//
// XXX I put these in a `traits` module for now - hdevalence
use traits::{Identity, ValidityCheck};
use subtle::ConditionallyAssignable;
use subtle::ConditionallySwappable;
@ -427,7 +429,7 @@ impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar {
#[cfg(test)]
mod test {
use constants::BASE_COMPRESSED_MONTGOMERY;
use edwards::Identity;
use traits::Identity;
use super::*;
use rand::OsRng;

View file

@ -400,18 +400,21 @@ use core::ops::{Add, Sub, Neg};
use core::ops::{AddAssign, SubAssign};
use core::ops::{Mul, MulAssign};
use edwards;
use edwards::ExtendedPoint;
use edwards::CompletedPoint;
use edwards::EdwardsBasepointTable;
use edwards::Identity;
use scalar::Scalar;
use subtle;
use subtle::ConditionallyAssignable;
use subtle::ConditionallyNegatable;
use subtle::Equal;
use edwards;
use edwards::ExtendedPoint;
use edwards::EdwardsBasepointTable;
use scalar::Scalar;
use curve_models::CompletedPoint;
use traits::Identity;
// ------------------------------------------------------------------------
// Compressed points
// ------------------------------------------------------------------------
@ -530,8 +533,9 @@ impl<'de> Deserialize<'de> for RistrettoPoint {
where E: serde::de::Error
{
if v.len() == 32 {
let arr32 = array_ref!(v, 0, 32); // &[u8;32] from &[u8]
CompressedRistretto(*arr32)
let mut arr32 = [0u8; 32];
arr32[0..32].copy_from_slice(v);
CompressedRistretto(arr32)
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
} else {
@ -557,7 +561,7 @@ impl<'de> Deserialize<'de> for RistrettoPoint {
/// `ExtendedPoint`, with custom equality, compression, and
/// decompression routines to account for the quotient.
#[derive(Copy, Clone)]
pub struct RistrettoPoint(pub ExtendedPoint);
pub struct RistrettoPoint(pub(crate) ExtendedPoint);
impl RistrettoPoint {
/// Compress in Ristretto format.
@ -953,7 +957,7 @@ impl ConditionallyAssignable for RistrettoPoint {
/// #
/// # use subtle::ConditionallyAssignable;
/// #
/// # use curve25519_dalek::edwards::Identity;
/// # use curve25519_dalek::traits::Identity;
/// # use curve25519_dalek::ristretto::RistrettoPoint;
/// # use curve25519_dalek::constants;
/// # fn main() {
@ -1032,8 +1036,7 @@ mod test {
use scalar::Scalar;
use constants;
use edwards::CompressedEdwardsY;
use edwards::Identity;
use edwards::ValidityCheck;
use traits::{Identity, ValidityCheck};
use super::*;
#[cfg(feature = "serde")]

View file

@ -46,6 +46,17 @@ use subtle::slices_equal;
use subtle::ConditionallyAssignable;
use subtle::Equal;
use backend;
/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed.
#[cfg(feature="radix_51")]
type UnpackedScalar = backend::u64::scalar::Scalar64;
/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed.
#[cfg(not(feature="radix_51"))]
type UnpackedScalar = backend::u32::scalar::Scalar32;
/// The `Scalar` struct represents an element in /l, where
///
/// l = 2^252 + 27742317777372353535851937790883648493
@ -216,7 +227,9 @@ impl<'de> Deserialize<'de> for Scalar {
{
if v.len() == 32 {
// array_ref turns &[u8] into &[u8;32]
Ok(Scalar(*array_ref!(v, 0, 32)))
let mut bytes = [0u8;32];
bytes.copy_from_slice(v);
Ok(Scalar(bytes))
} else {
Err(serde::de::Error::invalid_length(v.len(), &self))
}
@ -227,18 +240,6 @@ impl<'de> Deserialize<'de> for Scalar {
}
}
/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed.
#[cfg(feature="radix_51")]
type UnpackedScalar = Scalar64;
#[cfg(feature="radix_51")]
use scalar_64bit::*;
/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed.
#[cfg(not(feature="radix_51"))]
type UnpackedScalar = Scalar32;
#[cfg(not(feature="radix_51"))]
use scalar_32bit::*;
impl Scalar {
/// Return a `Scalar` chosen uniformly at random using a user-provided RNG.
///
@ -428,7 +429,7 @@ impl Scalar {
}
/// Unpack this `Scalar` to an `UnpackedScalar`
pub fn unpack(&self) -> UnpackedScalar {
pub(crate) fn unpack(&self) -> UnpackedScalar {
UnpackedScalar::from_bytes(&self.0)
}

87
src/traits.rs Normal file
View file

@ -0,0 +1,87 @@
// -*- mode: rust; -*-
//
// This file is part of curve25519-dalek.
// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence
// See LICENSE for licensing information.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Module for common traits.
use core::ops::Neg;
use subtle;
use subtle::ConditionallyAssignable;
use subtle::ConditionallyNegatable;
// ------------------------------------------------------------------------
// Public Traits
// ------------------------------------------------------------------------
/// Trait for getting the identity element of a point type.
pub trait Identity {
/// Returns the identity element of the curve.
/// Can be used as a constructor.
fn identity() -> Self;
}
/// Trait for testing if a curve point is equivalent to the identity point.
pub trait IsIdentity {
/// Return true if this element is the identity element of the curve.
fn is_identity(&self) -> bool;
}
/// Implement generic identity equality testing for a point representations
/// which have constant-time equality testing and a defined identity
/// constructor.
impl<T> IsIdentity for T where T: subtle::Equal + Identity {
fn is_identity(&self) -> bool {
self.ct_eq(&T::identity()) == 1u8
}
}
// ------------------------------------------------------------------------
// Private Traits
// ------------------------------------------------------------------------
/// Trait for checking whether a point is on the curve.
///
/// This trait is only for debugging/testing, since it should be
/// impossible for a `curve25519-dalek` user to construct an invalid
/// point.
pub(crate) trait ValidityCheck {
/// Checks whether the point is on the curve. Not CT.
fn is_valid(&self) -> bool;
}
// This isn't a trait, but it is fully generic...
/// Given precomputed points `[P, 2P, 3P, ..., 8P]`, as well as `-8 ≤
/// x ≤ 8`, compute `x * B` in constant time, i.e., without branching
/// on x or using it as an array index.
pub(crate) fn select_precomputed_point<T>(x: i8, points: &[T; 8]) -> T
where T: Identity + ConditionallyAssignable, for<'a> &'a T: Neg<Output=T>
{
debug_assert!(x >= -8); debug_assert!(x <= 8);
// Compute xabs = |x|
let xmask = x >> 7;
let xabs = (x + xmask) ^ xmask;
// Set t = 0 * P = identity
let mut t = T::identity();
for j in 1..9 {
// Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`.
t.conditional_assign(&points[j-1],
subtle::bytes_equal(xabs as u8, j as u8));
}
// Now t == |x| * P.
let neg_mask = (xmask & 1) as u8;
t.conditional_negate(neg_mask);
// Now t == x * P.
t
}