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 cc30d7f..c56dd25 100644 --- a/src/curve.rs +++ b/src/curve.rs @@ -826,27 +826,8 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a 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`. @@ -873,7 +854,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; @@ -894,21 +875,26 @@ 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 - } - - fn basepoint_mult(scalar: &Scalar) -> ExtendedPoint { - constants::ED25519_BASEPOINT_TABLE.basepoint_mult(scalar) +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 } } @@ -1286,7 +1272,7 @@ 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); } @@ -1338,7 +1324,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(), @@ -1348,14 +1334,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()); } @@ -1364,10 +1351,9 @@ 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 @@ -1388,7 +1374,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); } @@ -1454,7 +1440,7 @@ 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 { @@ -1499,13 +1485,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 * &A_SCALAR); + let B = &constants::ED25519_BASEPOINT; + b.iter(|| B * &A_SCALAR); } #[bench] @@ -1569,7 +1556,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)); } @@ -1590,8 +1577,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 6e4d2c6..1023b26 100644 --- a/src/decaf.rs +++ b/src/decaf.rs @@ -40,7 +40,6 @@ use std::boxed::Box; use curve; use curve::ExtendedPoint; use curve::EdwardsBasepointTable; -use curve::BasepointMult; use curve::Identity; use scalar::Scalar; @@ -265,22 +264,17 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a DecafPoint { } } -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)) - } -} - - /// 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`. @@ -289,11 +283,6 @@ impl DecafBasepointTable { let edwards_table = EdwardsBasepointTable::create(&basepoint.0); box DecafBasepointTable(*edwards_table) } - - /// Use the precomputed table to quickly compute `scalar * basepoint` - pub fn basepoint_mult(&self, scalar: &Scalar) -> DecafPoint { - DecafPoint(self.0.basepoint_mult(scalar)) - } } // ------------------------------------------------------------------------ @@ -350,7 +339,6 @@ mod test { use constants; use curve::CompressedEdwardsY; use curve::ExtendedPoint; - use curve::BasepointMult; use curve::Identity; use super::*; @@ -376,17 +364,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])); @@ -396,8 +384,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])); @@ -407,27 +395,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"))] @@ -440,8 +415,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()); } @@ -449,8 +424,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()); } }