diff --git a/Cargo.toml b/Cargo.toml index c164472..556dd79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,12 +36,10 @@ version = "^0.6" version = "0.4" [features] -nightly = ["basepoint_table_creation", "radix_51"] +nightly = ["radix_51"] default = ["std"] std = ["rand"] yolocrypto = [] -# Needs nightly for placement new -basepoint_table_creation = [] bench = [] # Radix-51 arithmetic using u128 radix_51 = [] diff --git a/src/constants.rs b/src/constants.rs index 50879da..2d3c790 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -24,6 +24,8 @@ use curve::ExtendedPoint; use curve::AffineNielsPoint; use curve::CompressedEdwardsY; use curve::EdwardsBasepointTable; +#[cfg(feature = "yolocrypto")] +use decaf::{DecafPoint, DecafBasepointTable}; use scalar::Scalar; #[cfg(feature="radix_51")] @@ -136,6 +138,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); + /// Basepoint has y = 4/5. #[cfg(not(feature="radix_51"))] pub const ED25519_BASEPOINT: ExtendedPoint = ExtendedPoint{ @@ -384,6 +390,11 @@ pub const bi: [AffineNielsPoint; 8] = [ } ]; +#[cfg(feature = "yolocrypto")] +/// The Ed25519 basepoint +pub const DECAF_ED25519_BASEPOINT_TABLE: DecafBasepointTable + = DecafBasepointTable(ED25519_BASEPOINT_TABLE); + /// 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`, diff --git a/src/curve.rs b/src/curve.rs index 05153c1..daab17d 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -79,7 +79,9 @@ use core::fmt::Debug; use core::iter::Iterator; -use core::ops::{Add, Sub, Neg, Index}; +use core::ops::{Add, Sub, Neg}; +use core::ops::{Mul, MulAssign}; +use core::ops::Index; use constants; use field::FieldElement; @@ -90,11 +92,6 @@ use subtle::CTAssignable; use subtle::CTEq; use subtle::CTNegatable; -#[cfg(all(not(feature = "std"), feature = "basepoint_table_creation"))] -use collections::boxed::Box; -#[cfg(all(feature = "std", feature = "basepoint_table_creation"))] -use std::boxed::Box; - // ------------------------------------------------------------------------ // Compressed points // ------------------------------------------------------------------------ @@ -789,18 +786,20 @@ impl<'a> Neg for &'a AffineNielsPoint { // Scalar multiplication // ------------------------------------------------------------------------ -/// Trait for scalar multiplication of an arbitrary point. -pub trait ScalarMult { - /// Compute `scalar * self`. - fn scalar_mult(&self, scalar: &S) -> Self; +impl<'b> MulAssign<&'b Scalar> for ExtendedPoint { + fn mul_assign(&mut self, scalar: &'b Scalar) { + let result = (self as &ExtendedPoint) * scalar; + *self = result; + } } -impl ScalarMult for ExtendedPoint { +impl<'a, 'b> Mul<&'b Scalar> for &'a ExtendedPoint { + type Output = ExtendedPoint; /// Scalar multiplication: compute `scalar * self`. /// /// Uses a window of size 4. Note: for scalar multiplication of /// the basepoint, `basepoint_mult` is approximately 4x faster. - fn scalar_mult(&self, scalar: &Scalar) -> ExtendedPoint { + fn mul(self, scalar: &'b Scalar) -> ExtendedPoint { let A = self.to_projective_niels(); let mut As: [ProjectiveNielsPoint; 8] = [A; 8]; for i in 0..7 { @@ -822,27 +821,8 @@ impl ScalarMult for ExtendedPoint { #[derive(Clone)] pub struct EdwardsBasepointTable(pub [[AffineNielsPoint; 8]; 32]); -impl EdwardsBasepointTable { - /// Create a table of precomputed multiples of `basepoint`. - #[cfg(feature="basepoint_table_creation")] - pub fn create(basepoint: &ExtendedPoint) -> Box { - // Create the table storage - // XXX can we be assured that this is not allocated on the stack? - // XXX can we skip the initialization without too much unsafety? - let mut table = box EdwardsBasepointTable([[AffineNielsPoint::identity(); 8]; 32]); - let mut P = basepoint.clone(); - for i in 0..32 { - // P = (16^2)^i * B - let mut jP = P.to_affine_niels(); - for j in 1..9 { - // table[i][j-1] is supposed to be j*(16^2)^i*B - table.0[i][j-1] = jP; - jP = (&P + &jP).to_extended().to_affine_niels(); - } - P = P.mult_by_pow_2(8); - } - return table - } +impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { + type Output = ExtendedPoint; /// Construct an `ExtendedPoint` from a `Scalar`, `scalar`, by /// computing the multiple `aB` of the basepoint `B`. @@ -869,7 +849,7 @@ impl EdwardsBasepointTable { /// 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. - pub fn basepoint_mult(&self, scalar: &Scalar) -> ExtendedPoint { + fn mul(self, scalar: &'b Scalar) -> ExtendedPoint { let e = scalar.to_radix_16(); let mut h = ExtendedPoint::identity(); let mut t: CompletedPoint; @@ -890,21 +870,32 @@ impl EdwardsBasepointTable { } } -/// Trait for scalar multiplication of a distinguished basepoint. -pub trait BasepointMult { - /// Return the basepoint `B`. - fn basepoint() -> Self; - /// Compute `scalar * B`. - fn basepoint_mult(scalar: &S) -> Self; -} - -impl BasepointMult for ExtendedPoint { - fn basepoint() -> ExtendedPoint { - constants::ED25519_BASEPOINT +impl EdwardsBasepointTable { + /// Create a table of precomputed multiples of `basepoint`. + pub fn create(basepoint: &ExtendedPoint) -> EdwardsBasepointTable { + // Create the table storage + // XXX can we skip the initialization without too much unsafety? + // stick 30K on the stack and call it a day. + let mut table = EdwardsBasepointTable([[AffineNielsPoint::identity(); 8]; 32]); + let mut P = basepoint.clone(); + for i in 0..32 { + // P = (16^2)^i * B + let mut jP = P.to_affine_niels(); + for j in 1..9 { + // table[i][j-1] is supposed to be j*(16^2)^i*B + table.0[i][j-1] = jP; + jP = (&P + &jP).to_extended().to_affine_niels(); + } + P = P.mult_by_pow_2(8); + } + table } - fn basepoint_mult(scalar: &Scalar) -> ExtendedPoint { - constants::ED25519_BASEPOINT_TABLE.basepoint_mult(scalar) + /// Get the basepoint for this table as an `ExtendedPoint`. + pub fn basepoint(&self) -> ExtendedPoint { + // self.0[0][0] has 1*(16^2)^0*B, but as an `AffineNielsPoint` + // Add identity to convert to extended. + (&ExtendedPoint::identity() + &self.0[0][0]).to_extended() } } @@ -1075,12 +1066,15 @@ pub mod vartime { /// /// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an /// error to call this function with two vectors of different lengths. - pub fn k_fold_scalar_mult(scalars: &Vec, - points: &Vec) -> ExtendedPoint { - assert_eq!(scalars.len(), points.len()); + pub fn k_fold_scalar_mult<'a,'b,I,J>(scalars: I, points: J) -> ExtendedPoint + where I: IntoIterator, J: IntoIterator + { + //assert_eq!(scalars.len(), points.len()); - let nafs: Vec<_> = scalars.iter().map(|c| c.non_adjacent_form()).collect(); - let odd_multiples: Vec<_> = points.iter().map(|P| OddMultiples::create(&P)).collect(); + let nafs: Vec<_> = scalars.into_iter() + .map(|c| c.non_adjacent_form()).collect(); + let odd_multiples: Vec<_> = points.into_iter() + .map(|P| OddMultiples::create(P)).collect(); let mut r = ProjectivePoint::identity(); @@ -1282,11 +1276,18 @@ mod test { /// Test that computing 1*basepoint gives the correct basepoint. #[test] fn basepoint_mult_one_vs_basepoint() { - let bp = ExtendedPoint::basepoint_mult(&Scalar::one()); + let bp = &constants::ED25519_BASEPOINT_TABLE * &Scalar::one(); let compressed = bp.compress_edwards(); assert_eq!(compressed, constants::BASE_CMPRSSD); } + /// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint. + #[test] + fn basepoint_table_basepoint_function_correct() { + let bp = constants::ED25519_BASEPOINT_TABLE.basepoint(); + assert_eq!(bp.compress_edwards(), constants::BASE_CMPRSSD); + } + /// Test `impl Add for ExtendedPoint` /// using basepoint + basepoint versus the 2*basepoint constant. #[test] @@ -1334,7 +1335,7 @@ mod test { #[test] fn to_affine_niels_clears_denominators() { // construct a point as aB so it has denominators (ie. Z != 1) - let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); + let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; let aB_affine_niels = aB.to_affine_niels(); let also_aB = (&ExtendedPoint::identity() + &aB_affine_niels).to_extended(); assert_eq!( aB.compress_edwards(), @@ -1344,14 +1345,15 @@ mod test { /// Test basepoint_mult versus a known scalar multiple from ed25519.py #[test] fn basepoint_mult_vs_ed25519py() { - let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); + let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT); } /// Test that multiplication by the basepoint order kills the basepoint #[test] fn basepoint_mult_by_basepoint_order() { - let should_be_id = ExtendedPoint::basepoint_mult(&constants::l); + let B = &constants::ED25519_BASEPOINT_TABLE; + let should_be_id = B * &constants::l; assert!(should_be_id.is_identity()); } @@ -1360,16 +1362,15 @@ mod test { #[cfg(feature="basepoint_table_creation")] fn test_precomputed_basepoint_mult() { let table = EdwardsBasepointTable::create(&constants::ED25519_BASEPOINT); - let aB_1 = ExtendedPoint::basepoint_mult(&A_SCALAR); - let aB_2 = table.basepoint_mult(&A_SCALAR); - assert_eq!(aB_1.compress_edwards(), - aB_2.compress_edwards()); + 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()); } /// Test scalar_mult versus a known scalar multiple from ed25519.py #[test] fn scalar_mult_vs_ed25519py() { - let aB = constants::ED25519_BASEPOINT.scalar_mult(&A_SCALAR); + let aB = &constants::ED25519_BASEPOINT * &A_SCALAR; assert_eq!(aB.compress_edwards(), A_TIMES_BASEPOINT); } @@ -1384,7 +1385,7 @@ mod test { #[test] fn basepoint_mult_two_vs_basepoint2() { let mut two_bytes = [0u8; 32]; two_bytes[0] = 2; - let bp2 = ExtendedPoint::basepoint_mult(&Scalar(two_bytes)); + let bp2 = &constants::ED25519_BASEPOINT_TABLE * &Scalar(two_bytes); assert_eq!(bp2.compress_edwards(), BASE2_CMPRSSD); } @@ -1450,11 +1451,11 @@ mod test { /// the type system and prove correctness). #[test] fn monte_carlo_overflow_underflow_debug_assert_test() { - let mut P = ExtendedPoint::basepoint(); + let mut P = constants::ED25519_BASEPOINT; // N.B. each scalar_mult does 1407 field mults, 1024 field squarings, // so this does ~ 1M of each operation. for _ in 0..1_000 { - P = P.scalar_mult(&A_SCALAR); + P *= &A_SCALAR; } } @@ -1473,9 +1474,10 @@ mod test { #[test] fn k_fold_scalar_mult_vs_ed25519py() { let A = A_TIMES_BASEPOINT.decompress().unwrap(); - let points = vec![A,constants::ED25519_BASEPOINT]; - let scalars = vec![A_SCALAR, B_SCALAR]; - let result = vartime::k_fold_scalar_mult(&scalars, &points); + let result = vartime::k_fold_scalar_mult( + &[A_SCALAR, B_SCALAR], + &[A, constants::ED25519_BASEPOINT] + ); assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT); } } @@ -1495,13 +1497,14 @@ mod bench { #[bench] fn basepoint_mult(b: &mut Bencher) { - b.iter(|| ExtendedPoint::basepoint_mult(&A_SCALAR)); + let B = &constants::ED25519_BASEPOINT_TABLE; + b.iter(|| B * &A_SCALAR); } #[bench] fn scalar_mult(b: &mut Bencher) { - let bp = constants::ED25519_BASEPOINT; - b.iter(|| bp.scalar_mult(&A_SCALAR)); + let B = &constants::ED25519_BASEPOINT; + b.iter(|| B * &A_SCALAR); } #[bench] @@ -1565,7 +1568,7 @@ mod bench { #[cfg(feature="basepoint_table_creation")] #[bench] fn create_basepoint_table(b: &mut Bencher) { - let aB = ExtendedPoint::basepoint_mult(&A_SCALAR); + let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; b.iter(|| EdwardsBasepointTable::create(&aB)); } @@ -1586,8 +1589,8 @@ mod bench { // Create 10 random scalars let scalars: Vec<_> = (0..10).map(|_| Scalar::random(&mut csprng)).collect(); // Create 10 points (by doing scalar mults) - let points: Vec<_> = scalars.iter() - .map(|s| ExtendedPoint::basepoint_mult(s)).collect(); + let B = &constants::ED25519_BASEPOINT_TABLE; + let points: Vec<_> = scalars.iter().map(|s| B * &s).collect(); // XXX Currently Rust's benchmarking implementation doesn't // allow you to specify a sequence of random inputs, but only diff --git a/src/decaf.rs b/src/decaf.rs index bb73132..4fba23f 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -30,17 +30,11 @@ use subtle::CTAssignable; use subtle::CTNegatable; use core::ops::{Add, Sub, Neg}; - -#[cfg(all(not(feature = "std"), feature = "basepoint_table_creation"))] -use collections::boxed::Box; -#[cfg(all(feature = "std", feature = "basepoint_table_creation"))] -use std::boxed::Box; +use core::ops::{Mul, MulAssign}; use curve; use curve::ExtendedPoint; use curve::EdwardsBasepointTable; -use curve::BasepointMult; -use curve::ScalarMult; use curve::Identity; use scalar::Scalar; @@ -250,40 +244,42 @@ impl<'a> Neg for &'a DecafPoint { } } -impl ScalarMult for DecafPoint { - fn scalar_mult(&self, scalar: &Scalar) -> DecafPoint { - DecafPoint(self.0.scalar_mult(scalar)) +impl<'b> MulAssign<&'b Scalar> for DecafPoint { + fn mul_assign(&mut self, scalar: &'b Scalar) { + let result = (self as &DecafPoint) * scalar; + *self = result; } } -impl BasepointMult for DecafPoint { - // XXX is this actually in the image of the isogeny, - // or do we need a different basepoint? - fn basepoint() -> DecafPoint { - DecafPoint(ExtendedPoint::basepoint()) - } - - fn basepoint_mult(scalar: &Scalar) -> DecafPoint { - DecafPoint(ExtendedPoint::basepoint_mult(scalar)) +impl<'a, 'b> Mul<&'b Scalar> for &'a DecafPoint { + type Output = DecafPoint; + /// Scalar multiplication: compute `scalar * self`. + fn mul(self, scalar: &'b Scalar) -> DecafPoint { + DecafPoint(&self.0 * scalar) } } - /// Precomputation #[derive(Clone)] -pub struct DecafBasepointTable(EdwardsBasepointTable); +pub struct DecafBasepointTable(pub EdwardsBasepointTable); + +impl<'a, 'b> Mul<&'b Scalar> for &'a DecafBasepointTable { + type Output = DecafPoint; + + fn mul(self, scalar: &'b Scalar) -> DecafPoint { + DecafPoint(&self.0 * scalar) + } +} impl DecafBasepointTable { /// Create a precomputed table of multiples of the given `basepoint`. - #[cfg(feature = "basepoint_table_creation")] - pub fn create(basepoint: &DecafPoint) -> Box { - let edwards_table = EdwardsBasepointTable::create(&basepoint.0); - box DecafBasepointTable(*edwards_table) + pub fn create(basepoint: &DecafPoint) -> DecafBasepointTable { + DecafBasepointTable(EdwardsBasepointTable::create(&basepoint.0)) } - /// Use the precomputed table to quickly compute `scalar * basepoint` - pub fn basepoint_mult(&self, scalar: &Scalar) -> DecafPoint { - DecafPoint(self.0.basepoint_mult(scalar)) + /// Get the basepoint for this table as a `DecafPoint`. + pub fn basepoint(&self) -> DecafPoint { + DecafPoint(self.0.basepoint()) } } @@ -322,10 +318,11 @@ pub mod vartime { /// /// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an /// error to call this function with two vectors of different lengths. - pub fn k_fold_scalar_mult(scalars: &Vec, - points: &Vec) -> DecafPoint { - let extended_points: Vec = points.iter().map(|P| P.0).collect(); - DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, &extended_points)) + pub fn k_fold_scalar_mult<'a,'b,I,J>(scalars: I, points: J) -> DecafPoint + where I: IntoIterator, J: IntoIterator + { + let extended_points = points.into_iter().map(|P| &P.0); + DecafPoint(curve::vartime::k_fold_scalar_mult(scalars, extended_points)) } } @@ -341,7 +338,6 @@ mod test { use constants; use curve::CompressedEdwardsY; use curve::ExtendedPoint; - use curve::BasepointMult; use curve::Identity; use super::*; @@ -367,17 +363,17 @@ mod test { #[test] fn decaf_basepoint_roundtrip() { - let bp_compressed_decaf = DecafPoint::basepoint().compress(); + let bp_compressed_decaf = constants::DECAF_ED25519_BASEPOINT.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 = &ExtendedPoint::basepoint() - &bp_recaf; - let diff4 = diff.mult_by_pow_2(4); + let diff = &constants::ED25519_BASEPOINT - &bp_recaf; + let diff4 = diff.mult_by_pow_2(4); // XXX this is wrong assert_eq!(diff4.compress_edwards(), CompressedEdwardsY::identity()); } #[test] fn decaf_four_torsion_basepoint() { - let bp = DecafPoint::basepoint(); + let bp = constants::DECAF_ED25519_BASEPOINT; let bp_coset = bp.coset4(); for i in 0..4 { assert_eq!(bp, DecafPoint(bp_coset[i])); @@ -387,8 +383,8 @@ mod test { #[test] fn decaf_four_torsion_random() { let mut rng = OsRng::new().unwrap(); - let s = Scalar::random(&mut rng); - let P = DecafPoint::basepoint_mult(&s); + let B = &constants::DECAF_ED25519_BASEPOINT_TABLE; + let P = B * &Scalar::random(&mut rng); let P_coset = P.coset4(); for i in 0..4 { assert_eq!(P, DecafPoint(P_coset[i])); @@ -398,27 +394,14 @@ mod test { #[test] fn decaf_random_roundtrip() { let mut rng = OsRng::new().unwrap(); + let B = &constants::DECAF_ED25519_BASEPOINT_TABLE; for _ in 0..100 { - let s = Scalar::random(&mut rng); - let P = DecafPoint::basepoint_mult(&s); + let P = B * &Scalar::random(&mut rng); let compressed_P = P.compress(); let Q = compressed_P.decompress().unwrap(); assert_eq!(P, Q); } } - - /// Test basepoint_mult versus a newly-generated DecafBasepointTable - #[test] - #[cfg(feature = "basepoint_table_creation")] - fn basepoint_mult_vs_decafbasepointtable() { - let table = DecafBasepointTable::create(&DecafPoint::basepoint()); - let mut rng = OsRng::new().unwrap(); - let s = Scalar::random(&mut rng); - let basepoint_mult_s = DecafPoint::basepoint_mult(&s); - let table_basepoint_mult_s = table.basepoint_mult(&s); - - assert_eq!(basepoint_mult_s, table_basepoint_mult_s); - } } #[cfg(all(test, feature = "bench"))] @@ -431,8 +414,8 @@ mod bench { #[bench] fn decompression(b: &mut Bencher) { let mut rng = OsRng::new().unwrap(); - let s = Scalar::random(&mut rng); - let P = DecafPoint::basepoint_mult(&s); + let B = &constants::DECAF_ED25519_BASEPOINT_TABLE; + let P = B * &Scalar::random(&mut rng); let P_compressed = P.compress(); b.iter(|| P_compressed.decompress().unwrap()); } @@ -440,8 +423,8 @@ mod bench { #[bench] fn compression(b: &mut Bencher) { let mut rng = OsRng::new().unwrap(); - let s = Scalar::random(&mut rng); - let P = DecafPoint::basepoint_mult(&s); + let B = &constants::DECAF_ED25519_BASEPOINT_TABLE; + let P = B * &Scalar::random(&mut rng); b.iter(|| P.compress()); } } diff --git a/src/lib.rs b/src/lib.rs index 31e7177..40efe8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,10 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(collections))] -#![cfg_attr(feature = "nightly", feature(box_syntax))] #![cfg_attr(feature = "nightly", feature(i128_type))] -#![allow(unused_features)] #![cfg_attr(feature = "bench", feature(test))] + +#![allow(unused_features)] #![deny(missing_docs)] // refuse to compile if documentation is missing //! # curve25519-dalek diff --git a/src/scalar.rs b/src/scalar.rs index aca9f2b..90f3931 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -261,6 +261,15 @@ impl Scalar { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) } + /// Construct a scalar from the given `u64`. + pub fn from_u64(x: u64) -> Scalar { + let mut s = Scalar::zero(); + for i in 0..8 { + s[i] = (x >> (i*8)) as u8; + } + s + } + /// Compute the multiplicative inverse of this scalar. pub fn invert(&self) -> Scalar { self.unpack().invert().pack() @@ -727,6 +736,20 @@ mod test { } } + #[test] + fn from_unsigned() { + let val = 0xdeadbeefdeadbeef; + let s = Scalar::from_u64(val); + assert_eq!(s[7], 0xde); + assert_eq!(s[6], 0xad); + assert_eq!(s[5], 0xbe); + assert_eq!(s[4], 0xef); + assert_eq!(s[3], 0xde); + assert_eq!(s[2], 0xad); + assert_eq!(s[1], 0xbe); + assert_eq!(s[0], 0xef); + } + #[test] fn scalar_multiply_by_one() { let one = Scalar::one();