mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-06 20:41:14 +00:00
Split internal curve models into a private submodule
This commit is contained in:
parent
e196f8347c
commit
8d0808a077
8 changed files with 650 additions and 550 deletions
8
build.rs
8
build.rs
|
|
@ -36,12 +36,15 @@ mod edwards;
|
||||||
mod ristretto;
|
mod ristretto;
|
||||||
#[path="src/constants.rs"]
|
#[path="src/constants.rs"]
|
||||||
mod constants;
|
mod constants;
|
||||||
|
#[path="src/traits.rs"]
|
||||||
|
mod traits;
|
||||||
|
|
||||||
// Internal modules
|
// Internal modules
|
||||||
|
|
||||||
#[path="src/field.rs"]
|
#[path="src/field.rs"]
|
||||||
mod field;
|
mod field;
|
||||||
|
#[path="src/curve_models/mod.rs"]
|
||||||
|
mod curve_models;
|
||||||
#[path="src/backend/mod.rs"]
|
#[path="src/backend/mod.rs"]
|
||||||
mod backend;
|
mod backend;
|
||||||
|
|
||||||
|
|
@ -65,9 +68,10 @@ use backend::u64::field::FieldElement64;
|
||||||
#[cfg(not(feature=\"radix_51\"))]
|
#[cfg(not(feature=\"radix_51\"))]
|
||||||
use backend::u32::field::FieldElement32;
|
use backend::u32::field::FieldElement32;
|
||||||
|
|
||||||
use edwards::AffineNielsPoint;
|
|
||||||
use edwards::EdwardsBasepointTable;
|
use edwards::EdwardsBasepointTable;
|
||||||
|
|
||||||
|
use curve_models::AffineNielsPoint;
|
||||||
|
|
||||||
/// Table containing precomputed multiples of the basepoint `B = (x,4/5)`.
|
/// 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`,
|
/// The table is defined so `constants::base[i][j-1] = j*(16^2i)*B`,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! use curve25519_dalek::constants;
|
//! use curve25519_dalek::constants;
|
||||||
//! use curve25519_dalek::edwards::IsIdentity;
|
//! use curve25519_dalek::traits::IsIdentity;
|
||||||
//!
|
//!
|
||||||
//! let B = &constants::RISTRETTO_BASEPOINT_TABLE;
|
//! let B = &constants::RISTRETTO_BASEPOINT_TABLE;
|
||||||
//! let l = &constants::BASEPOINT_ORDER;
|
//! let l = &constants::BASEPOINT_ORDER;
|
||||||
|
|
@ -102,8 +102,7 @@ pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use field::FieldElement;
|
use field::FieldElement;
|
||||||
use edwards::IsIdentity;
|
use traits::{IsIdentity, ValidityCheck};
|
||||||
use edwards::ValidityCheck;
|
|
||||||
use constants;
|
use constants;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
505
src/curve_models/mod.rs
Normal file
505
src/curve_models/mod.rs
Normal file
|
|
@ -0,0 +1,505 @@
|
||||||
|
// -*- 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 core::ops::Index;
|
||||||
|
|
||||||
|
use constants;
|
||||||
|
|
||||||
|
use field::FieldElement;
|
||||||
|
|
||||||
|
use edwards::ExtendedPoint;
|
||||||
|
use edwards::CompressedEdwardsY;
|
||||||
|
use montgomery::MontgomeryPoint;
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 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
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
563
src/edwards.rs
563
src/edwards.rs
|
|
@ -8,67 +8,7 @@
|
||||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||||
|
|
||||||
//! Group operations for Curve25519, in the form of the twisted
|
//! Group operations for Curve25519, in Edwards form.
|
||||||
//! 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
|
|
||||||
|
|
||||||
// We allow non snake_case names because coordinates in projective space are
|
// We allow non snake_case names because coordinates in projective space are
|
||||||
// traditionally denoted by the capitalisation of their respective
|
// 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::{Mul, MulAssign};
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
|
|
||||||
use constants;
|
|
||||||
use field::FieldElement;
|
|
||||||
use scalar::Scalar;
|
|
||||||
use montgomery::MontgomeryPoint;
|
|
||||||
|
|
||||||
use subtle::slices_equal;
|
use subtle::slices_equal;
|
||||||
use subtle::bytes_equal;
|
|
||||||
use subtle::ConditionallyAssignable;
|
use subtle::ConditionallyAssignable;
|
||||||
use subtle::ConditionallyNegatable;
|
use subtle::ConditionallyNegatable;
|
||||||
|
// XXX subtle::Equal
|
||||||
use 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
|
// Compressed points
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
@ -210,74 +161,19 @@ impl<'de> Deserialize<'de> for ExtendedPoint {
|
||||||
|
|
||||||
/// An `ExtendedPoint` is a point on the curve in 𝗣³(𝔽ₚ).
|
/// An `ExtendedPoint` is a point on the curve in 𝗣³(𝔽ₚ).
|
||||||
/// A point (x,y) in the affine model corresponds to (x:y:1:xy).
|
/// 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)]
|
#[derive(Copy, Clone)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub struct ExtendedPoint {
|
pub struct ExtendedPoint {
|
||||||
pub X: FieldElement,
|
pub(crate) X: FieldElement,
|
||||||
pub Y: FieldElement,
|
pub(crate) Y: FieldElement,
|
||||||
pub Z: FieldElement,
|
pub(crate) Z: FieldElement,
|
||||||
pub T: FieldElement,
|
pub(crate) 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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Constructors
|
// 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 {
|
impl Identity for CompressedEdwardsY {
|
||||||
fn identity() -> CompressedEdwardsY {
|
fn identity() -> CompressedEdwardsY {
|
||||||
CompressedEdwardsY([1, 0, 0, 0, 0, 0, 0, 0,
|
CompressedEdwardsY([1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
|
@ -296,58 +192,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)
|
// 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 {
|
impl ValidityCheck for ExtendedPoint {
|
||||||
// XXX this should also check that T is correct
|
// XXX this should also check that T is correct
|
||||||
fn is_valid(&self) -> bool {
|
fn is_valid(&self) -> bool {
|
||||||
|
|
@ -359,24 +207,6 @@ impl ValidityCheck for ExtendedPoint {
|
||||||
// Constant-time assignment
|
// 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 {
|
impl ConditionallyAssignable for ExtendedPoint {
|
||||||
fn conditional_assign(&mut self, other: &ExtendedPoint, choice: u8) {
|
fn conditional_assign(&mut self, other: &ExtendedPoint, choice: u8) {
|
||||||
self.X.conditional_assign(&other.X, choice);
|
self.X.conditional_assign(&other.X, choice);
|
||||||
|
|
@ -397,120 +227,10 @@ 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
|
// 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 {
|
impl ExtendedPoint {
|
||||||
/// Convert to a ProjectiveNielsPoint
|
/// Convert to a ProjectiveNielsPoint
|
||||||
pub fn to_projective_niels(&self) -> ProjectiveNielsPoint {
|
pub fn to_projective_niels(&self) -> ProjectiveNielsPoint {
|
||||||
|
|
@ -561,54 +281,13 @@ impl ExtendedPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// 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 {
|
impl ExtendedPoint {
|
||||||
/// Add this point to itself.
|
/// Add this point to itself.
|
||||||
pub fn double(&self) -> ExtendedPoint {
|
pub(crate) fn double(&self) -> ExtendedPoint {
|
||||||
self.to_projective().double().to_extended()
|
self.to_projective().double().to_extended()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -617,88 +296,6 @@ impl ExtendedPoint {
|
||||||
// Addition and Subtraction
|
// 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 {
|
impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint {
|
||||||
type Output = ExtendedPoint;
|
type Output = ExtendedPoint;
|
||||||
fn add(self, other: &'b ExtendedPoint) -> ExtendedPoint {
|
fn add(self, other: &'b ExtendedPoint) -> ExtendedPoint {
|
||||||
|
|
@ -742,32 +339,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
|
// Scalar multiplication
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
@ -843,6 +414,8 @@ impl<'a, 'b> Mul<&'b ExtendedPoint> for &'a Scalar {
|
||||||
///
|
///
|
||||||
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
|
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
|
||||||
/// error to call this function with two vectors of different lengths.
|
/// error to call this function with two vectors of different lengths.
|
||||||
|
///
|
||||||
|
/// XXX need to clear memory
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
|
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
|
||||||
where I: IntoIterator<Item = &'a Scalar>,
|
where I: IntoIterator<Item = &'a Scalar>,
|
||||||
|
|
@ -889,7 +462,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
|
// mults: we perform 63 multiplications by 16 instead of 63*n
|
||||||
// multiplications, saving 252*(n-1) doublings.
|
// multiplications, saving 252*(n-1) doublings.
|
||||||
let mut Q = ExtendedPoint::identity();
|
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() {
|
for j in (0..64).rev() {
|
||||||
Q = Q.mult_by_pow_2(4);
|
Q = Q.mult_by_pow_2(4);
|
||||||
let it = scalar_digits_list.iter().zip(lookup_tables.iter());
|
let it = scalar_digits_list.iter().zip(lookup_tables.iter());
|
||||||
|
|
@ -904,8 +477,10 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> ExtendedPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Precomputation
|
/// Precomputation
|
||||||
|
///
|
||||||
|
/// XXX we should box the internals
|
||||||
#[derive(Clone)]
|
#[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 {
|
impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable {
|
||||||
type Output = ExtendedPoint;
|
type Output = ExtendedPoint;
|
||||||
|
|
@ -963,27 +538,6 @@ impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar {
|
||||||
/// a the basepoint, `B` included in a precomputed `basepoint_table`.
|
/// a the basepoint, `B` included in a precomputed `basepoint_table`.
|
||||||
///
|
///
|
||||||
/// Precondition: this scalar must be reduced.
|
/// 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 {
|
fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> ExtendedPoint {
|
||||||
basepoint_table * &self
|
basepoint_table * &self
|
||||||
}
|
}
|
||||||
|
|
@ -1054,38 +608,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)
|
// Elligator2 (uniform encoding/decoding of curve points)
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// XXX should this be in another module, with types and `From` impls, like `CompressedEdwardsY`?
|
||||||
|
|
||||||
impl ExtendedPoint {
|
impl ExtendedPoint {
|
||||||
/// Use Elligator2 to try to convert `self` to a uniformly random
|
/// Use Elligator2 to try to convert `self` to a uniformly random
|
||||||
/// string.
|
/// string.
|
||||||
|
|
@ -1116,34 +644,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 {
|
impl Debug for EdwardsBasepointTable {
|
||||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||||
write!(f, "EdwardsBasepointTable([\n")?;
|
write!(f, "EdwardsBasepointTable([\n")?;
|
||||||
|
|
@ -1154,7 +654,6 @@ impl Debug for EdwardsBasepointTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Variable-time functions
|
// Variable-time functions
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ pub mod edwards;
|
||||||
pub mod ristretto;
|
pub mod ristretto;
|
||||||
// Useful constants, like the Ed25519 basepoint
|
// Useful constants, like the Ed25519 basepoint
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
|
// External (and internal) traits.
|
||||||
|
pub mod traits;
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// curve25519-dalek internal modules
|
// curve25519-dalek internal modules
|
||||||
|
|
@ -95,4 +97,4 @@ pub(crate) mod field;
|
||||||
pub(crate) mod backend;
|
pub(crate) mod backend;
|
||||||
|
|
||||||
// Internal curve models which are not part of the public API.
|
// Internal curve models which are not part of the public API.
|
||||||
//mod curve_models;
|
pub(crate) mod curve_models;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,9 @@ use scalar::Scalar;
|
||||||
// XXX Move these to a common "group" module? At the same time, we should
|
// 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 probably make a `trait Group` once const generics are implemented in
|
||||||
// XXX Rust. —isis
|
// 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::ConditionallyAssignable;
|
||||||
use subtle::ConditionallySwappable;
|
use subtle::ConditionallySwappable;
|
||||||
|
|
@ -427,7 +429,7 @@ impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use constants::BASE_COMPRESSED_MONTGOMERY;
|
use constants::BASE_COMPRESSED_MONTGOMERY;
|
||||||
use edwards::Identity;
|
use traits::Identity;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use rand::OsRng;
|
use rand::OsRng;
|
||||||
|
|
|
||||||
|
|
@ -400,18 +400,21 @@ use core::ops::{Add, Sub, Neg};
|
||||||
use core::ops::{AddAssign, SubAssign};
|
use core::ops::{AddAssign, SubAssign};
|
||||||
use core::ops::{Mul, MulAssign};
|
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;
|
||||||
use subtle::ConditionallyAssignable;
|
use subtle::ConditionallyAssignable;
|
||||||
use subtle::ConditionallyNegatable;
|
use subtle::ConditionallyNegatable;
|
||||||
use subtle::Equal;
|
use subtle::Equal;
|
||||||
|
|
||||||
|
use edwards;
|
||||||
|
use edwards::ExtendedPoint;
|
||||||
|
use edwards::EdwardsBasepointTable;
|
||||||
|
|
||||||
|
use scalar::Scalar;
|
||||||
|
|
||||||
|
use curve_models::CompletedPoint;
|
||||||
|
|
||||||
|
use traits::Identity;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Compressed points
|
// Compressed points
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
@ -953,7 +956,7 @@ impl ConditionallyAssignable for RistrettoPoint {
|
||||||
/// #
|
/// #
|
||||||
/// # use subtle::ConditionallyAssignable;
|
/// # use subtle::ConditionallyAssignable;
|
||||||
/// #
|
/// #
|
||||||
/// # use curve25519_dalek::edwards::Identity;
|
/// # use curve25519_dalek::traits::Identity;
|
||||||
/// # use curve25519_dalek::ristretto::RistrettoPoint;
|
/// # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// # use curve25519_dalek::constants;
|
/// # use curve25519_dalek::constants;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
|
|
@ -1032,8 +1035,7 @@ mod test {
|
||||||
use scalar::Scalar;
|
use scalar::Scalar;
|
||||||
use constants;
|
use constants;
|
||||||
use edwards::CompressedEdwardsY;
|
use edwards::CompressedEdwardsY;
|
||||||
use edwards::Identity;
|
use traits::{Identity, ValidityCheck};
|
||||||
use edwards::ValidityCheck;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
|
|
||||||
87
src/traits.rs
Normal file
87
src/traits.rs
Normal 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
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue