Merge remote-tracking branch 'isislovecruft/develop' into develop

This commit is contained in:
Isis Lovecruft 2017-03-13 21:52:20 +00:00
commit 65136a202a
Failed to extract signature
4 changed files with 170 additions and 250 deletions

View file

@ -1574,19 +1574,12 @@ pub const base: [[AffineNielsPoint; 8]; 32] = [
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use field::FieldElement; use field::FieldElement;
use curve::AffineNielsPoint;
use curve::CompressedEdwardsY;
use curve::ExtendedPoint;
use curve::Identity;
use curve::IsIdentity; use curve::IsIdentity;
use curve::ValidityCheck; use curve::ValidityCheck;
use constants; use constants;
#[test] #[test]
fn test_eight_torsion() { fn test_eight_torsion() {
let mut bytes = [0;32];
bytes[0] = 1;
let compressed_id = CompressedEdwardsY(bytes);
for i in 0..8 { for i in 0..8 {
let Q = constants::EIGHT_TORSION[i].mult_by_pow_2(3); let Q = constants::EIGHT_TORSION[i].mult_by_pow_2(3);
assert!(Q.is_valid()); assert!(Q.is_valid());
@ -1596,9 +1589,6 @@ mod test {
#[test] #[test]
fn test_four_torsion() { fn test_four_torsion() {
let mut bytes = [0;32];
bytes[0] = 1;
let compressed_id = CompressedEdwardsY(bytes);
for i in (0..8).filter(|i| i % 2 == 0) { for i in (0..8).filter(|i| i % 2 == 0) {
let Q = constants::EIGHT_TORSION[i].mult_by_pow_2(2); let Q = constants::EIGHT_TORSION[i].mult_by_pow_2(2);
assert!(Q.is_valid()); assert!(Q.is_valid());
@ -1608,9 +1598,6 @@ mod test {
#[test] #[test]
fn test_two_torsion() { fn test_two_torsion() {
let mut bytes = [0;32];
bytes[0] = 1;
let compressed_id = CompressedEdwardsY(bytes);
for i in (0..8).filter(|i| i % 4 == 0) { for i in (0..8).filter(|i| i % 4 == 0) {
let Q = constants::EIGHT_TORSION[i].mult_by_pow_2(1); let Q = constants::EIGHT_TORSION[i].mult_by_pow_2(1);
assert!(Q.is_valid()); assert!(Q.is_valid());
@ -1625,6 +1612,16 @@ mod test {
assert_eq!(one, &two * &constants::HALF); assert_eq!(one, &two * &constants::HALF);
} }
#[test]
/// Test that the constant for sqrt(-486664) really is a square
/// root of -486664.
fn sqrt_minus_aplus2() {
let minus_aplus2 = FieldElement([-486664,0,0,0,0,0,0,0,0,0]);
let sqrt = constants::SQRT_MINUS_APLUS2;
let sq = &sqrt * &sqrt;
assert_eq!(sq, minus_aplus2);
}
#[test] #[test]
/// Test that SQRT_M1 and MSQRT_M1 are square roots of -1 /// Test that SQRT_M1 and MSQRT_M1 are square roots of -1
fn test_sqrt_minus_one() { fn test_sqrt_minus_one() {
@ -1682,12 +1679,12 @@ mod test {
let mut P = bp; let mut P = bp;
for i in 0..32 { for i in 0..32 {
// P = (16^2)^i * B // P = (16^2)^i * B
let mut jP = P.to_precomputed(); let mut jP = P.to_affine_niels();
for j in 1..9 { for j in 1..9 {
// constants::base[i][j-1] is supposed to be // constants::base[i][j-1] is supposed to be
// j * (16^2)^i * B // j * (16^2)^i * B
assert_eq!(constants::base[i][j-1], jP); assert_eq!(constants::base[i][j-1], jP);
jP = (&P + &jP).to_extended().to_precomputed(); jP = (&P + &jP).to_extended().to_affine_niels();
} }
P = P.mult_by_pow_2(8); P = P.mult_by_pow_2(8);
} }

View file

@ -80,7 +80,6 @@
use core::fmt::Debug; use core::fmt::Debug;
use core::iter::Iterator; use core::iter::Iterator;
use core::ops::{Add, Sub, Neg}; use core::ops::{Add, Sub, Neg};
use core::cmp::{PartialEq, Eq};
use constants; use constants;
use field::FieldElement; use field::FieldElement;
@ -201,6 +200,8 @@ impl CompressedMontgomeryU {
let y: FieldElement = CompressedMontgomeryU::to_edwards_y(&u); // y = (u-1)/(u+1) 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() CompressedEdwardsY(y.to_bytes()).decompress()
} }
@ -210,7 +211,7 @@ impl CompressedMontgomeryU {
/// # Return /// # Return
/// ///
/// A `FieldElement` corresponding to this coordinate, but in Edwards form. /// A `FieldElement` corresponding to this coordinate, but in Edwards form.
fn to_edwards_y(u: &FieldElement) -> FieldElement { 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)`. // 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() &(u - &FieldElement::one()) * &(u + &FieldElement::one()).invert()
} }
@ -224,12 +225,9 @@ impl CompressedMontgomeryU {
/// A tuple of (`u8`, `FieldElement`), where the `u8` is `1` if the v² was /// 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 /// actually a square and `0` if otherwise, along with a `FieldElement`: the
/// Montgomery `v` corresponding to this `u`. /// Montgomery `v` corresponding to this `u`.
fn to_montgomery_v(u: &FieldElement) -> (u8, FieldElement) { pub fn to_montgomery_v(u: &FieldElement) -> (u8, FieldElement) {
let one: FieldElement = FieldElement::one(); let one: FieldElement = FieldElement::one();
let v_squared: FieldElement = u * &(&(&u.square() + &(&(&constants::A * u) + &one))); let v_squared: FieldElement = u * &(&(&u.square() + &(&(&constants::A * u) + &one)));
let v_inv: FieldElement;
let v: FieldElement;
let okay: u8;
let (okay, v_inv) = v_squared.invsqrt(); let (okay, v_inv) = v_squared.invsqrt();
let v = &v_inv * &v_squared; let v = &v_inv * &v_squared;
@ -262,7 +260,7 @@ impl CompressedMontgomeryU {
/// A `FieldElement`, the Edwards `x` coordinate, by using `(u, v)` to /// A `FieldElement`, the Edwards `x` coordinate, by using `(u, v)` to
/// convert from Montgomery to Edwards form via the right-hand side of the /// convert from Montgomery to Edwards form via the right-hand side of the
/// equation: `x=(u/v)*sqrt(-A-2)`. /// equation: `x=(u/v)*sqrt(-A-2)`.
fn to_edwards_x(u: &FieldElement, v: &FieldElement, sign: &u8) -> FieldElement { pub fn to_edwards_x(u: &FieldElement, v: &FieldElement, sign: &u8) -> FieldElement {
let mut x: FieldElement = &(u * &v.invert()) * &constants::SQRT_MINUS_APLUS2; let mut x: FieldElement = &(u * &v.invert()) * &constants::SQRT_MINUS_APLUS2;
let neg_x: FieldElement = -(&x); let neg_x: FieldElement = -(&x);
let current_sign: u8 = x.is_negative_ed25519(); let current_sign: u8 = x.is_negative_ed25519();
@ -544,7 +542,7 @@ impl ProjectivePoint {
impl ExtendedPoint { impl ExtendedPoint {
/// Convert to a ProjectiveNielsPoint /// Convert to a ProjectiveNielsPoint
pub fn to_cached(&self) -> ProjectiveNielsPoint { pub fn to_projective_niels(&self) -> ProjectiveNielsPoint {
ProjectiveNielsPoint{ ProjectiveNielsPoint{
Y_plus_X: &self.Y + &self.X, Y_plus_X: &self.Y + &self.X,
Y_minus_X: &self.Y - &self.X, Y_minus_X: &self.Y - &self.X,
@ -568,7 +566,7 @@ impl ExtendedPoint {
/// Dehomogenize to a AffineNielsPoint. /// Dehomogenize to a AffineNielsPoint.
/// Mainly for testing. /// Mainly for testing.
pub fn to_precomputed(&self) -> AffineNielsPoint { pub fn to_affine_niels(&self) -> AffineNielsPoint {
let recip = self.Z.invert(); let recip = self.Z.invert();
let x = &self.X * &recip; let x = &self.X * &recip;
let y = &self.Y * &recip; let y = &self.Y * &recip;
@ -738,14 +736,14 @@ impl<'a,'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint {
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 {
(self + &other.to_cached()).to_extended() (self + &other.to_projective_niels()).to_extended()
} }
} }
impl<'a,'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint { impl<'a,'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint {
type Output = ExtendedPoint; type Output = ExtendedPoint;
fn sub(self, other: &'b ExtendedPoint) -> ExtendedPoint { fn sub(self, other: &'b ExtendedPoint) -> ExtendedPoint {
(self - &other.to_cached()).to_extended() (self - &other.to_projective_niels()).to_extended()
} }
} }
@ -804,10 +802,10 @@ impl ScalarMult<Scalar> for ExtendedPoint {
/// Uses a window of size 4. Note: for scalar multiplication of /// Uses a window of size 4. Note: for scalar multiplication of
/// the basepoint, `basepoint_mult` is approximately 4x faster. /// the basepoint, `basepoint_mult` is approximately 4x faster.
fn scalar_mult(&self, scalar: &Scalar) -> ExtendedPoint { fn scalar_mult(&self, scalar: &Scalar) -> ExtendedPoint {
let A = self.to_cached(); let A = self.to_projective_niels();
let mut As: [ProjectiveNielsPoint; 8] = [A; 8]; let mut As: [ProjectiveNielsPoint; 8] = [A; 8];
for i in 0..7 { for i in 0..7 {
As[i+1] = (self + &As[i]).to_extended().to_cached(); As[i+1] = (self + &As[i]).to_extended().to_projective_niels();
} }
let e = scalar.to_radix_16(); let e = scalar.to_radix_16();
let mut h = ExtendedPoint::identity(); let mut h = ExtendedPoint::identity();
@ -938,9 +936,9 @@ pub fn double_scalar_mult_vartime(a: &Scalar, A: &ExtendedPoint, b: &Scalar) ->
// Build a lookup table of odd multiples of A // Build a lookup table of odd multiples of A
let mut Ai = [ProjectiveNielsPoint::identity(); 8]; let mut Ai = [ProjectiveNielsPoint::identity(); 8];
let A2 = A.double(); let A2 = A.double();
Ai[0] = A.to_cached(); Ai[0] = A.to_projective_niels();
for i in 0..7 { for i in 0..7 {
Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_cached(); Ai[i+1] = (&A2 + &Ai[i]).to_extended().to_projective_niels();
} }
// Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A]
@ -1076,16 +1074,11 @@ impl Debug for ProjectiveNielsPoint {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use test::Bencher;
use rand::OsRng;
use field::FieldElement; use field::FieldElement;
use scalar::Scalar; use scalar::Scalar;
use subtle::CTAssignable; use subtle::CTAssignable;
use constants; use constants;
use constants::BASE_CMPRSSD;
use super::*; use super::*;
use super::select_precomputed_point;
/// The X25519 basepoint, in compressed Montgomery form. /// The X25519 basepoint, in compressed Montgomery form.
static BASE_CMPRSSD_MONTY: CompressedMontgomeryU = static BASE_CMPRSSD_MONTY: CompressedMontgomeryU =
@ -1100,12 +1093,14 @@ mod test {
[0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, [0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69,
0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21]; 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21];
/// Compressed Edwards Y form of 2*basepoint.
static BASE2_CMPRSSD: CompressedEdwardsY = static BASE2_CMPRSSD: CompressedEdwardsY =
CompressedEdwardsY([0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0xe, CompressedEdwardsY([0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0xe,
0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97,
0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d,
0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22]); 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22]);
/// Compressed Edwards Y form of 16*basepoint.
static BASE16_CMPRSSD: CompressedEdwardsY = static BASE16_CMPRSSD: CompressedEdwardsY =
CompressedEdwardsY([0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, CompressedEdwardsY([0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8,
0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0,
@ -1113,58 +1108,46 @@ mod test {
0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70]); 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70]);
/// 4493907448824000747700850167940867464579944529806937181821189941592931634714 /// 4493907448824000747700850167940867464579944529806937181821189941592931634714
static A_SCALAR: Scalar = Scalar([ pub static A_SCALAR: Scalar = Scalar([
0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d,
0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d, 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d,
0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1,
0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09]); 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09]);
/// 2506056684125797857694181776241676200180934651973138769173342316833279714961 /// 2506056684125797857694181776241676200180934651973138769173342316833279714961
static B_SCALAR: Scalar = Scalar([ pub static B_SCALAR: Scalar = Scalar([
0x91, 0x26, 0x7a, 0xcf, 0x25, 0xc2, 0x09, 0x1b, 0x91, 0x26, 0x7a, 0xcf, 0x25, 0xc2, 0x09, 0x1b,
0xa2, 0x17, 0x74, 0x7b, 0x66, 0xf0, 0xb3, 0x2e, 0xa2, 0x17, 0x74, 0x7b, 0x66, 0xf0, 0xb3, 0x2e,
0x9d, 0xf2, 0xa5, 0x67, 0x41, 0xcf, 0xda, 0xc4, 0x9d, 0xf2, 0xa5, 0x67, 0x41, 0xcf, 0xda, 0xc4,
0x56, 0xa7, 0xd4, 0xaa, 0xb8, 0x60, 0x8a, 0x05]); 0x56, 0xa7, 0xd4, 0xaa, 0xb8, 0x60, 0x8a, 0x05]);
/// A_SCALAR * basepoint, computed with ed25519.py /// A_SCALAR * basepoint, computed with ed25519.py
static A_TIMES_BASEPOINT: CompressedEdwardsY = CompressedEdwardsY([ pub static A_TIMES_BASEPOINT: CompressedEdwardsY = CompressedEdwardsY([
0xea, 0x27, 0xe2, 0x60, 0x53, 0xdf, 0x1b, 0x59, 0xea, 0x27, 0xe2, 0x60, 0x53, 0xdf, 0x1b, 0x59,
0x56, 0xf1, 0x4d, 0x5d, 0xec, 0x3c, 0x34, 0xc3, 0x56, 0xf1, 0x4d, 0x5d, 0xec, 0x3c, 0x34, 0xc3,
0x84, 0xa2, 0x69, 0xb7, 0x4c, 0xc3, 0x80, 0x3e, 0x84, 0xa2, 0x69, 0xb7, 0x4c, 0xc3, 0x80, 0x3e,
0xa8, 0xe2, 0xe7, 0xc9, 0x42, 0x5e, 0x40, 0xa5]); 0xa8, 0xe2, 0xe7, 0xc9, 0x42, 0x5e, 0x40, 0xa5]);
/// A_SCALAR * (A_TIMES_BASEPOINT) + B_SCALAR * BASEPOINT /// A_SCALAR * (A_TIMES_BASEPOINT) + B_SCALAR * BASEPOINT
/// computed with ed25519.py
static DOUBLE_SCALAR_MULT_RESULT: CompressedEdwardsY = CompressedEdwardsY([ static DOUBLE_SCALAR_MULT_RESULT: CompressedEdwardsY = CompressedEdwardsY([
0x7d, 0xfd, 0x6c, 0x45, 0xaf, 0x6d, 0x6e, 0x0e, 0x7d, 0xfd, 0x6c, 0x45, 0xaf, 0x6d, 0x6e, 0x0e,
0xba, 0x20, 0x37, 0x1a, 0x23, 0x64, 0x59, 0xc4, 0xba, 0x20, 0x37, 0x1a, 0x23, 0x64, 0x59, 0xc4,
0xc0, 0x46, 0x83, 0x43, 0xde, 0x70, 0x4b, 0x85, 0xc0, 0x46, 0x83, 0x43, 0xde, 0x70, 0x4b, 0x85,
0x09, 0x6f, 0xfe, 0x35, 0x4f, 0x13, 0x2b, 0x42]); 0x09, 0x6f, 0xfe, 0x35, 0x4f, 0x13, 0x2b, 0x42]);
/// Test Montgomery conversion against the X25519 basepoint.
#[test] #[test]
/// Test that the constant for sqrt(-486664) really is a square fn basepoint_to_montgomery() {
/// root of -486664. assert_eq!(constants::BASEPOINT.compress_montgomery().unwrap(),
/// XXX this should be a test in constants.rs ?? BASE_CMPRSSD_MONTY);
fn test_sqrt_minus_aplus2() {
let minus_aplus2 = FieldElement([-486664,0,0,0,0,0,0,0,0,0]);
let sqrt = constants::SQRT_MINUS_APLUS2;
let sq = &sqrt * &sqrt;
assert_eq!(sq, minus_aplus2);
} }
/// Test Montgomery conversion against the X25519 basepoint. /// Test Montgomery conversion against the X25519 basepoint.
#[test] #[test]
fn test_basepoint_to_montgomery() { fn basepoint_from_montgomery() {
let bp = BASE_CMPRSSD.decompress().unwrap(); assert_eq!(BASE_CMPRSSD_MONTY.decompress().unwrap().compress_edwards(),
let bp_monty = bp.compress_montgomery().unwrap(); constants::BASE_CMPRSSD);
assert_eq!(bp_monty, BASE_CMPRSSD_MONTY);
}
/// Test Montgomery conversion against the X25519 basepoint.
#[test]
fn test_basepoint_from_montgomery() {
let bp = BASE_CMPRSSD_MONTY.decompress().unwrap();
let bp_compressed_edwards = bp.compress_edwards();
assert_eq!(bp_compressed_edwards, BASE_CMPRSSD);
} }
/// If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660. /// If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660.
@ -1172,7 +1155,7 @@ mod test {
/// ///
/// XXX what does Signal do here? /// XXX what does Signal do here?
#[test] #[test]
fn test_u_minus_one_monty() { fn u_minus_one_monty() {
let mut m1 = FieldElement::zero(); let mut m1 = FieldElement::zero();
m1[0] = -1; m1[0] = -1;
let m1_bytes = m1.to_bytes(); let m1_bytes = m1.to_bytes();
@ -1183,125 +1166,117 @@ mod test {
/// Montgomery compression of the identity point should /// Montgomery compression of the identity point should
/// fail (it's sent to infinity). /// fail (it's sent to infinity).
#[test] #[test]
fn test_identity_to_monty() { fn identity_to_monty() {
let id = ExtendedPoint::identity(); let id = ExtendedPoint::identity();
assert!(id.compress_montgomery().is_none()); assert!(id.compress_montgomery().is_none());
} }
/// Test round-trip decompression for the basepoint. /// Test round-trip decompression for the basepoint.
#[test] #[test]
fn test_basepoint_decompression_compression() { fn basepoint_decompression_compression() {
let base_X = FieldElement::from_bytes(&BASE_X_COORD_BYTES); let base_X = FieldElement::from_bytes(&BASE_X_COORD_BYTES);
let bp = BASE_CMPRSSD.decompress().unwrap(); let bp = constants::BASE_CMPRSSD.decompress().unwrap();
let bp2 = BASE2_CMPRSSD.decompress().unwrap(); assert!(bp.is_valid());
assert!( bp.is_valid());
assert!(bp2.is_valid());
let compressed = bp.compress_edwards();
let compressed2 = bp2.compress_edwards();
// Check that decompression actually gives the correct X coordinate // Check that decompression actually gives the correct X coordinate
assert_eq!(base_X, bp.X); assert_eq!(base_X, bp.X);
assert_eq!(compressed, BASE_CMPRSSD); assert_eq!(bp.compress_edwards(), constants::BASE_CMPRSSD);
assert_eq!(compressed2, BASE2_CMPRSSD);
} }
/// Test sign handling in decompression /// Test sign handling in decompression
#[test] #[test]
fn test_decompression_sign_handling() { fn decompression_sign_handling() {
let mut m_bp_bytes: [u8;32] = BASE_CMPRSSD.as_bytes().clone(); // Manually set the high bit of the last byte to flip the sign
// Set the high bit of the last byte to flip the sign let mut minus_basepoint_bytes = constants::BASE_CMPRSSD.as_bytes().clone();
m_bp_bytes[31] |= 1 << 7; minus_basepoint_bytes[31] |= 1 << 7;
let m_bp = CompressedEdwardsY(m_bp_bytes).decompress().unwrap(); let minus_basepoint = CompressedEdwardsY(minus_basepoint_bytes)
let bp = BASE_CMPRSSD.decompress().unwrap(); .decompress().unwrap();
assert_eq!(m_bp.X, -(&bp.X)); // Test projective coordinates exactly since we know they should
assert_eq!(m_bp.Y, bp.Y); // only differ by a flipped sign.
assert_eq!(m_bp.Z, bp.Z); assert_eq!(minus_basepoint.X, -(&constants::BASEPOINT.X));
assert_eq!(m_bp.T, -(&bp.T)); assert_eq!(minus_basepoint.Y, constants::BASEPOINT.Y);
assert_eq!(minus_basepoint.Z, constants::BASEPOINT.Z);
assert_eq!(minus_basepoint.T, -(&constants::BASEPOINT.T));
} }
/// Test that computing 1*basepoint gives the correct basepoint. /// Test that computing 1*basepoint gives the correct basepoint.
#[test] #[test]
fn test_basepoint_mult_one_vs_basepoint() { fn basepoint_mult_one_vs_basepoint() {
let bp = ExtendedPoint::basepoint_mult(&Scalar::one()); let bp = ExtendedPoint::basepoint_mult(&Scalar::one());
let compressed = bp.compress_edwards(); let compressed = bp.compress_edwards();
assert_eq!(compressed, BASE_CMPRSSD); assert_eq!(compressed, constants::BASE_CMPRSSD);
} }
/// Test `impl Add<ExtendedPoint> for ExtendedPoint` /// Test `impl Add<ExtendedPoint> for ExtendedPoint`
/// using basepoint + basepoint versus the 2*basepoint constant. /// using basepoint + basepoint versus the 2*basepoint constant.
#[test] #[test]
fn test_basepoint_plus_basepoint() { fn basepoint_plus_basepoint_vs_basepoint2() {
let bp = BASE_CMPRSSD.decompress().unwrap(); let bp = constants::BASEPOINT;
let bp_added = &bp + &bp; let bp_added = &bp + &bp;
assert_eq!( bp_added.compress_edwards(), BASE2_CMPRSSD); assert_eq!(bp_added.compress_edwards(), BASE2_CMPRSSD);
} }
/// Test `impl Add<ProjectiveNielsPoint> for ExtendedPoint` /// Test `impl Add<ProjectiveNielsPoint> for ExtendedPoint`
/// using the basepoint, basepoint2 constants /// using the basepoint, basepoint2 constants
#[test] #[test]
fn test_basepoint_plus_basepoint_cached() { fn basepoint_plus_basepoint_projective_niels_vs_basepoint2() {
let bp = BASE_CMPRSSD.decompress().unwrap(); let bp = constants::BASEPOINT;
let bp_added = (&bp + &bp.to_cached()).to_extended(); let bp_added = (&bp + &bp.to_projective_niels()).to_extended();
assert_eq!( bp_added.compress_edwards(), BASE2_CMPRSSD); assert_eq!(bp_added.compress_edwards(), BASE2_CMPRSSD);
} }
/// Test `impl Add<AffineNielsPoint> for ExtendedPoint` /// Test `impl Add<AffineNielsPoint> for ExtendedPoint`
/// using the basepoint, basepoint2 constants /// using the basepoint, basepoint2 constants
#[test] #[test]
fn test_basepoint_plus_basepoint_precomputed() { fn basepoint_plus_basepoint_affine_niels_vs_basepoint2() {
let bp = BASE_CMPRSSD.decompress().unwrap(); let bp = constants::BASEPOINT;
// on decode, Z =1, so x = X/Z = X, y = Y/Z = Y, xy = T let bp_affine_niels = bp.to_affine_niels();
let bp_precomputed = AffineNielsPoint{ let bp_added = (&bp + &bp_affine_niels).to_extended();
y_plus_x: &bp.Y + &bp.X, assert_eq!(bp_added.compress_edwards(), BASE2_CMPRSSD);
y_minus_x: &bp.Y - &bp.X,
xy2d: &bp.T * &constants::d2,
};
let bp_added = (&bp + &bp_precomputed).to_extended();
assert_eq!( bp_added.compress_edwards(), BASE2_CMPRSSD);
} }
/// Check that equality of `ExtendedPoints` handles projective
/// coordinates correctly.
#[test] #[test]
fn test_extended_point_equality() { fn extended_point_equality_handles_scaling() {
let two = [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, let mut two_bytes = [0u8; 32]; two_bytes[0] = 2;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
let id1 = ExtendedPoint::identity(); let id1 = ExtendedPoint::identity();
let id2 = ExtendedPoint{ let id2 = ExtendedPoint{
X: FieldElement::zero(), X: FieldElement::zero(),
Y: FieldElement::from_bytes(&two), Y: FieldElement::from_bytes(&two_bytes),
Z: FieldElement::from_bytes(&two), Z: FieldElement::from_bytes(&two_bytes),
T: FieldElement::zero()}; T: FieldElement::zero()
};
assert!(id1.ct_eq(&id2) == 1u8); assert!(id1.ct_eq(&id2) == 1u8);
} }
/// Sanity check for conversion to precomputed points /// Sanity check for conversion to precomputed points
#[test] #[test]
fn test_convert_to_precomputed() { fn to_affine_niels_clears_denominators() {
// construct a point as aB so it has denominators (ie. Z != 1) // construct a point as aB so it has denominators (ie. Z != 1)
let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); let aB = ExtendedPoint::basepoint_mult(&A_SCALAR);
let aB_pc = aB.to_precomputed(); let aB_affine_niels = aB.to_affine_niels();
let id = ExtendedPoint::identity(); let also_aB = (&ExtendedPoint::identity() + &aB_affine_niels).to_extended();
let P = &id + &aB_pc; assert_eq!( aB.compress_edwards(),
assert_eq!(P.to_extended().compress_edwards(), aB.compress_edwards()) also_aB.compress_edwards());
} }
/// Test basepoint_mult versus a known scalar multiple from ed25519.py /// Test basepoint_mult versus a known scalar multiple from ed25519.py
#[test] #[test]
fn test_basepoint_mult() { fn basepoint_mult_vs_ed25519py() {
let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); let aB = ExtendedPoint::basepoint_mult(&A_SCALAR);
assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT); assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT);
} }
/// Test scalar_mult versus a known scalar multiple from ed25519.py /// Test scalar_mult versus a known scalar multiple from ed25519.py
#[test] #[test]
fn test_scalar_mult() { fn scalar_mult_vs_ed25519py() {
let bp = BASE_CMPRSSD.decompress().unwrap(); let aB = constants::BASEPOINT.scalar_mult(&A_SCALAR);
let aB = bp.scalar_mult(&A_SCALAR);
assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT); assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT);
} }
/// Test double_scalar_mult_vartime vs ed25519.py /// Test double_scalar_mult_vartime vs ed25519.py
#[test] #[test]
fn test_double_scalar_mult_vartime() { fn double_scalar_mult_vartime_vs_ed25519py() {
let A = A_TIMES_BASEPOINT.decompress().unwrap(); let A = A_TIMES_BASEPOINT.decompress().unwrap();
let result = double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR); let result = double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR);
assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT); assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT);
@ -1309,118 +1284,88 @@ mod test {
/// Test basepoint.double() versus the 2*basepoint constant. /// Test basepoint.double() versus the 2*basepoint constant.
#[test] #[test]
fn test_basepoint_double() { fn basepoint_double_vs_basepoint2() {
let bp = BASE_CMPRSSD.decompress().unwrap(); assert_eq!(constants::BASEPOINT.double().compress_edwards(),
let bp_doubled = bp.double(); BASE2_CMPRSSD);
assert_eq!(bp_doubled.compress_edwards(), BASE2_CMPRSSD);
} }
/// Test that computing 2*basepoint is the same as basepoint.double() /// Test that computing 2*basepoint is the same as basepoint.double()
#[test] #[test]
fn test_scalar_mult_two_vs_double() { fn basepoint_mult_two_vs_basepoint2() {
// XXX this seems like a pain point: better way to construct small let mut two_bytes = [0u8; 32]; two_bytes[0] = 2;
// scalars? let bp2 = ExtendedPoint::basepoint_mult(&Scalar(two_bytes));
let two = Scalar([ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, assert_eq!(bp2.compress_edwards(), BASE2_CMPRSSD);
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]);
let bp = BASE_CMPRSSD.decompress().unwrap();
let bp_doubled = bp.double();
let bp2 = ExtendedPoint::basepoint_mult(&two);
assert_eq!(bp_doubled.compress_edwards(), bp2.compress_edwards());
} }
/// Check that converting to projective and then back to extended round-trips.
#[test] #[test]
fn test_basepoint_projective_extended_round_trip() { fn basepoint_projective_extended_round_trip() {
let bp = BASE_CMPRSSD.decompress().unwrap(); assert_eq!(constants::BASEPOINT.to_projective().to_extended().compress_edwards(),
let bp_roundtrip = bp.to_projective().to_extended(); constants::BASE_CMPRSSD);
assert_eq!(BASE_CMPRSSD, bp_roundtrip.compress_edwards());
} }
/// Test computing 16*basepoint vs mult_by_pow_2 /// Test computing 16*basepoint vs mult_by_pow_2(4)
#[test] #[test]
fn test_mult_by_pow_2() { fn basepoint16_vs_mult_by_pow_2_4() {
let bp = BASE_CMPRSSD.decompress().unwrap(); let bp16 = constants::BASEPOINT.mult_by_pow_2(4);
let bp16 = bp.mult_by_pow_2(4);
assert_eq!(bp16.compress_edwards(), BASE16_CMPRSSD); assert_eq!(bp16.compress_edwards(), BASE16_CMPRSSD);
} }
/// The basepoint, doubled, minus the basepoint should equal the basepoint. /// Test that the conditional assignment trait works for AffineNielsPoints.
#[test] #[test]
fn test_ge_sub() { fn conditional_assign_for_affine_niels_point() {
let p1: ExtendedPoint = BASE_CMPRSSD.decompress().unwrap();
let p2: ExtendedPoint = BASE2_CMPRSSD.decompress().unwrap();
let p3: ExtendedPoint = (&p2 - &p1.to_cached()).to_extended();
assert_eq!(p1.compress_edwards(), p3.compress_edwards());
}
/// The basepoint plus the identity should equal the basepoint.
#[test]
fn test_ge_add() {
let p1: ExtendedPoint = BASE_CMPRSSD.decompress().unwrap();
let p2: ExtendedPoint = ExtendedPoint::identity();
let p3: ExtendedPoint = (&p1 + &p2.to_cached()).to_extended();
assert_eq!(p1.compress_edwards(), p3.compress_edwards());
}
#[test]
fn test_AffineNielsPoint_conditional_assign() {
let id = AffineNielsPoint::identity(); let id = AffineNielsPoint::identity();
let mut p1 = AffineNielsPoint::identity(); let mut p1 = AffineNielsPoint::identity();
let p2: AffineNielsPoint = AffineNielsPoint{ let bp = constants::BASEPOINT.to_affine_niels();
y_plus_x: FieldElement([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
y_minus_x: FieldElement([11, 22, 33, 44, 55, 66, 77, 88, 99, 100]),
xy2d: FieldElement([10, 20, 30, 40, 50, 60, 70, 80, 90, 101]),
};
p1.conditional_assign(&p2, 0); p1.conditional_assign(&bp, 0);
assert_eq!(p1.y_plus_x, id.y_plus_x); assert_eq!(p1, id);
assert_eq!(p1.y_minus_x, id.y_minus_x); p1.conditional_assign(&bp, 1);
assert_eq!(p1.xy2d, id.xy2d); assert_eq!(p1, bp);
p1.conditional_assign(&p2, 1);
assert_eq!(p1.y_plus_x, p2.y_plus_x);
assert_eq!(p1.y_minus_x, p2.y_minus_x);
assert_eq!(p1.xy2d, p2.xy2d);
} }
#[test] #[test]
fn test_is_small_order() { fn is_small_order() {
let p1: ExtendedPoint = ExtendedPoint::identity(); // The basepoint has large prime order
let p2: ExtendedPoint = BASE_CMPRSSD.decompress().unwrap(); assert!(constants::BASEPOINT.is_small_order() == false);
// constants::EIGHT_TORSION has all points of small order.
assert!(p1.is_small_order() == true); for torsion_point in &constants::EIGHT_TORSION {
assert!(p2.is_small_order() == false); assert!(torsion_point.is_small_order() == true);
}
} }
#[test] #[test]
fn test_compressed_identity() { fn compressed_identity() {
assert_eq!(ExtendedPoint::identity().compress_edwards(), assert_eq!(ExtendedPoint::identity().compress_edwards(),
CompressedEdwardsY::identity()); CompressedEdwardsY::identity());
} }
#[test] #[test]
fn test_is_identity() { fn is_identity() {
assert!(ExtendedPoint::identity().is_identity()); assert!(ExtendedPoint::identity().is_identity() == true);
assert!( constants::BASEPOINT.is_identity() == false);
} }
}
#[test] // ------------------------------------------------------------------------
fn test_montgomery_u_is_neg_one_rejected() { // Benchmarks
let fe_u: FieldElement = FieldElement::minus_one(); // ------------------------------------------------------------------------
let u: CompressedMontgomeryU = CompressedMontgomeryU(fe_u.to_bytes());
let result: Option<ExtendedPoint> = u.decompress();
assert!(result.is_none()); #[cfg(test)]
} mod bench {
use test::Bencher;
use constants;
use super::*;
use super::test::{A_SCALAR, A_TIMES_BASEPOINT, B_SCALAR};
#[bench] #[bench]
fn bench_basepoint_mult(b: &mut Bencher) { fn basepoint_mult(b: &mut Bencher) {
b.iter(|| ExtendedPoint::basepoint_mult(&A_SCALAR)); b.iter(|| ExtendedPoint::basepoint_mult(&A_SCALAR));
} }
#[bench] #[bench]
fn bench_scalar_mult(b: &mut Bencher) { fn scalar_mult(b: &mut Bencher) {
let bp = BASE_CMPRSSD.decompress().unwrap(); let bp = constants::BASEPOINT;
b.iter(|| bp.scalar_mult(&A_SCALAR)); b.iter(|| bp.scalar_mult(&A_SCALAR));
} }
@ -1430,77 +1375,61 @@ mod test {
} }
#[bench] #[bench]
fn bench_double_scalar_mult_vartime(bench: &mut Bencher) { fn bench_double_scalar_mult_vartime(b: &mut Bencher) {
let A = A_TIMES_BASEPOINT.decompress().unwrap(); let A = A_TIMES_BASEPOINT.decompress().unwrap();
bench.iter(|| double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR)); b.iter(|| double_scalar_mult_vartime(&A_SCALAR, &A, &B_SCALAR));
} }
#[bench] #[bench]
fn bench_extended_add_cached(b: &mut Bencher) { fn add_extended_and_cached_output_completed(b: &mut Bencher) {
let p1 = BASE_CMPRSSD.decompress().unwrap(); let p1 = constants::BASEPOINT;
let p2 = BASE2_CMPRSSD.decompress().unwrap().to_cached(); let p2 = constants::BASEPOINT.to_projective_niels();
b.iter(| | &p1 + &p2); b.iter(|| &p1 + &p2);
} }
#[bench] #[bench]
fn bench_extended_add_cached_to_extended(b: &mut Bencher) { fn add_extended_and_cached_output_extended(b: &mut Bencher) {
let p1 = BASE_CMPRSSD.decompress().unwrap(); let p1 = constants::BASEPOINT;
let p2 = BASE2_CMPRSSD.decompress().unwrap().to_cached(); let p2 = constants::BASEPOINT.to_projective_niels();
b.iter(| | (&p1 + &p2).to_extended()); b.iter(|| (&p1 + &p2).to_extended());
} }
#[bench] #[bench]
fn bench_extended_add_precomputed(b: &mut Bencher) { fn add_extended_and_precomputed_output_completed(b: &mut Bencher) {
let p1 = BASE_CMPRSSD.decompress().unwrap(); let p1 = constants::BASEPOINT;
let p2 = select_precomputed_point(6, &constants::base[27]); let p2 = select_precomputed_point(6, &constants::base[27]);
b.iter(| | &p1 + &p2); b.iter(|| &p1 + &p2);
} }
#[bench] #[bench]
fn bench_extended_add_precomputed_to_extended(b: &mut Bencher) { fn add_extended_and_precomputed_output_extended(b: &mut Bencher) {
let p1 = BASE_CMPRSSD.decompress().unwrap(); let p1 = constants::BASEPOINT;
let p2 = select_precomputed_point(6, &constants::base[27]); let p2 = select_precomputed_point(6, &constants::base[27]);
b.iter(| | (&p1 + &p2).to_extended()); b.iter(|| (&p1 + &p2).to_extended());
} }
#[bench] #[bench]
fn bench_double(b: &mut Bencher) { fn projective_double_output_completed(b: &mut Bencher) {
let p1 = BASE_CMPRSSD.decompress().unwrap().to_projective(); let p1 = constants::BASEPOINT.to_projective();
b.iter(| | p1.double() ); b.iter(|| p1.double() );
} }
#[bench] #[bench]
fn bench_double_to_extended(b: &mut Bencher) { fn extended_double_output_extended(b: &mut Bencher) {
let p1 = BASE_CMPRSSD.decompress().unwrap().to_projective(); let p1 = constants::BASEPOINT;
b.iter(| | p1.double().to_extended() ); b.iter(|| p1.double() );
} }
#[bench] #[bench]
fn bench_mult_by_pow2_4(b: &mut Bencher) { fn mult_by_cofactor(b: &mut Bencher) {
let p1 = BASE_CMPRSSD.decompress().unwrap(); let p1 = constants::BASEPOINT;
b.iter(| | p1.mult_by_pow_2(4) ); b.iter(|| p1.mult_by_cofactor() );
}
#[bench]
fn bench_compress_edwards(b: &mut Bencher) {
let mut rng: OsRng = OsRng::new().unwrap();
let p1: ExtendedPoint = ExtendedPoint::basepoint_mult(&Scalar::random(&mut rng));
b.iter(| | p1.compress_edwards() );
}
#[bench]
fn bench_compress_montgomery(b: &mut Bencher) {
let mut rng: OsRng = OsRng::new().unwrap();
let p1: ExtendedPoint = ExtendedPoint::basepoint_mult(&Scalar::random(&mut rng));
b.iter(| | p1.compress_montgomery() );
} }
} }

View file

@ -289,7 +289,6 @@ mod test {
use scalar::Scalar; use scalar::Scalar;
use constants; use constants;
use constants::BASE_CMPRSSD;
use curve::CompressedEdwardsY; use curve::CompressedEdwardsY;
use curve::ExtendedPoint; use curve::ExtendedPoint;
use curve::BasepointMult; use curve::BasepointMult;
@ -297,28 +296,27 @@ mod test {
use super::*; use super::*;
#[test] #[test]
#[should_panic] fn decaf_decompress_negative_s_fails() {
fn test_decaf_decompress_negative_s_fails() {
// constants::d is neg, so decompression should fail as |d| != d. // constants::d is neg, so decompression should fail as |d| != d.
let bad_compressed = CompressedDecaf(constants::d.to_bytes()); let bad_compressed = CompressedDecaf(constants::d.to_bytes());
bad_compressed.decompress().unwrap(); assert!(bad_compressed.decompress().is_none());
} }
#[test] #[test]
fn test_decaf_decompress_id() { fn decaf_decompress_id() {
let compressed_id = CompressedDecaf::identity(); let compressed_id = CompressedDecaf::identity();
let id = compressed_id.decompress().unwrap(); let id = compressed_id.decompress().unwrap();
assert_eq!(id.0.compress_edwards(), CompressedEdwardsY::identity()); assert_eq!(id.0.compress_edwards(), CompressedEdwardsY::identity());
} }
#[test] #[test]
fn test_decaf_compress_id() { fn decaf_compress_id() {
let id = DecafPoint::identity(); let id = DecafPoint::identity();
assert_eq!(id.compress(), CompressedDecaf::identity()); assert_eq!(id.compress(), CompressedDecaf::identity());
} }
#[test] #[test]
fn test_decaf_basepoint_roundtrip() { fn decaf_basepoint_roundtrip() {
let bp_compressed_decaf = DecafPoint::basepoint().compress(); let bp_compressed_decaf = DecafPoint::basepoint().compress();
let bp_recaf = bp_compressed_decaf.decompress().unwrap().0; let bp_recaf = bp_compressed_decaf.decompress().unwrap().0;
// Check that bp_recaf differs from bp by a point of order 4 // Check that bp_recaf differs from bp by a point of order 4
@ -328,7 +326,7 @@ mod test {
} }
#[test] #[test]
fn test_decaf_four_torsion_basepoint() { fn decaf_four_torsion_basepoint() {
let bp = DecafPoint::basepoint(); let bp = DecafPoint::basepoint();
let bp_coset = bp.coset4(); let bp_coset = bp.coset4();
for i in 0..4 { for i in 0..4 {
@ -337,7 +335,7 @@ mod test {
} }
#[test] #[test]
fn test_decaf_four_torsion_random() { fn decaf_four_torsion_random() {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
let s = Scalar::random(&mut rng); let s = Scalar::random(&mut rng);
let P = DecafPoint::basepoint_mult(&s); let P = DecafPoint::basepoint_mult(&s);
@ -348,17 +346,15 @@ mod test {
} }
#[test] #[test]
fn test_decaf_random_roundtrip() { fn decaf_random_roundtrip() {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
for j in 0..100 { for _ in 0..100 {
let s = Scalar::random(&mut rng); let s = Scalar::random(&mut rng);
let P = DecafPoint::basepoint_mult(&s); let P = DecafPoint::basepoint_mult(&s);
let compressed_P = P.compress(); let compressed_P = P.compress();
let Q = compressed_P.decompress().unwrap(); let Q = compressed_P.decompress().unwrap();
for i in 0..4 {
assert_eq!(P, Q); assert_eq!(P, Q);
} }
}
} }
} }

View file

@ -37,7 +37,6 @@ use core::fmt::Debug;
use rand::Rng; use rand::Rng;
use digest::Digest; use digest::Digest;
use generic_array::GenericArray;
use generic_array::typenum::U64; use generic_array::typenum::U64;
use constants; use constants;
@ -593,7 +592,6 @@ impl UnpackedScalar {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use rand::Rng;
use rand::OsRng; use rand::OsRng;
use super::*; use super::*;
use test::Bencher; use test::Bencher;