Merge branch 'release/0.11.0'

This commit is contained in:
Isis Lovecruft 2017-08-15 05:00:25 +00:00
commit 84b7d8698f
Failed to extract signature
9 changed files with 291 additions and 247 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "curve25519-dalek"
version = "0.10.0"
version = "0.11.0"
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
"Henry de Valence <hdevalence@hdevalence.ca>"]
readme = "README.md"
@ -23,7 +23,7 @@ version = "1.0"
optional = true
[dependencies.arrayref]
version = "0.3.3"
version = "0.3.4"
[dependencies.rand]
optional = true

View file

@ -44,7 +44,7 @@ Extensive documentation is available [here](https://docs.rs/curve25519-dalek).
To install, add the following to the dependencies section of your project's
`Cargo.toml`:
curve25519-dalek = "^0.10"
curve25519-dalek = "^0.11"
Then, in your library or executable source, add:

View file

@ -19,7 +19,7 @@
#![allow(missing_docs)]
#![allow(non_snake_case)]
use curve::CompressedEdwardsY;
use edwards::CompressedEdwardsY;
#[cfg(feature = "yolocrypto")]
use decaf::{DecafPoint, DecafBasepointTable};
use scalar::Scalar;
@ -53,9 +53,10 @@ pub const BASE_CMPRSSD: CompressedEdwardsY =
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]);
/// The Ed25519 basepoint, as a `DecafPoint`.
#[cfg(feature = "yolocrypto")]
pub const DECAF_ED25519_BASEPOINT: DecafPoint = DecafPoint(ED25519_BASEPOINT);
/// The Ed25519 basepoint, as a `DecafPoint`. This is called `_POINT` to distinguish it from
/// `_TABLE`, which provides fast scalar multiplication.
#[cfg(feature = "yolocrypto")] pub const DECAF_ED25519_BASEPOINT_POINT: DecafPoint =
DecafPoint(ED25519_BASEPOINT_POINT);
/// `l` is the order of base point, i.e. 2^252 +
/// 27742317777372353535851937790883648493, in little-endian form
@ -86,8 +87,8 @@ pub const DECAF_ED25519_BASEPOINT_TABLE: DecafBasepointTable
#[cfg(test)]
mod test {
use field::FieldElement;
use curve::IsIdentity;
use curve::ValidityCheck;
use edwards::IsIdentity;
use edwards::ValidityCheck;
use constants;
#[test]

View file

@ -20,9 +20,9 @@
#![allow(non_snake_case)]
use field_32bit::FieldElement32;
use curve::ExtendedPoint;
use curve::AffineNielsPoint;
use curve::EdwardsBasepointTable;
use edwards::ExtendedPoint;
use edwards::AffineNielsPoint;
use edwards::EdwardsBasepointTable;
pub const d: FieldElement32 = FieldElement32([
-10913610, 13857413, -15372611, 6949391, 114729,
@ -94,8 +94,9 @@ pub const SQRT_MINUS_HALF: FieldElement32 = FieldElement32([ // sqrtMinusHalf
-17256545, 3971863, 28865457, -1750208, 27359696,
-16640980, 12573105, 1002827, -163343, 11073975, ]);
/// Basepoint has y = 4/5.
pub const ED25519_BASEPOINT: ExtendedPoint = ExtendedPoint{
/// Basepoint has y = 4/5. This is called `_POINT` to distinguish it from `_TABLE`, which should
/// be used for scalar multiplication (it's much faster).
pub const ED25519_BASEPOINT_POINT: ExtendedPoint = ExtendedPoint{
X: FieldElement32([-14297830, -7645148, 16144683, -16471763, 27570974, -2696100, -26142465, 8378389, 20764389, 8758491]),
Y: FieldElement32([-26843541, -6710886, 13421773, -13421773, 26843546, 6710886, -13421773, 13421773, -26843546, -6710886]),
Z: FieldElement32([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]),

View file

@ -20,9 +20,9 @@
#![allow(non_snake_case)]
use field_64bit::FieldElement64;
use curve::ExtendedPoint;
use curve::AffineNielsPoint;
use curve::EdwardsBasepointTable;
use edwards::ExtendedPoint;
use edwards::AffineNielsPoint;
use edwards::EdwardsBasepointTable;
pub const p: FieldElement64 = FieldElement64([2251799813685229, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247]);
@ -67,8 +67,9 @@ pub const SQRT_MINUS_APLUS2: FieldElement64 = FieldElement64([1693982333959686,
/// `SQRT_MINUS_HALF` is sqrt(-1/2)
pub const SQRT_MINUS_HALF: FieldElement64 = FieldElement64([266547196637087, 2134345371906993, 1135042577398223, 67298593331632, 743161882051057]);
/// Basepoint has y = 4/5.
pub const ED25519_BASEPOINT: ExtendedPoint = ExtendedPoint {
/// Basepoint has y = 4/5. This is called `_POINT` to distinguish it from `_TABLE`, which should
/// be used for scalar multiplication (it's much faster).
pub const ED25519_BASEPOINT_POINT: ExtendedPoint = ExtendedPoint{
X: FieldElement64([1738742601995546, 1146398526822698, 2070867633025821, 562264141797630, 587772402128613]),
Y: FieldElement64([1801439850948184, 1351079888211148, 450359962737049, 900719925474099, 1801439850948198]),
Z: FieldElement64([1, 0, 0, 0, 0]),

View file

@ -37,11 +37,11 @@ use core::ops::{Add, Sub, Neg};
use core::ops::{AddAssign, SubAssign};
use core::ops::{Mul, MulAssign};
use curve;
use curve::ExtendedPoint;
use curve::CompletedPoint;
use curve::EdwardsBasepointTable;
use curve::Identity;
use edwards;
use edwards::ExtendedPoint;
use edwards::CompletedPoint;
use edwards::EdwardsBasepointTable;
use edwards::Identity;
use scalar::Scalar;
use subtle::ConditionallyAssignable;
@ -59,6 +59,11 @@ pub struct CompressedDecaf(pub [u8; 32]);
/// The result of compressing a `DecafPoint`.
impl CompressedDecaf {
/// Convert this `CompressedDecaf` to an array of bytes.
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
/// View this `CompressedDecaf` as an array of bytes.
pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] {
&self.0
@ -593,7 +598,7 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> DecafPoint
J: IntoIterator<Item = &'b DecafPoint>,
{
let extended_points = points.into_iter().map(|P| &P.0);
DecafPoint(curve::multiscalar_mult(scalars, extended_points))
DecafPoint(edwards::multiscalar_mult(scalars, extended_points))
}
/// Precomputation
@ -643,12 +648,12 @@ impl ConditionallyAssignable for DecafPoint {
/// #
/// # use subtle::ConditionallyAssignable;
/// #
/// # use curve25519_dalek::curve::Identity;
/// # use curve25519_dalek::edwards::Identity;
/// # use curve25519_dalek::decaf::DecafPoint;
/// # use curve25519_dalek::constants;
/// # fn main() {
/// let A = DecafPoint::identity();
/// let B = constants::DECAF_ED25519_BASEPOINT;
/// let B = constants::DECAF_ED25519_BASEPOINT_POINT;
///
/// let mut P = A;
///
@ -706,7 +711,7 @@ pub mod vartime {
J: IntoIterator<Item = &'b DecafPoint>
{
let extended_points = points.into_iter().map(|P| &P.0);
DecafPoint(curve::vartime::multiscalar_mult(scalars, extended_points))
DecafPoint(edwards::vartime::multiscalar_mult(scalars, extended_points))
}
}
@ -720,9 +725,9 @@ mod test {
use scalar::Scalar;
use constants;
use curve::CompressedEdwardsY;
use curve::Identity;
use curve::ValidityCheck;
use edwards::CompressedEdwardsY;
use edwards::Identity;
use edwards::ValidityCheck;
use super::*;
#[cfg(feature = "serde")]
@ -731,9 +736,9 @@ mod test {
#[test]
#[cfg(feature = "serde")]
fn serde_cbor_basepoint_roundtrip() {
let output = serde_cbor::to_vec(&constants::DECAF_ED25519_BASEPOINT).unwrap();
let output = serde_cbor::to_vec(&constants::DECAF_ED25519_BASEPOINT_POINT).unwrap();
let parsed: DecafPoint = serde_cbor::from_slice(&output).unwrap();
assert_eq!(parsed, constants::DECAF_ED25519_BASEPOINT);
assert_eq!(parsed, constants::DECAF_ED25519_BASEPOINT_POINT);
}
@ -759,10 +764,10 @@ mod test {
#[test]
fn decaf_basepoint_roundtrip() {
let bp_compressed_decaf = constants::DECAF_ED25519_BASEPOINT.compress();
let bp_compressed_decaf = constants::DECAF_ED25519_BASEPOINT_POINT.compress();
let bp_recaf = bp_compressed_decaf.decompress().unwrap().0;
// Check that bp_recaf differs from bp by a point of order 4
let diff = &constants::ED25519_BASEPOINT - &bp_recaf;
let diff = &constants::ED25519_BASEPOINT_POINT - &bp_recaf;
let diff4 = diff.mult_by_pow_2(4); // XXX this is wrong
assert_eq!(diff4.compress_edwards(), CompressedEdwardsY::identity());
}
@ -789,16 +794,16 @@ mod test {
CompressedDecaf([7, 221, 140, 57, 13, 146, 248, 27, 56, 4, 128, 23, 145, 120, 126, 4, 158, 173, 52, 213, 164, 250, 26, 55, 89, 96, 187, 111, 211, 18, 63, 19]),
CompressedDecaf([91, 213, 193, 10, 102, 92, 199, 124, 61, 176, 1, 47, 111, 59, 183, 91, 79, 56, 208, 109, 172, 209, 17, 167, 229, 216, 3, 236, 200, 208, 15, 20]),
];
let mut bp = constants::DECAF_ED25519_BASEPOINT;
let mut bp = constants::DECAF_ED25519_BASEPOINT_POINT;
for i in 0..16 {
assert_eq!(bp.compress(), compressed[i]);
bp = &bp + &constants::DECAF_ED25519_BASEPOINT;
bp = &bp + &constants::DECAF_ED25519_BASEPOINT_POINT;
}
}
#[test]
fn decaf_four_torsion_basepoint() {
let bp = constants::DECAF_ED25519_BASEPOINT;
let bp = constants::DECAF_ED25519_BASEPOINT_POINT;
let bp_coset = bp.coset4();
for i in 0..4 {
assert_eq!(bp, DecafPoint(bp_coset[i]));

View file

@ -90,6 +90,7 @@ use core::ops::Index;
use constants;
use field::FieldElement;
use scalar::Scalar;
use montgomery::CompressedMontgomeryU;
use subtle::slices_equal;
use subtle::bytes_equal;
@ -151,133 +152,6 @@ impl CompressedEdwardsY {
}
}
/// In "Montgomery u" format, as used in X25519, a point `(u,v)` on
/// the Montgomery curve
///
/// v^2 = u * (u^2 + 486662*u + 1)
///
/// is represented just by `u`. Note that we use `(u,v)` instead of
/// `(x,y)` for Montgomery coordinates to avoid confusion with Edwards
/// coordinates. For Montgomery curves, it is possible to compute the
/// `u`-coordinate of `n(u,v)` just from `n` and `u`, so it is not
/// necessary to use `v` for a Diffie-Hellman key exchange.
///
/// XXX add note on monty, twist security, edwards impl of x25519, rfc7748
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CompressedMontgomeryU(pub [u8; 32]);
impl CompressedMontgomeryU {
/// View this `CompressedMontgomeryU` as an array of bytes.
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
/// Attempt to decompress to an `ExtendedPoint`.
///
/// # Note
///
/// Since there are two curve points with the same
/// `u`-coordinate, the `u`-coordinate does not fully specify a
/// point. That is, roundtripping between an `ExtendedPoint` and
/// a `CompressedMontgomeryU` discards its sign bit.
///
/// # Warning
///
/// This function is *not* constant time.
///
/// # Return
///
/// An `Option<ExtendedPoint>`, which will be `None` if either condition holds:
///
/// * `u = -1`, or
/// * `v` is not square.
//
// XXX any other exceptional points for the birational map?
pub fn decompress(&self) -> Option<ExtendedPoint> {
let u: FieldElement = FieldElement::from_bytes(&self.0);
// If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660.
// But 486660 is nonsquare mod p, so this is not a curve point.
//
// Note: currently, without this check, u = -1 will accidentally
// decode to a valid (but incorrect) point, since 0.invert() = 0.
if u == FieldElement::minus_one() {
return None;
}
let y: FieldElement = CompressedMontgomeryU::to_edwards_y(&u); // y = (u-1)/(u+1)
// XXX this does two inversions: the above + one in .decompress()
// is it possible to do one?
CompressedEdwardsY(y.to_bytes()).decompress()
}
/// Given a Montgomery `u` coordinate, compute an Edwards `y` via
/// `y = (u-1)/(u+1)`.
///
/// # Return
///
/// A `FieldElement` corresponding to this coordinate, but in Edwards form.
pub fn to_edwards_y(u: &FieldElement) -> FieldElement {
// Since `u = (1+y)/(1-y)` and `v = √(u(u²+Au+1))`, so `y = (u-1)/(u+1)`.
&(u - &FieldElement::one()) * &(u + &FieldElement::one()).invert()
}
/// Given a Montgomery `u` coordinate, compute the corresponding
/// Montgomery `v` coordinate by computing the right-hand side of
/// the Montgomery field equation, `v² = u(u² + Au +1)`.
///
/// # Return
///
/// A tuple of (`u8`, `FieldElement`), where the `u8` is `1` if the v² was
/// actually a square and `0` if otherwise, along with a `FieldElement`: the
/// Montgomery `v` corresponding to this `u`.
pub fn to_montgomery_v(u: &FieldElement) -> (u8, FieldElement) {
let one: FieldElement = FieldElement::one();
let v_squared: FieldElement = u * &(&u.square() + &(&(&constants::A * u) + &one));
let (okay, v_inv) = v_squared.invsqrt();
let v = &v_inv * &v_squared;
(okay, v)
}
/// Given Montgomery coordinates `(u, v)`, recover the Edwards `x` coordinate.
///
/// # Inputs
///
/// * `u` and `v` are both `&FieldElement`s, corresponding the the `(u, v)`
/// coordinates of this `CompressedMontgomeryU`.
/// * `sign` is an &u8.
///
/// ## Explanation of choice of `sign`
///
/// ### Original Signal behaviour:
///
/// - `1u8` will leave `x` negative if it is negative, and will negate
/// `x` if it is positive, and
/// - `0u8` will leave `x` positive if it is positive, and will negate
/// `x` if it is negative.
///
/// Hence, if `sign` is `1u8`, the returned `x` will be negative.
/// Otherwise, if `sign` is `0u8`, the returned `x` will be positive.
///
/// # Return
///
/// A `FieldElement`, the Edwards `x` coordinate, by using `(u, v)` to
/// convert from Montgomery to Edwards form via the right-hand side of the
/// equation: `x=(u/v)*sqrt(-A-2)`.
pub fn to_edwards_x(u: &FieldElement, v: &FieldElement, sign: &u8) -> FieldElement {
let mut x: FieldElement = &(u * &v.invert()) * &constants::SQRT_MINUS_APLUS2;
let neg_x: FieldElement = -(&x);
let current_sign: u8 = x.is_negative_ed25519();
// Negate x to match the sign:
x.conditional_assign(&neg_x, current_sign ^ sign);
x
}
}
// ------------------------------------------------------------------------
// Serde support
// ------------------------------------------------------------------------
@ -553,8 +427,7 @@ impl ProjectivePoint {
/// 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).
#[allow(dead_code)] // rustc complains this is unused even when it's used
fn to_extended(&self) -> ExtendedPoint {
pub fn to_extended(&self) -> ExtendedPoint {
ExtendedPoint{
X: &self.X * &self.Z,
Y: &self.Y * &self.Z,
@ -1318,7 +1191,7 @@ pub mod vartime {
/// with x positive).
pub fn double_scalar_mult_basepoint(a: &Scalar,
A: &ExtendedPoint,
b: &Scalar) -> ProjectivePoint {
b: &Scalar) -> ExtendedPoint {
let a_naf = a.non_adjacent_form();
let b_naf = b.non_adjacent_form();
@ -1357,7 +1230,7 @@ pub mod vartime {
i -= 1;
}
r
r.to_extended()
}
}
@ -1376,13 +1249,6 @@ mod test {
use constants;
use super::*;
/// The X25519 basepoint, in compressed Montgomery form.
static BASE_CMPRSSD_MONTY: CompressedMontgomeryU =
CompressedMontgomeryU([0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
/// X coordinate of the basepoint.
/// = 15112221349535400772501151409588531511454012693041857206046113283949847762202
static BASE_X_COORD_BYTES: [u8; 32] =
@ -1432,40 +1298,6 @@ mod test {
0xc0, 0x46, 0x83, 0x43, 0xde, 0x70, 0x4b, 0x85,
0x09, 0x6f, 0xfe, 0x35, 0x4f, 0x13, 0x2b, 0x42]);
/// Test Montgomery conversion against the X25519 basepoint.
#[test]
fn basepoint_to_montgomery() {
assert_eq!(constants::ED25519_BASEPOINT.compress_montgomery().unwrap(),
BASE_CMPRSSD_MONTY);
}
/// Test Montgomery conversion against the X25519 basepoint.
#[test]
fn basepoint_from_montgomery() {
assert_eq!(BASE_CMPRSSD_MONTY.decompress().unwrap().compress_edwards(),
constants::BASE_CMPRSSD);
}
/// If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660.
/// But 486660 is nonsquare mod p, so this should fail.
///
/// XXX what does Signal do here?
#[test]
fn u_minus_one_monty() {
let minus_one = FieldElement::minus_one();
let minus_one_bytes = minus_one.to_bytes();
let div_by_zero_u = CompressedMontgomeryU(minus_one_bytes);
assert!(div_by_zero_u.decompress().is_none());
}
/// Montgomery compression of the identity point should
/// fail (it's sent to infinity).
#[test]
fn identity_to_monty() {
let id = ExtendedPoint::identity();
assert!(id.compress_montgomery().is_none());
}
/// Test round-trip decompression for the basepoint.
#[test]
fn basepoint_decompression_compression() {
@ -1487,10 +1319,10 @@ mod test {
.decompress().unwrap();
// Test projective coordinates exactly since we know they should
// only differ by a flipped sign.
assert_eq!(minus_basepoint.X, -(&constants::ED25519_BASEPOINT.X));
assert_eq!(minus_basepoint.Y, constants::ED25519_BASEPOINT.Y);
assert_eq!(minus_basepoint.Z, constants::ED25519_BASEPOINT.Z);
assert_eq!(minus_basepoint.T, -(&constants::ED25519_BASEPOINT.T));
assert_eq!(minus_basepoint.X, -(&constants::ED25519_BASEPOINT_POINT.X));
assert_eq!(minus_basepoint.Y, constants::ED25519_BASEPOINT_POINT.Y);
assert_eq!(minus_basepoint.Z, constants::ED25519_BASEPOINT_POINT.Z);
assert_eq!(minus_basepoint.T, -(&constants::ED25519_BASEPOINT_POINT.T));
}
/// Test that computing 1*basepoint gives the correct basepoint.
@ -1512,7 +1344,7 @@ mod test {
/// using basepoint + basepoint versus the 2*basepoint constant.
#[test]
fn basepoint_plus_basepoint_vs_basepoint2() {
let bp = constants::ED25519_BASEPOINT;
let bp = constants::ED25519_BASEPOINT_POINT;
let bp_added = &bp + &bp;
assert_eq!(bp_added.compress_edwards(), BASE2_CMPRSSD);
}
@ -1521,7 +1353,7 @@ mod test {
/// using the basepoint, basepoint2 constants
#[test]
fn basepoint_plus_basepoint_projective_niels_vs_basepoint2() {
let bp = constants::ED25519_BASEPOINT;
let bp = constants::ED25519_BASEPOINT_POINT;
let bp_added = (&bp + &bp.to_projective_niels()).to_extended();
assert_eq!(bp_added.compress_edwards(), BASE2_CMPRSSD);
}
@ -1530,7 +1362,7 @@ mod test {
/// using the basepoint, basepoint2 constants
#[test]
fn basepoint_plus_basepoint_affine_niels_vs_basepoint2() {
let bp = constants::ED25519_BASEPOINT;
let bp = constants::ED25519_BASEPOINT_POINT;
let bp_affine_niels = bp.to_affine_niels();
let bp_added = (&bp + &bp_affine_niels).to_extended();
assert_eq!(bp_added.compress_edwards(), BASE2_CMPRSSD);
@ -1581,7 +1413,7 @@ mod test {
#[test]
#[cfg(feature="basepoint_table_creation")]
fn test_precomputed_basepoint_mult() {
let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT);
let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT_POINT);
let aB_1 = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR;
let aB_2 = &table * &A_SCALAR;
assert_eq!(aB_1.compress_edwards(), aB_2.compress_edwards());
@ -1590,14 +1422,14 @@ mod test {
/// Test scalar_mult versus a known scalar multiple from ed25519.py
#[test]
fn scalar_mult_vs_ed25519py() {
let aB = &constants::ED25519_BASEPOINT * &A_SCALAR;
let aB = &constants::ED25519_BASEPOINT_POINT * &A_SCALAR;
assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT);
}
/// Test basepoint.double() versus the 2*basepoint constant.
#[test]
fn basepoint_double_vs_basepoint2() {
assert_eq!(constants::ED25519_BASEPOINT.double().compress_edwards(),
assert_eq!(constants::ED25519_BASEPOINT_POINT.double().compress_edwards(),
BASE2_CMPRSSD);
}
@ -1612,7 +1444,7 @@ mod test {
/// Check that converting to projective and then back to extended round-trips.
#[test]
fn basepoint_projective_extended_round_trip() {
assert_eq!(constants::ED25519_BASEPOINT
assert_eq!(constants::ED25519_BASEPOINT_POINT
.to_projective().to_extended().compress_edwards(),
constants::BASE_CMPRSSD);
}
@ -1620,7 +1452,7 @@ mod test {
/// Test computing 16*basepoint vs mult_by_pow_2(4)
#[test]
fn basepoint16_vs_mult_by_pow_2_4() {
let bp16 = constants::ED25519_BASEPOINT.mult_by_pow_2(4);
let bp16 = constants::ED25519_BASEPOINT_POINT.mult_by_pow_2(4);
assert_eq!(bp16.compress_edwards(), BASE16_CMPRSSD);
}
@ -1629,7 +1461,7 @@ mod test {
fn conditional_assign_for_affine_niels_point() {
let id = AffineNielsPoint::identity();
let mut p1 = AffineNielsPoint::identity();
let bp = constants::ED25519_BASEPOINT.to_affine_niels();
let bp = constants::ED25519_BASEPOINT_POINT.to_affine_niels();
p1.conditional_assign(&bp, 0);
assert_eq!(p1, id);
@ -1640,7 +1472,7 @@ mod test {
#[test]
fn is_small_order() {
// The basepoint has large prime order
assert!(constants::ED25519_BASEPOINT.is_small_order() == false);
assert!(constants::ED25519_BASEPOINT_POINT.is_small_order() == false);
// constants::EIGHT_TORSION has all points of small order.
for torsion_point in &constants::EIGHT_TORSION {
assert!(torsion_point.is_small_order() == true);
@ -1656,7 +1488,7 @@ mod test {
#[test]
fn is_identity() {
assert!( ExtendedPoint::identity().is_identity() == true);
assert!(constants::ED25519_BASEPOINT.is_identity() == false);
assert!(constants::ED25519_BASEPOINT_POINT.is_identity() == false);
}
/// Rust's debug builds have overflow and underflow trapping,
@ -1671,7 +1503,7 @@ mod test {
/// the type system and prove correctness).
#[test]
fn monte_carlo_overflow_underflow_debug_assert_test() {
let mut P = constants::ED25519_BASEPOINT;
let mut P = constants::ED25519_BASEPOINT_POINT;
// N.B. each scalar_mult does 1407 field mults, 1024 field squarings,
// so this does ~ 1M of each operation.
for _ in 0..1_000 {
@ -1681,7 +1513,7 @@ mod test {
#[test]
fn scalarmult_extended_point_works_both_ways() {
let G: ExtendedPoint = constants::ED25519_BASEPOINT;
let G: ExtendedPoint = constants::ED25519_BASEPOINT_POINT;
let s: Scalar = A_SCALAR;
let P1 = &G * &s;
@ -1693,7 +1525,7 @@ mod test {
#[test]
#[cfg(feature = "yolocrypto")]
fn scalarmult_decafpoint_works_both_ways() {
let P: DecafPoint = DecafPoint(constants::ED25519_BASEPOINT);
let P: DecafPoint = DecafPoint(constants::ED25519_BASEPOINT_POINT);
let s: Scalar = A_SCALAR;
let P1 = &P * &s;
@ -1719,7 +1551,7 @@ mod test {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result = vartime::multiscalar_mult(
&[A_SCALAR, B_SCALAR],
&[A, constants::ED25519_BASEPOINT]
&[A, constants::ED25519_BASEPOINT_POINT]
);
assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT);
}
@ -1729,11 +1561,11 @@ mod test {
let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result_vartime = vartime::multiscalar_mult(
&[A_SCALAR, B_SCALAR],
&[A, constants::ED25519_BASEPOINT]
&[A, constants::ED25519_BASEPOINT_POINT]
);
let result_consttime = multiscalar_mult(
&[A_SCALAR, B_SCALAR],
&[A, constants::ED25519_BASEPOINT]
&[A, constants::ED25519_BASEPOINT_POINT]
);
assert_eq!(result_vartime.compress_edwards(), result_consttime.compress_edwards());
@ -1746,7 +1578,7 @@ mod test {
#[test]
#[cfg(feature = "serde")]
fn serde_cbor_basepoint_roundtrip() {
let output = serde_cbor::to_vec(&constants::ED25519_BASEPOINT).unwrap();
let output = serde_cbor::to_vec(&constants::ED25519_BASEPOINT_POINT).unwrap();
let parsed: ExtendedPoint = serde_cbor::from_slice(&output).unwrap();
assert_eq!(parsed.compress_edwards(), constants::BASE_CMPRSSD);
}
@ -1754,7 +1586,7 @@ mod test {
#[test]
#[cfg(feature = "serde")]
fn serde_cbor_decode_invalid_fails() {
let mut output = serde_cbor::to_vec(&constants::ED25519_BASEPOINT).unwrap();
let mut output = serde_cbor::to_vec(&constants::ED25519_BASEPOINT_POINT).unwrap();
// CBOR apparently has two bytes of overhead for a 32-byte string.
// Set the low byte of the compressed point to 1 to make it invalid.
output[2] = 1;
@ -1783,7 +1615,7 @@ mod bench {
#[bench]
fn edwards_compress(b: &mut Bencher) {
let B = &constants::ED25519_BASEPOINT;
let B = &constants::ED25519_BASEPOINT_POINT;
b.iter(|| B.compress_edwards());
}
@ -1795,7 +1627,7 @@ mod bench {
#[bench]
fn scalar_mult(b: &mut Bencher) {
let B = &constants::ED25519_BASEPOINT;
let B = &constants::ED25519_BASEPOINT_POINT;
b.iter(|| B * &A_SCALAR);
}
@ -1806,53 +1638,53 @@ mod bench {
#[bench]
fn add_extended_and_projective_niels_output_completed(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT;
let p2 = constants::ED25519_BASEPOINT.to_projective_niels();
let p1 = constants::ED25519_BASEPOINT_POINT;
let p2 = constants::ED25519_BASEPOINT_POINT.to_projective_niels();
b.iter(|| &p1 + &p2);
}
#[bench]
fn add_extended_and_projective_niels_output_extended(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT;
let p2 = constants::ED25519_BASEPOINT.to_projective_niels();
let p1 = constants::ED25519_BASEPOINT_POINT;
let p2 = constants::ED25519_BASEPOINT_POINT.to_projective_niels();
b.iter(|| (&p1 + &p2).to_extended());
}
#[bench]
fn add_extended_and_affine_niels_output_completed(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT;
let p2 = constants::ED25519_BASEPOINT.to_affine_niels();
let p1 = constants::ED25519_BASEPOINT_POINT;
let p2 = constants::ED25519_BASEPOINT_POINT.to_affine_niels();
b.iter(|| &p1 + &p2);
}
#[bench]
fn add_extended_and_affine_niels_output_extended(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT;
let p2 = constants::ED25519_BASEPOINT.to_affine_niels();
let p1 = constants::ED25519_BASEPOINT_POINT;
let p2 = constants::ED25519_BASEPOINT_POINT.to_affine_niels();
b.iter(|| (&p1 + &p2).to_extended());
}
#[bench]
fn projective_double_output_completed(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT.to_projective();
let p1 = constants::ED25519_BASEPOINT_POINT.to_projective();
b.iter(|| p1.double());
}
#[bench]
fn extended_double_output_extended(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT;
let p1 = constants::ED25519_BASEPOINT_POINT;
b.iter(|| p1.double());
}
#[bench]
fn mult_by_cofactor(b: &mut Bencher) {
let p1 = constants::ED25519_BASEPOINT;
let p1 = constants::ED25519_BASEPOINT_POINT;
b.iter(|| p1.mult_by_cofactor());
}

View file

@ -72,7 +72,8 @@ mod field_32bit;
mod field_64bit;
pub mod scalar;
pub mod curve;
pub mod edwards;
pub mod montgomery;
// Feature gate decaf while our implementation is unfinished and probably incorrect.
#[cfg(feature = "yolocrypto")]

203
src/montgomery.rs Normal file
View file

@ -0,0 +1,203 @@
// -*- mode: rust; -*-
//
// To the extent possible under law, the authors have waived all copyright and
// related or neighboring rights to curve25519-dalek, using the Creative
// Commons "CC0" public domain dedication. See
// <http://creativecommons.org/publicdomain/zero/.0/> for full details.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Montgomery arithmetic prototype, subject to revision.
// We allow non snake_case names because coordinates in projective space are
// traditionally denoted by the capitalisation of their respective
// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my
// affine and projective cakes and eat both of them too.
#![allow(non_snake_case)]
use constants;
use field::FieldElement;
use edwards::{ExtendedPoint, CompressedEdwardsY};
use subtle::ConditionallyAssignable;
/// In "Montgomery u" format, as used in X25519, a point `(u,v)` on
/// the Montgomery curve
///
/// v^2 = u * (u^2 + 486662*u + 1)
///
/// is represented just by `u`. Note that we use `(u,v)` instead of
/// `(x,y)` for Montgomery coordinates to avoid confusion with Edwards
/// coordinates. For Montgomery curves, it is possible to compute the
/// `u`-coordinate of `n(u,v)` just from `n` and `u`, so it is not
/// necessary to use `v` for a Diffie-Hellman key exchange.
///
/// XXX add note on monty, twist security, edwards impl of x25519, rfc7748
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CompressedMontgomeryU(pub [u8; 32]);
impl CompressedMontgomeryU {
/// View this `CompressedMontgomeryU` as an array of bytes.
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
/// Attempt to decompress to an `ExtendedPoint`.
///
/// # Note
///
/// Since there are two curve points with the same
/// `u`-coordinate, the `u`-coordinate does not fully specify a
/// point. That is, roundtripping between an `ExtendedPoint` and
/// a `CompressedMontgomeryU` discards its sign bit.
///
/// # Warning
///
/// This function is *not* constant time.
///
/// # Return
///
/// An `Option<ExtendedPoint>`, which will be `None` if either condition holds:
///
/// * `u = -1`, or
/// * `v` is not square.
//
// XXX any other exceptional points for the birational map?
pub fn decompress(&self) -> Option<ExtendedPoint> {
let u: FieldElement = FieldElement::from_bytes(&self.0);
// If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660.
// But 486660 is nonsquare mod p, so this is not a curve point.
//
// Note: currently, without this check, u = -1 will accidentally
// decode to a valid (but incorrect) point, since 0.invert() = 0.
if u == FieldElement::minus_one() {
return None;
}
let y: FieldElement = CompressedMontgomeryU::to_edwards_y(&u); // y = (u-1)/(u+1)
// XXX this does two inversions: the above + one in .decompress()
// is it possible to do one?
CompressedEdwardsY(y.to_bytes()).decompress()
}
/// Given a Montgomery `u` coordinate, compute an Edwards `y` via
/// `y = (u-1)/(u+1)`.
///
/// # Return
///
/// A `FieldElement` corresponding to this coordinate, but in Edwards form.
pub fn to_edwards_y(u: &FieldElement) -> FieldElement {
// Since `u = (1+y)/(1-y)` and `v = √(u(u²+Au+1))`, so `y = (u-1)/(u+1)`.
&(u - &FieldElement::one()) * &(u + &FieldElement::one()).invert()
}
/// Given a Montgomery `u` coordinate, compute the corresponding
/// Montgomery `v` coordinate by computing the right-hand side of
/// the Montgomery field equation, `v² = u(u² + Au +1)`.
///
/// # Return
///
/// A tuple of (`u8`, `FieldElement`), where the `u8` is `1` if the v² was
/// actually a square and `0` if otherwise, along with a `FieldElement`: the
/// Montgomery `v` corresponding to this `u`.
pub fn to_montgomery_v(u: &FieldElement) -> (u8, FieldElement) {
let one: FieldElement = FieldElement::one();
let v_squared: FieldElement = u * &(&u.square() + &(&(&constants::A * u) + &one));
let (okay, v_inv) = v_squared.invsqrt();
let v = &v_inv * &v_squared;
(okay, v)
}
/// Given Montgomery coordinates `(u, v)`, recover the Edwards `x` coordinate.
///
/// # Inputs
///
/// * `u` and `v` are both `&FieldElement`s, corresponding the the `(u, v)`
/// coordinates of this `CompressedMontgomeryU`.
/// * `sign` is an &u8.
///
/// ## Explanation of choice of `sign`
///
/// ### Original Signal behaviour:
///
/// - `1u8` will leave `x` negative if it is negative, and will negate
/// `x` if it is positive, and
/// - `0u8` will leave `x` positive if it is positive, and will negate
/// `x` if it is negative.
///
/// Hence, if `sign` is `1u8`, the returned `x` will be negative.
/// Otherwise, if `sign` is `0u8`, the returned `x` will be positive.
///
/// # Return
///
/// A `FieldElement`, the Edwards `x` coordinate, by using `(u, v)` to
/// convert from Montgomery to Edwards form via the right-hand side of the
/// equation: `x=(u/v)*sqrt(-A-2)`.
pub fn to_edwards_x(u: &FieldElement, v: &FieldElement, sign: &u8) -> FieldElement {
let mut x: FieldElement = &(u * &v.invert()) * &constants::SQRT_MINUS_APLUS2;
let neg_x: FieldElement = -(&x);
let current_sign: u8 = x.is_negative_ed25519();
// Negate x to match the sign:
x.conditional_assign(&neg_x, current_sign ^ sign);
x
}
}
// ------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------
#[cfg(test)]
mod test {
use edwards::Identity;
use super::*;
/// The X25519 basepoint, in compressed Montgomery form.
static BASE_CMPRSSD_MONTY: CompressedMontgomeryU =
CompressedMontgomeryU([0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
/// Test Montgomery conversion against the X25519 basepoint.
#[test]
fn basepoint_to_montgomery() {
assert_eq!(constants::ED25519_BASEPOINT_POINT.compress_montgomery().unwrap(),
BASE_CMPRSSD_MONTY);
}
/// Test Montgomery conversion against the X25519 basepoint.
#[test]
fn basepoint_from_montgomery() {
assert_eq!(BASE_CMPRSSD_MONTY.decompress().unwrap().compress_edwards(),
constants::BASE_CMPRSSD);
}
/// If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660.
/// But 486660 is nonsquare mod p, so this should fail.
///
/// XXX what does Signal do here?
#[test]
fn u_minus_one_monty() {
let minus_one = FieldElement::minus_one();
let minus_one_bytes = minus_one.to_bytes();
let div_by_zero_u = CompressedMontgomeryU(minus_one_bytes);
assert!(div_by_zero_u.decompress().is_none());
}
/// Montgomery compression of the identity point should
/// fail (it's sent to infinity).
#[test]
fn identity_to_monty() {
let id = ExtendedPoint::identity();
assert!(id.compress_montgomery().is_none());
}
}