diff --git a/benchmarks/dusk_benchmarks.rs b/benchmarks/dusk_benchmarks.rs index ff6376c9..b3335560 100644 --- a/benchmarks/dusk_benchmarks.rs +++ b/benchmarks/dusk_benchmarks.rs @@ -123,7 +123,7 @@ mod scalar_benches { mod edwards_benches { use super::*; - use zerocaf::edwards::{EdwardsPoint, ProjectivePoint}; + use zerocaf::edwards::{EdwardsPoint, ProjectivePoint, CompressedEdwardsY}; use zerocaf::scalar::Scalar; use zerocaf::field::FieldElement; use subtle::Choice; @@ -159,6 +159,12 @@ mod edwards_benches { /// `A = 182687704666362864775460604089535377456991567872`. pub static A: Scalar = Scalar([0, 0, 0, 2, 0]); + /// `P1_EXTENDED on `CompressedEdwardsY` format. + pub(self) static P1_COMPRESSED: CompressedEdwardsY = CompressedEdwardsY([216, 221, 167, 21, 54, 234, 101, 84, 47, + 55, 89, 137, 7, 175, 226, 87, 240, 1, 227, + 18, 81, 168, 46, 95, 65, 36, 110, 118, 217, + 246, 20, 140]); + pub fn bench_extended_point_ops(c: &mut Criterion) { c.bench( "Extended Coordinates Point Addition", @@ -213,6 +219,20 @@ mod edwards_benches { Choice::from(1u8)))) ); } + + pub fn bench_point_compression_decompression(c: &mut Criterion) { + c.bench( + "Compress/Decompress", + Benchmark::new("Point compression.", + |b| b.iter(|| P1_EXTENDED.compress())) + ); + + c.bench( + "Compress/Decompress", + Benchmark::new("Point decompression.", + |b| b.iter(|| P1_COMPRESSED.decompress().unwrap())) + ); + } } criterion_group!(benchmarks, @@ -220,6 +240,7 @@ criterion_group!(benchmarks, field_benches::bench_modular_inverse, scalar_benches::bench_scalar_element_ops, edwards_benches::bench_extended_point_ops, - edwards_benches::bench_projective_point_ops); + edwards_benches::bench_projective_point_ops, + edwards_benches::bench_point_compression_decompression); //criterion_group!(benchmarks, field_benches::bench_modular_inverse); criterion_main!(benchmarks); \ No newline at end of file diff --git a/src/backend/u64/field.rs b/src/backend/u64/field.rs index 44a1a991..6f8b9a65 100644 --- a/src/backend/u64/field.rs +++ b/src/backend/u64/field.rs @@ -281,7 +281,6 @@ impl Mul for FieldElement { } } - impl<'a,'b> Div<&'a FieldElement> for &'b FieldElement { type Output = FieldElement; /// Performs the op: `x / y (mod l)`. @@ -309,7 +308,6 @@ impl Div for FieldElement { } } - impl<'a> Square for &'a FieldElement { type Output = FieldElement; /// Compute `a^2 (mod l)`. @@ -490,7 +488,10 @@ impl FieldElement { /// Evaluate if a `FieldElement` is even or not. pub fn is_even(self) -> bool { - self.0[0].is_even() + // Compare the last bit of the first limb to check evenness. + // 0b0 -> true + // 0b1 -> false + self.0[0] & 0b01 == 0u64 } pub fn generate_random() -> FieldElement { @@ -1519,4 +1520,12 @@ pub mod tests { assert!(res[i] == INV_MOD_C[i]); } } + + #[test] + fn evenness() { + // Even number should return true. + assert!(A.is_even()); + // Odd number should return false. + assert!(!B.is_even()); + } } diff --git a/src/edwards.rs b/src/edwards.rs index 80702e5e..4ed37a77 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -2,6 +2,70 @@ //! Edwards Point operation implementations and definitions. //! Encoding/decoding processes implementations //! and support for all kind of interactions with them. +//! +//! # Examples +//! ```rust +//! use zerocaf::edwards::*; +//! use zerocaf::traits::ops::*; +//! use zerocaf::traits::Identity; +//! use zerocaf::field::FieldElement; +//! use zerocaf::scalar::Scalar; +//! +//! use subtle::Choice; +//! use core::ops::{Add, Sub, Mul}; +//! +//! // You can work in different point coordinates like +//! // Affine, Projective and Extended ones. +//! // +//! // It's highly recommended to work over Extended ones +//! // since are the fastest. And the ones you can compress +//! // directly. +//! +//! // In order to get a Point over the Doppio curve, +//! // you can do the following: +//! +//! // From a y-coordinate of a point: +//! let y = FieldElement([1799957170131195, 4493955741554471, 4409493758224495, 3389415867291423, 16342693473584]); +//! // The `Choice` specifies the symbol that we want to get as a result +//! // for the `x-coordinate`. +//! let ex_point = EdwardsPoint::new_from_y_coord(&y, Choice::from(0u8)).unwrap(); +//! +//! // Create a random point. +//! let rngp = EdwardsPoint::new_random_point(); +//! +//! // Get it from an AffinePoint or a ProjectivePoint: +//! let exampl = EdwardsPoint::from(&ProjectivePoint::identity()); +//! +//! // The same examples work for the ProjectivePoint struct. +//! +//! // You can perform the following operations with an EdwardsPoint +//! // or a ProjectivePoint: +//! +//! // Point addition: +//! let p1 = &ex_point + &rngp; +//! // Point subtraction (which is a point negation and a sum): +//! let p2 = &ex_point - &rngp; +//! // Point doubling: +//! let p3 = &ex_point.double(); +//! // Scalar mul: +//! let p4 = double_and_add(&ex_point, &Scalar::from(&8u8)); +//! +//! // You can also multiply by the co-factor directly: +//! assert!(p4 == mul_by_cofactor(&ex_point)); +//! +//! // In order to send points saving space, you can use +//! // compressed points, repressented as: `CompressedEwdardsY`. +//! +//! // The only ways of getting a `CompressedEdwardsY` are: +//! // By compressing an `EdwardsPoint`: +//! let cp_point = rngp.compress(); +//! // Note that you can get your EdwardsPoint back just by doing: +//! let decompr_point = &cp_point.decompress().unwrap(); +//! +//! // You can also get a compressed point by copying it from a +//! // slice of bytes (as if it came from a socket or similar situations). +//! let cpedw = CompressedEdwardsY::from_slice(&cp_point.to_bytes()); +//! ``` use crate::field::FieldElement; use crate::scalar::Scalar; @@ -11,7 +75,7 @@ use crate::traits::Identity; use crate::traits::ops::*; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; +use subtle::{Choice, ConstantTimeEq}; use rand::{Rng, thread_rng}; @@ -171,7 +235,7 @@ impl CompressedEdwardsY { /// # Note: /// This function should only be used to get a /// `CompressedEdwardsY` compressed point from - /// a [u8; 31] that we know that is already a + /// a [u8; 32] that we know that is already a /// compressed point. /// /// If this function is used with y-coordinates diff --git a/src/field.rs b/src/field.rs index 33e8b827..cf22c655 100644 --- a/src/field.rs +++ b/src/field.rs @@ -12,6 +12,7 @@ //! use zerocaf::field::FieldElement; //! use zerocaf::traits::ops::*; //! use zerocaf::constants::EDWARDS_D; +//! use subtle::Choice; //! //! // You can create a FieldElement from a byte-array as follows: //! let a = FieldElement::from_bytes(&[0u8;32]); @@ -20,6 +21,9 @@ //! let b = FieldElement::from(&86649u128); //! let c = FieldElement::from(&86650u64); //! +//! // You can create random FieldElements by calling: +//! let rand = FieldElement::generate_random(); +//! //! // The last way of creating a FieldElement it by calling the //! // constructor. THIS IS NOT RECOMMENDED since NO checks about //! // the correctness of the input will be done at all. @@ -34,6 +38,11 @@ //! res = a * b; // Performs a * b (mod l). //! res = a.square(); // Performs a^2 (mod l). //! res = -&a; // Performs Negation over the modulo l. +//! res = a.pow(&b); // Performs Modular exponentiation. +//! res = a.mod_sqrt(Choice::from(1u8)).unwrap(); //Performs +//! // modular sqrt. +//! // Returs `None` if the input is not a QR on the field. +//! // Returns Some(result) if everything is correct. //! //! // Division has been also implemented. Remember that when we write //! // a/b (mod l), we are indeed performing a * inverse_mod(b, l) (mod l). diff --git a/src/scalar.rs b/src/scalar.rs index cff43c5d..c4ed20bb 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -38,7 +38,7 @@ //! res = a.square(); // Performs a^2 (mod l). //! res = -&a; // Performs Negation over the modulo l. //! -//! // Dividing by two even Scalars is recommended through the `Half` +//! // Dividing even Scalars by two is recommended through the `Half` //! // trait implmementation since it's much faster. //! if a.is_even() { //! let half_c = c.half(); // This will panic if a isn't even.