From 2b5c6b493bbd82ed69e2681cb72bf8b88ad0ef56 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 28 Jun 2021 17:10:06 +0700 Subject: [PATCH 01/93] Impl From for BigInt --- src/arithmetic/big_gmp.rs | 6 ++++++ src/arithmetic/big_native.rs | 6 ++++++ src/arithmetic/mod.rs | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/arithmetic/big_gmp.rs b/src/arithmetic/big_gmp.rs index 4526174f..1f90af67 100644 --- a/src/arithmetic/big_gmp.rs +++ b/src/arithmetic/big_gmp.rs @@ -389,6 +389,12 @@ impl ring_algorithm::RingNormalize for BigInt { crate::__bigint_impl_from! { u32, i32, u64 } +impl From for BigInt { + fn from(n: u16) -> Self { + BigInt::from(u64::from(n)) + } +} + /// Internal helper trait. Creates short-hand for wrapping Mpz into BigInt. trait Wrap { fn wrap(self) -> BigInt; diff --git a/src/arithmetic/big_native.rs b/src/arithmetic/big_native.rs index 8ccfd1d8..48706e2d 100644 --- a/src/arithmetic/big_native.rs +++ b/src/arithmetic/big_native.rs @@ -99,6 +99,12 @@ impl num_traits::Num for BigInt { crate::__bigint_impl_from! { u32, i32, u64 } +impl From for BigInt { + fn from(n: u16) -> Self { + BigInt::from(u64::from(n)) + } +} + impl BasicOps for BigInt { fn pow(&self, exponent: u32) -> Self { self.num.pow(exponent).wrap() diff --git a/src/arithmetic/mod.rs b/src/arithmetic/mod.rs index dbda76a7..fb254ea7 100644 --- a/src/arithmetic/mod.rs +++ b/src/arithmetic/mod.rs @@ -356,7 +356,7 @@ mod test { // Conversion traits for<'a> u64: std::convert::TryFrom<&'a BigInt>, for<'a> i64: std::convert::TryFrom<&'a BigInt>, - BigInt: From + From + From, + BigInt: From + From + From + From, // STD Operators BigInt: Add + Sub From d469b0bac311fedbe9dbb8f30562d46b122a8d3d Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 29 Jun 2021 18:34:51 +0300 Subject: [PATCH 02/93] Add Polynomial --- src/cryptographic_primitives/mod.rs | 3 + src/cryptographic_primitives/polynomial.rs | 371 ++++++++++++++++++ .../secret_sharing/feldman_vss.rs | 75 ++-- 3 files changed, 420 insertions(+), 29 deletions(-) create mode 100644 src/cryptographic_primitives/polynomial.rs diff --git a/src/cryptographic_primitives/mod.rs b/src/cryptographic_primitives/mod.rs index 2a868030..8a98644d 100644 --- a/src/cryptographic_primitives/mod.rs +++ b/src/cryptographic_primitives/mod.rs @@ -7,6 +7,9 @@ pub mod commitments; pub mod hashing; +mod polynomial; pub mod proofs; pub mod secret_sharing; pub mod twoparty; + +pub use polynomial::Polynomial; diff --git a/src/cryptographic_primitives/polynomial.rs b/src/cryptographic_primitives/polynomial.rs new file mode 100644 index 00000000..e73f811a --- /dev/null +++ b/src/cryptographic_primitives/polynomial.rs @@ -0,0 +1,371 @@ +use std::convert::TryFrom; +use std::{fmt, iter, ops}; + +use derivative::Derivative; + +use crate::elliptic::curves::traits::{ECPoint, ECScalar}; +use crate::BigInt; + +/// Polynomial of some degree `n` +/// +/// Polynomial has a form: `f(x) = a_0 + a_1 * x^1 + ... + a_(n-1) * x^(n-1) + a_n * x^n`. +/// +/// Coefficients `a_i` and indeterminate `x` are scalars in curve prime field, +/// ie. their type is `ECScalar` implementor. +#[derive(Derivative)] +#[derivative(Clone(bound = "P::Scalar: Clone"))] +#[derivative(Debug(bound = "P::Scalar: fmt::Debug"))] +pub struct Polynomial { + coefficients: Vec, +} + +impl

Polynomial

+where + P: ECPoint, + P::Scalar: Clone, +{ + /// Constructs polynomial `f(x)` from list of coefficients `a`. + /// + /// ## Order + /// + /// `a[i]` should corresponds to coefficient `a_i` of polynomial `f(x) = ... + a_i * x^i + ...` + /// + /// ## Panics + /// + /// Panics if list of coefficients is empty + /// + /// ## Example + /// + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// use curv::elliptic::curves::p256::{GE, FE}; + /// + /// let coefs = vec![ECScalar::new_random(), ECScalar::new_random()]; + /// let poly = Polynomial::::from_coefficients(coefs.clone()); + /// + /// assert_eq!(coefs, poly.coefficients()); + /// ``` + pub fn from_coefficients(coefficients: Vec) -> Self { + assert!( + !coefficients.is_empty(), + "coefficients must have at least one coefficient" + ); + Self { coefficients } + } + + /// Sample a random polynomial of given degree + /// + /// ## Example + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// use curv::elliptic::curves::p256::{GE, FE}; + /// + /// let polynomial = Polynomial::::sample(3); + /// assert_eq!(polynomial.degree(), 3); + /// ``` + /// + pub fn sample(degree: u16) -> Self { + Polynomial { + coefficients: iter::repeat_with(ECScalar::new_random) + .take(usize::from(degree + 1)) + .collect(), + } + } + + /// Samples random polynomial of degree `n` with fixed coefficient `a_0 = coef0` + /// + /// ## Example + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// use curv::elliptic::curves::p256::{GE, FE}; + /// + /// let coef0: FE = ECScalar::new_random(); + /// let polynomial = Polynomial::::sample_fixed_coef0(3, coef0); + /// assert_eq!(polynomial.evaluate(&FE::zero()), coef0); + /// ``` + pub fn sample_fixed_coef0(n: u16, coef0: P::Scalar) -> Self { + let random_coefficients = iter::repeat_with(ECScalar::new_random).take(usize::from(n)); + Polynomial { + coefficients: iter::once(coef0).chain(random_coefficients).collect(), + } + } + + /// Takes scalar `x` and evaluates `f(x)` + /// + /// ## Example + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// # use curv::arithmetic::BigInt; + /// use curv::elliptic::curves::p256::{GE, FE}; + /// + /// let coef0: FE = ECScalar::new_random(); + /// let polynomial = Polynomial::::sample_fixed_coef0(2, coef0); + /// + /// let x: FE = ECScalar::from(&BigInt::from(10)); + /// let y: FE = polynomial.evaluate(&x); + /// + /// let a = polynomial.coefficients(); + /// assert_eq!(y, a[0] + a[1] * x + a[2] * x*x); + /// ``` + pub fn evaluate(&self, point_x: &P::Scalar) -> P::Scalar { + let mut reversed_coefficients = self.coefficients.iter().rev(); + let head = reversed_coefficients + .next() + .expect("at least one coefficient is guaranteed to be present"); + let tail = reversed_coefficients; + tail.fold(head.clone(), |partial, coef| { + let partial_times_point_x = partial * point_x.clone(); + partial_times_point_x + coef.clone() + }) + } + + /// Takes point `x` that's convertable to BigInt, and evaluates `f(x)` + /// + /// ## Example + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// # use curv::arithmetic::BigInt; + /// use curv::elliptic::curves::p256::{GE, FE}; + /// + /// let coef0: FE = ECScalar::new_random(); + /// let polynomial = Polynomial::::sample_fixed_coef0(2, coef0); + /// + /// let x: u16 = 10; + /// let y: FE = polynomial.evaluate_bigint(x); + /// + /// let a = polynomial.coefficients(); + /// let x: FE = ECScalar::from(&BigInt::from(x)); + /// assert_eq!(y, a[0] + a[1] * x + a[2] * x*x); + /// ``` + pub fn evaluate_bigint(&self, point_x: B) -> P::Scalar + where + BigInt: From, + { + self.evaluate(&::from(&BigInt::from(point_x))) + } + + /// Takes list of points `xs` and returns iterator over `f(xs[i])` + /// + /// ## Example + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// # use curv::arithmetic::BigInt; + /// use curv::elliptic::curves::p256::{GE, FE}; + /// + /// let coef0: FE = ECScalar::new_random(); + /// let polynomial = Polynomial::::sample_fixed_coef0(2, coef0); + /// + /// let xs: &[FE] = &[ECScalar::from(&BigInt::from(10)), ECScalar::from(&BigInt::from(11))]; + /// let ys = polynomial.evaluate_many(xs); + /// + /// let a = polynomial.coefficients(); + /// for (y, x) in ys.zip(xs) { + /// assert_eq!(y, a[0] + a[1] * x + a[2] * x*x); + /// } + /// ``` + pub fn evaluate_many<'i, I>(&'i self, points_x: I) -> impl Iterator + 'i + where + I: IntoIterator + 'i, + { + points_x.into_iter().map(move |x| self.evaluate(x)) + } + + /// Takes a list of points `xs` that are convertable to BigInt, and returns iterator over + /// `f(xs[i])`. + /// + /// ## Example + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// # use curv::arithmetic::BigInt; + /// use curv::elliptic::curves::p256::{GE, FE}; + /// + /// let coef0: FE = ECScalar::new_random(); + /// let polynomial = Polynomial::::sample_fixed_coef0(2, coef0); + /// + /// let xs: &[u16] = &[10, 11]; + /// let ys = polynomial.evaluate_many_bigint(xs.iter().copied()); + /// + /// let a = polynomial.coefficients(); + /// for (y, x) in ys.zip(xs) { + /// let x: FE = ECScalar::from(&BigInt::from(*x)); + /// assert_eq!(y, a[0] + a[1] * x + a[2] * x*x); + /// } + /// ``` + pub fn evaluate_many_bigint<'i, B, I>( + &'i self, + points_x: I, + ) -> impl Iterator + 'i + where + I: IntoIterator + 'i, + BigInt: From, + { + points_x.into_iter().map(move |x| self.evaluate_bigint(x)) + } + + /// Returns degree of polynomial + /// + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// use curv::elliptic::curves::secp256_k1::{GE, FE}; + /// + /// let coef0: FE = ECScalar::new_random(); + /// let polynomial = Polynomial::::sample_fixed_coef0(3, coef0); + /// assert_eq!(polynomial.degree(), 3); + /// ``` + pub fn degree(&self) -> u16 { + let len = + u16::try_from(self.coefficients.len()).expect("degree guaranteed to fit into u16"); + len - 1 + } + + /// Returns list of polynomial coefficients `a`: `a[i]` corresponds to coefficient `a_i` of + /// polynomial `f(x) = ... + a_i * x^i + ...` + /// + /// ## Example + /// + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// use curv::elliptic::curves::secp256_k1::{GE, FE}; + /// + /// let coef0: FE = ECScalar::new_random(); + /// let polynomial = Polynomial::::sample_fixed_coef0(3, coef0); + /// assert_eq!(polynomial.coefficients()[0], coef0); + /// ``` + pub fn coefficients(&self) -> &[P::Scalar] { + &self.coefficients + } +} + +/// Multiplies polynomial `f(x)` at scalar `s`, returning resulting polynomial `g(x) = s * f(x)` +/// +/// ## Example +/// +/// ```rust +/// # use curv::cryptographic_primitives::Polynomial; +/// # use curv::elliptic::curves::traits::ECScalar; +/// use curv::elliptic::curves::secp256_k1::{GE, FE}; +/// +/// let f = Polynomial::::sample_fixed_coef0(3, ECScalar::new_random()); +/// +/// let s: FE = ECScalar::new_random(); +/// let g = &f * &s; +/// +/// for (f_coef, g_coef) in f.coefficients().iter().zip(g.coefficients()) { +/// assert_eq!(*f_coef * s, *g_coef); +/// } +/// ``` +impl

ops::Mul<&P::Scalar> for &Polynomial

+where + P: ECPoint, + P::Scalar: Clone, +{ + type Output = Polynomial

; + fn mul(self, scalar: &P::Scalar) -> Self::Output { + let coefficients = self + .coefficients + .iter() + .map(|c| c.clone() * scalar.clone()) + .collect(); + Polynomial::from_coefficients(coefficients) + } +} + +/// Adds two polynomial `f(x)` and `g(x)` returning resulting polynomial `h(x) = f(x) + g(x)` +/// +/// ## Example +/// +/// ```rust +/// # use curv::cryptographic_primitives::Polynomial; +/// # use curv::elliptic::curves::traits::ECScalar; +/// # use curv::arithmetic::BigInt; +/// use curv::elliptic::curves::secp256_k1::{GE, FE}; +/// +/// let f = Polynomial::::sample_fixed_coef0(2, ECScalar::new_random()); +/// let g = Polynomial::::sample_fixed_coef0(3, ECScalar::new_random()); +/// let h = &f + &g; +/// +/// let x: FE = ECScalar::from(&BigInt::from(10)); +/// assert_eq!(h.evaluate(&x), f.evaluate(&x) + g.evaluate(&x)); +/// ``` +impl

ops::Add for &Polynomial

+where + P: ECPoint, + P::Scalar: Clone, +{ + type Output = Polynomial

; + fn add(self, g: Self) -> Self::Output { + let len1 = self.coefficients.len(); + let len2 = g.coefficients.len(); + + let overlapped = self + .coefficients() + .iter() + .zip(g.coefficients()) + .map(|(f_coef, g_coef)| f_coef.clone() + g_coef.clone()); + let tail = if len1 < len2 { + &g.coefficients()[len1..] + } else { + &self.coefficients()[len2..] + }; + + Polynomial::from_coefficients(overlapped.chain(tail.iter().cloned()).collect()) + } +} + +/// Subtracts two polynomial `g(x)` from `f(x)` returning resulting polynomial `h(x) = f(x) - g(x)` +/// +/// ## Example +/// +/// ```rust +/// # use curv::cryptographic_primitives::Polynomial; +/// # use curv::elliptic::curves::traits::ECScalar; +/// # use curv::arithmetic::BigInt; +/// use curv::elliptic::curves::secp256_k1::{GE, FE}; +/// +/// let f = Polynomial::::sample_fixed_coef0(2, ECScalar::new_random()); +/// let g = Polynomial::::sample_fixed_coef0(3, ECScalar::new_random()); +/// let h = &f - &g; +/// +/// let x: FE = ECScalar::from(&BigInt::from(10)); +/// assert_eq!(h.evaluate(&x), f.evaluate(&x).sub(&g.evaluate(&x).get_element())); +/// ``` +impl

ops::Sub for &Polynomial

+where + P: ECPoint, + P::Scalar: Clone, +{ + type Output = Polynomial

; + fn sub(self, g: Self) -> Self::Output { + let len1 = self.coefficients.len(); + let len2 = g.coefficients.len(); + + let overlapped = self + .coefficients() + .iter() + .zip(g.coefficients()) + .map(|(f_coef, g_coef)| f_coef.sub(&g_coef.get_element())); + let tail = if len1 < len2 { + // Instead of evaluating (0 - s), we use a trick and evaluate ((1 - s) - 1). + // The reason why we do this - some of scalars cannot be constructed to be zero ( + // panic will be raised) + let one: P::Scalar = ECScalar::from(&BigInt::from(1)); + g.coefficients()[len1..] + .iter() + .map(|x| one.sub(&x.get_element()).sub(&one.get_element())) + .collect() + } else { + self.coefficients()[len2..].to_vec() + }; + + Polynomial::from_coefficients(overlapped.chain(tail.into_iter()).collect()) + } +} diff --git a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs index 274a5954..74adbbac 100644 --- a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs +++ b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs @@ -6,9 +6,12 @@ License MIT: */ +use std::convert::{TryFrom, TryInto}; + use serde::{Deserialize, Serialize}; use crate::arithmetic::traits::*; +use crate::cryptographic_primitives::Polynomial; use crate::elliptic::curves::traits::*; use crate::BigInt; use crate::ErrorSS::{self, VerifyShareError}; @@ -38,22 +41,27 @@ where self.parameters.threshold + 1 } + // TODO: share should accept u16 rather than usize // generate VerifiableSS from a secret pub fn share(t: usize, n: usize, secret: &P::Scalar) -> (VerifiableSS

, Vec) { assert!(t < n); - let poly = VerifiableSS::

::sample_polynomial(t, secret); - let index_vec: Vec = (1..=n).collect(); - let secret_shares = VerifiableSS::

::evaluate_polynomial(&poly, &index_vec); + let t = u16::try_from(t).unwrap(); + let n = u16::try_from(n).unwrap(); + + let poly = Polynomial::

::sample_fixed_coef0(t, secret.clone()); + let secret_shares = poly.evaluate_many_bigint(1..=n).collect(); let G: P = ECPoint::generator(); - let commitments = (0..poly.len()) - .map(|i| G.clone() * poly[i].clone()) + let commitments = poly + .coefficients() + .iter() + .map(|coef| G.clone() * coef.clone()) .collect::>(); ( VerifiableSS { parameters: ShamirSecretSharing { - threshold: t, - share_count: n, + threshold: t.into(), + share_count: n.into(), }, commitments, }, @@ -63,16 +71,19 @@ where // takes given VSS and generates a new VSS for the same secret and a secret shares vector to match the new commitments pub fn reshare(&self) -> (VerifiableSS

, Vec) { + // TODO: ShamirSecretSharing::{threshold, share_count} should be u16 rather than usize + let t = u16::try_from(self.parameters.threshold).unwrap(); + let n = u16::try_from(self.parameters.share_count).unwrap(); + let one: P::Scalar = ECScalar::from(&BigInt::one()); - let poly = VerifiableSS::

::sample_polynomial(self.parameters.threshold, &one); - let index_vec: Vec = (1..=self.parameters.share_count).collect(); - let secret_shares_biased = VerifiableSS::

::evaluate_polynomial(&poly, &index_vec); + let poly = Polynomial::

::sample_fixed_coef0(t, one.clone()); + let secret_shares_biased: Vec<_> = poly.evaluate_many_bigint(1..=n).collect(); let secret_shares: Vec<_> = (0..secret_shares_biased.len()) .map(|i| secret_shares_biased[i].sub(&one.get_element())) .collect(); let G: P = ECPoint::generator(); let mut new_commitments = vec![self.commitments[0].clone()]; - for (poly, commitment) in poly.iter().zip(&self.commitments).skip(1) { + for (poly, commitment) in poly.coefficients().iter().zip(&self.commitments).skip(1) { new_commitments.push((G.clone() * poly.clone()) + commitment.clone()) } ( @@ -92,18 +103,25 @@ where index_vec: &[usize], ) -> (VerifiableSS

, Vec) { assert_eq!(n, index_vec.len()); - let poly = VerifiableSS::

::sample_polynomial(t, secret); - let secret_shares = VerifiableSS::

::evaluate_polynomial(&poly, index_vec); + // TODO: share_at_indices should accept u16 rather than usize (t, n, index_vec) + let t = u16::try_from(t).unwrap(); + let n = u16::try_from(n).unwrap(); + let index_vec = index_vec.iter().map(|&i| u16::try_from(i).unwrap()); + + let poly = Polynomial::

::sample_fixed_coef0(t, secret.clone()); + let secret_shares = poly.evaluate_many_bigint(index_vec).collect(); let G: P = ECPoint::generator(); - let commitments = (0..poly.len()) - .map(|i| G.clone() * poly[i].clone()) + let commitments = poly + .coefficients() + .iter() + .map(|coef| G.clone() * coef.clone()) .collect::>(); ( VerifiableSS { parameters: ShamirSecretSharing { - threshold: t, - share_count: n, + threshold: t.into(), + share_count: n.into(), }, commitments, }, @@ -112,25 +130,24 @@ where } // returns vector of coefficients + #[deprecated(since = "0.7.1", note = "please use Polynomial::sample instead")] pub fn sample_polynomial(t: usize, coef0: &P::Scalar) -> Vec { - let mut coefficients = vec![coef0.clone()]; - // sample the remaining coefficients randomly using secure randomness - let random_coefficients: Vec = (0..t).map(|_| ECScalar::new_random()).collect(); - coefficients.extend(random_coefficients); - // return - coefficients + Polynomial::

::sample_fixed_coef0(t.try_into().unwrap(), coef0.clone()) + .coefficients() + .to_vec() } + #[deprecated( + since = "0.7.1", + note = "please use Polynomial::evaluate_many_bigint instead" + )] pub fn evaluate_polynomial(coefficients: &[P::Scalar], index_vec: &[usize]) -> Vec { - (0..index_vec.len()) - .map(|point| { - let point_bn = BigInt::from(index_vec[point] as u32); - - VerifiableSS::

::mod_evaluate_polynomial(coefficients, ECScalar::from(&point_bn)) - }) + Polynomial::

::from_coefficients(coefficients.to_vec()) + .evaluate_many_bigint(index_vec.iter().map(|&i| u64::try_from(i).unwrap())) .collect() } + #[deprecated(since = "0.7.1", note = "please use Polynomial::evaluate instead")] pub fn mod_evaluate_polynomial(coefficients: &[P::Scalar], point: P::Scalar) -> P::Scalar { // evaluate using Horner's rule // - to combine with fold we consider the coefficients in reverse order From 138f41d46f8b4169bd8d4787073ebc4f9b11cd04 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 29 Jun 2021 18:34:58 +0300 Subject: [PATCH 03/93] Add the proof --- Cargo.toml | 1 + .../low_degree_exponent_interpolation.rs | 215 ++++++++++++++++++ src/cryptographic_primitives/proofs/mod.rs | 1 + 3 files changed, 217 insertions(+) create mode 100644 src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs diff --git a/Cargo.toml b/Cargo.toml index 196ee0dd..98530d41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ serde = { version = "1.0", features = ["derive"] } serde_derive = "1.0" sha2 = "0.8.0" sha3 = "0.8.2" +thiserror = "1" zeroize = "1" rust-gmp-kzen = { version = "0.5", features = ["serde_support"], optional = true } diff --git a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs new file mode 100644 index 00000000..830b5e0d --- /dev/null +++ b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs @@ -0,0 +1,215 @@ +use std::fmt; + +use derivative::Derivative; +use thiserror::Error; + +use crate::cryptographic_primitives::hashing::traits::Hash; +use crate::cryptographic_primitives::proofs::ProofError; +use crate::cryptographic_primitives::Polynomial; +use crate::elliptic::curves::traits::ECPoint; + +/// Claims that there's polynomial `w(x)` of degree `deg(w) <= degree`, and +/// `forall i. x[i] = g[i] * alpha[i]` (and the prover knows `w(x)`) +#[derive(Derivative)] +#[derivative(Clone(bound = "P: Clone, P::Scalar: Clone"))] +#[derivative(Debug(bound = "P: fmt::Debug, P::Scalar: fmt::Debug"))] +pub struct LdeiStatement { + pub alpha: Vec, + pub g: Vec

, + pub x: Vec

, + pub degree: u16, +} + +#[derive(Derivative)] +#[derivative(Clone(bound = "P: Clone, P::Scalar: Clone"))] +#[derivative(Debug(bound = "P: fmt::Debug, P::Scalar: fmt::Debug"))] +pub struct LdeiProof { + pub a: Vec

, + pub e: P::Scalar, + pub z: Polynomial

, +} + +impl

LdeiProof

+where + P: ECPoint + Clone + PartialEq, + P::Scalar: Clone + PartialEq, +{ + /// Constructs [LdeiStatement] and proves it correctness + /// + /// ## Protocol + /// + /// The prover samples `u(X) ← Z_q[X]` with `deg(u) ≤ d` and computes `a_i = g_i^u(alpha_i)` + /// for all `i ∈ [m]`, in addition to `e = H(g_1,...,g_m,x_1,...,x_m,a_1,...,a_m)`, and + /// `z(X) = u(X) − e · w(X)`. The proof is `(a_1,...,a_m,e,z)`. + #[allow(clippy::many_single_char_names)] + pub fn prove( + w: &Polynomial

, + alpha: Vec, + g: Vec

, + ) -> Result<(LdeiStatement

, LdeiProof

), LdeiProveError> + where + H: Hash, + { + if alpha.len() != g.len() { + return Err(LdeiProveError::AlphaLengthDoesntMatchG); + } + + // Check that alphas are pairwise distinct + for (i, a1) in alpha.iter().enumerate() { + for (j, a2) in alpha.iter().enumerate() { + if i != j && a1 == a2 { + return Err(LdeiProveError::AlphaNotPairwiseDistinct); + } + } + } + + let x: Vec

= g + .iter() + .zip(&alpha) + .map(|(g, a)| g.clone() * w.evaluate(a)) + .collect(); + + let d = w.degree(); + let u = Polynomial::

::sample(d); + let a: Vec

= g + .iter() + .zip(&alpha) + .map(|(g, a)| g.clone() * u.evaluate(a)) + .collect(); + + let hash_input: Vec<&P> = g.iter().chain(&x).chain(&a).collect(); + let e = H::create_hash_from_ge::

(hash_input.as_slice()); + + let z = &u - &(w * &e); + + let statement = LdeiStatement { + alpha, + g, + x, + degree: d, + }; + let proof = LdeiProof { a, e, z }; + + Ok((statement, proof)) + } + + /// Verifies correctness of a statement + /// + /// ## Protocol + /// + /// The verifier checks that `e = H(g1,...,gm,x1,...,xm,a1,...,am)`, that + /// `deg(z) ≤ d`, and that `a_i = g_i^z(αlpha_i) * x_i^e` for all i, and accepts if all of this is + /// true, otherwise rejects. + pub fn verify(&self, statement: &LdeiStatement

) -> Result<(), ProofError> + where + H: Hash, + { + let hash_input: Vec<&P> = statement + .g + .iter() + .chain(&statement.x) + .chain(&self.a) + .collect(); + let e = H::create_hash_from_ge::

(hash_input.as_slice()); + if e != self.e { + return Err(ProofError); + } + if self.z.degree() > statement.degree { + return Err(ProofError); + } + + let expected_a: Vec<_> = statement + .g + .iter() + .zip(&statement.alpha) + .zip(&statement.x) + .map(|((g, a), x)| g.clone() * self.z.evaluate(&a) + x.clone() * e.clone()) + .collect(); + + if self.a == expected_a { + Ok(()) + } else { + Err(ProofError) + } + } +} + +#[derive(Debug, Error)] +pub enum LdeiProveError { + #[error("`alpha`s are not pairwise distinct")] + AlphaNotPairwiseDistinct, + #[error("alpha.len() != g.len()")] + AlphaLengthDoesntMatchG, +} + +#[cfg(test)] +mod tests { + use std::iter; + + use crate::arithmetic::BigInt; + use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; + use crate::elliptic::curves::traits::ECScalar; + use crate::test_for_all_curves; + + use super::*; + + test_for_all_curves!(correctly_proofs); + fn correctly_proofs

() + where + P: ECPoint + Clone + PartialEq, + P::Scalar: ECScalar + Clone + PartialEq, + { + let poly = Polynomial::

::sample(5); + + let alpha: Vec = (1..=10).map(|i| ECScalar::from(&BigInt::from(i))).collect(); + let g: Vec

= iter::repeat_with(ECScalar::new_random) + .map(|x| P::generator() * x) + .take(10) + .collect(); + + let (statement, proof) = + LdeiProof::prove::(&poly, alpha, g).expect("failed to prove"); + proof + .verify::(&statement) + .expect("failed to validate proof"); + } + + test_for_all_curves!(catches_invalid_args); + fn catches_invalid_args

() + where + P: ECPoint + Clone + PartialEq + fmt::Debug, + P::Scalar: ECScalar + Clone + PartialEq + fmt::Debug, + { + let poly = Polynomial::

::sample(5); + + // Test that prove requires alphas.len() == g.len() + { + let alpha: Vec = + (2..=10).map(|i| ECScalar::from(&BigInt::from(i))).collect(); + let g: Vec

= iter::repeat_with(ECScalar::new_random) + .map(|x| P::generator() * x) + .take(10) + .collect(); + let result = LdeiProof::prove::(&poly, alpha, g); + if !matches!(result, Err(LdeiProveError::AlphaLengthDoesntMatchG)) { + panic!("Unexpected result: {:?}", result); + } + } + + // Test that prove requires alphas to be pairwise distinct + { + let alpha: Vec = iter::once(2) + .chain(2..=10) + .map(|i| ECScalar::from(&BigInt::from(i))) + .collect(); + let g: Vec

= iter::repeat_with(ECScalar::new_random) + .map(|x| P::generator() * x) + .take(10) + .collect(); + let result = LdeiProof::prove::(&poly, alpha, g); + if !matches!(result, Err(LdeiProveError::AlphaNotPairwiseDistinct)) { + panic!("Unexpected result: {:?}", result); + } + } + } +} diff --git a/src/cryptographic_primitives/proofs/mod.rs b/src/cryptographic_primitives/proofs/mod.rs index 4fe29589..a3a8b33c 100644 --- a/src/cryptographic_primitives/proofs/mod.rs +++ b/src/cryptographic_primitives/proofs/mod.rs @@ -8,6 +8,7 @@ use std::error::Error; use std::fmt; +pub mod low_degree_exponent_interpolation; pub mod sigma_correct_homomorphic_elgamal_enc; pub mod sigma_correct_homomorphic_elgamal_encryption_of_dlog; pub mod sigma_dlog; From 076b59c3c261823b6908c6cb27ed8687e53aff9d Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 29 Jun 2021 18:14:15 +0300 Subject: [PATCH 04/93] Update travis config --- .travis.yml | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index e99fd798..d2e92617 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,25 @@ language: rust cache: cargo -rust: - - stable +rust: stable +virt: lxd -before_script: - - rustup component add rustfmt-preview clippy - - cargo fmt --all -- --check - - cargo clippy -- -D clippy::all +env: + - BIGINT_BACKEND=rust-gmp-kzen + - BIGINT_BACKEND=num-bigint + +before_install: + - rustup component add rustfmt clippy script: - - cargo build --verbose - - cargo test --verbose + - cargo build --verbose --no-default-features --features $BIGINT_BACKEND + - cargo test --verbose --no-default-features --features $BIGINT_BACKEND + - if [[ "$BIGINT_BACKEND" = "rust-gmp-kzen" ]]; then cargo fmt --all -- --check; fi + - if [[ "$BIGINT_BACKEND" = "rust-gmp-kzen" ]]; then cargo clippy -- -D clippy::all; fi + +deploy: + provider: cargo + token: + secure: "FE6A1XRyJtTK92rV3y5e0go+FDKn1HpJbYkHOacDqabTkUluXrCTw3ERFcQQ13QZdc9xkxoAs7roKp8ivl0Xg1IJCzI+yLb0ZR6YcYebKEqd06YFbBmejjvMsyyZHKPTQmroe+tBwcA1IqLLcAY8vmY5EGhJTsGUhovIomw1RvqM6gu9yUwII/sF0a5gqY761cJd4QoLlWTb1Er7DqZxoU9drhWAJQP7sLsspjLu6dOyWzb0A2mTmnek+iuVnt9mGPtjGk4FcNPGbEmNu3UPOVuXcyibFPIALEWrH0ouZB7E9k312g45LucSeKSimgQYQBNAzdsnkKyBwyTpGuaosGnMbI7mhoi3visV21RTbw61N05dmZTYb4VAMcx+93TslKMDv5nmIlUmKxULNRBSTPPtrg0/X7KuKaoHVstrxx0ohd8GFwGYQBB64mQaOxFBhoy//prpHjhFl+1cti4JHyaHFSV/PfaryvUfRg4q2Dlq1HP+ey5cPRPbwfpSO1RmXlIDWe21ncRnKSpgMHTPBzYNtil+gZyzHl5X4ZLvLCaHsZwZQPMFB+otlabFaS1caqkk1F1fHMrj8NMak/snb2IyUJqXgQivqzEn38G3k9/QHeQXhNVwyGDtdWV51P9XfXFpxrEuuWlXF56ABiWcF7bY7Y3DeCbnFNLkVkGZYvY=" + on: + tags: true + condition: '"$TRAVIS_TAG" =~ ^v[0-9.]+$ && "$BIGINT_BACKEND" = "rust-gmp-kzen"' From 83699f4275a2e9c650579c0a0da8995398ee637e Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 29 Jun 2021 18:30:50 +0300 Subject: [PATCH 05/93] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 98530d41..be7fb3a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "curv" -version = "0.7.0" +version = "0.7.1" edition = "2018" authors = ["Omer Shlomovits"] license = "MIT" From 8882430e0ef823a3e4ced3c3df0c1ce290fe2c71 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 30 Jun 2021 10:29:17 +0300 Subject: [PATCH 06/93] Rename coef0 to const_term + update docs --- src/cryptographic_primitives/polynomial.rs | 44 +++++++++---------- .../secret_sharing/feldman_vss.rs | 8 ++-- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/cryptographic_primitives/polynomial.rs b/src/cryptographic_primitives/polynomial.rs index e73f811a..0300436a 100644 --- a/src/cryptographic_primitives/polynomial.rs +++ b/src/cryptographic_primitives/polynomial.rs @@ -74,7 +74,7 @@ where } } - /// Samples random polynomial of degree `n` with fixed coefficient `a_0 = coef0` + /// Samples random polynomial of degree `n` with fixed constant term (ie. `a_0 = constant_term`) /// /// ## Example /// ```rust @@ -82,14 +82,14 @@ where /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let coef0: FE = ECScalar::new_random(); - /// let polynomial = Polynomial::::sample_fixed_coef0(3, coef0); - /// assert_eq!(polynomial.evaluate(&FE::zero()), coef0); + /// let const_term: FE = ECScalar::new_random(); + /// let polynomial = Polynomial::::sample_fixed_const_term(3, const_term); + /// assert_eq!(polynomial.evaluate(&FE::zero()), const_term); /// ``` - pub fn sample_fixed_coef0(n: u16, coef0: P::Scalar) -> Self { + pub fn sample_fixed_const_term(n: u16, const_term: P::Scalar) -> Self { let random_coefficients = iter::repeat_with(ECScalar::new_random).take(usize::from(n)); Polynomial { - coefficients: iter::once(coef0).chain(random_coefficients).collect(), + coefficients: iter::once(const_term).chain(random_coefficients).collect(), } } @@ -102,8 +102,7 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let coef0: FE = ECScalar::new_random(); - /// let polynomial = Polynomial::::sample_fixed_coef0(2, coef0); + /// let polynomial = Polynomial::::sample(2); /// /// let x: FE = ECScalar::from(&BigInt::from(10)); /// let y: FE = polynomial.evaluate(&x); @@ -132,8 +131,7 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let coef0: FE = ECScalar::new_random(); - /// let polynomial = Polynomial::::sample_fixed_coef0(2, coef0); + /// let polynomial = Polynomial::::sample(2); /// /// let x: u16 = 10; /// let y: FE = polynomial.evaluate_bigint(x); @@ -158,8 +156,7 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let coef0: FE = ECScalar::new_random(); - /// let polynomial = Polynomial::::sample_fixed_coef0(2, coef0); + /// let polynomial = Polynomial::::sample(2); /// /// let xs: &[FE] = &[ECScalar::from(&BigInt::from(10)), ECScalar::from(&BigInt::from(11))]; /// let ys = polynomial.evaluate_many(xs); @@ -186,8 +183,7 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let coef0: FE = ECScalar::new_random(); - /// let polynomial = Polynomial::::sample_fixed_coef0(2, coef0); + /// let polynomial = Polynomial::::sample(2); /// /// let xs: &[u16] = &[10, 11]; /// let ys = polynomial.evaluate_many_bigint(xs.iter().copied()); @@ -216,8 +212,7 @@ where /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// - /// let coef0: FE = ECScalar::new_random(); - /// let polynomial = Polynomial::::sample_fixed_coef0(3, coef0); + /// let polynomial = Polynomial::::sample(3); /// assert_eq!(polynomial.degree(), 3); /// ``` pub fn degree(&self) -> u16 { @@ -236,9 +231,10 @@ where /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// - /// let coef0: FE = ECScalar::new_random(); - /// let polynomial = Polynomial::::sample_fixed_coef0(3, coef0); - /// assert_eq!(polynomial.coefficients()[0], coef0); + /// let polynomial = Polynomial::::sample(3); + /// let a = polynomial.coefficients(); + /// let x: FE = ECScalar::new_random(); + /// assert_eq!(polynomial.evaluate(&x), a[0] + a[1] * x + a[2] * x*x + a[3] * x*x*x); /// ``` pub fn coefficients(&self) -> &[P::Scalar] { &self.coefficients @@ -254,7 +250,7 @@ where /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// -/// let f = Polynomial::::sample_fixed_coef0(3, ECScalar::new_random()); +/// let f = Polynomial::::sample(3); /// /// let s: FE = ECScalar::new_random(); /// let g = &f * &s; @@ -289,8 +285,8 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// -/// let f = Polynomial::::sample_fixed_coef0(2, ECScalar::new_random()); -/// let g = Polynomial::::sample_fixed_coef0(3, ECScalar::new_random()); +/// let f = Polynomial::::sample(2); +/// let g = Polynomial::::sample(3); /// let h = &f + &g; /// /// let x: FE = ECScalar::from(&BigInt::from(10)); @@ -331,8 +327,8 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// -/// let f = Polynomial::::sample_fixed_coef0(2, ECScalar::new_random()); -/// let g = Polynomial::::sample_fixed_coef0(3, ECScalar::new_random()); +/// let f = Polynomial::::sample(2); +/// let g = Polynomial::::sample(3); /// let h = &f - &g; /// /// let x: FE = ECScalar::from(&BigInt::from(10)); diff --git a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs index 74adbbac..1240c9fb 100644 --- a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs +++ b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs @@ -48,7 +48,7 @@ where let t = u16::try_from(t).unwrap(); let n = u16::try_from(n).unwrap(); - let poly = Polynomial::

::sample_fixed_coef0(t, secret.clone()); + let poly = Polynomial::

::sample_fixed_const_term(t, secret.clone()); let secret_shares = poly.evaluate_many_bigint(1..=n).collect(); let G: P = ECPoint::generator(); @@ -76,7 +76,7 @@ where let n = u16::try_from(self.parameters.share_count).unwrap(); let one: P::Scalar = ECScalar::from(&BigInt::one()); - let poly = Polynomial::

::sample_fixed_coef0(t, one.clone()); + let poly = Polynomial::

::sample_fixed_const_term(t, one.clone()); let secret_shares_biased: Vec<_> = poly.evaluate_many_bigint(1..=n).collect(); let secret_shares: Vec<_> = (0..secret_shares_biased.len()) .map(|i| secret_shares_biased[i].sub(&one.get_element())) @@ -108,7 +108,7 @@ where let n = u16::try_from(n).unwrap(); let index_vec = index_vec.iter().map(|&i| u16::try_from(i).unwrap()); - let poly = Polynomial::

::sample_fixed_coef0(t, secret.clone()); + let poly = Polynomial::

::sample_fixed_const_term(t, secret.clone()); let secret_shares = poly.evaluate_many_bigint(index_vec).collect(); let G: P = ECPoint::generator(); @@ -132,7 +132,7 @@ where // returns vector of coefficients #[deprecated(since = "0.7.1", note = "please use Polynomial::sample instead")] pub fn sample_polynomial(t: usize, coef0: &P::Scalar) -> Vec { - Polynomial::

::sample_fixed_coef0(t.try_into().unwrap(), coef0.clone()) + Polynomial::

::sample_fixed_const_term(t.try_into().unwrap(), coef0.clone()) .coefficients() .to_vec() } From 8aed49627af9d7f6a3a59eca35811625cc4cdc2f Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 30 Jun 2021 12:30:21 +0300 Subject: [PATCH 07/93] Add sample_exact and sample_exact_with_fixed_const --- src/cryptographic_primitives/polynomial.rs | 180 +++++++++++++----- .../low_degree_exponent_interpolation.rs | 4 +- .../secret_sharing/feldman_vss.rs | 8 +- 3 files changed, 143 insertions(+), 49 deletions(-) diff --git a/src/cryptographic_primitives/polynomial.rs b/src/cryptographic_primitives/polynomial.rs index 0300436a..3b9ec262 100644 --- a/src/cryptographic_primitives/polynomial.rs +++ b/src/cryptographic_primitives/polynomial.rs @@ -22,17 +22,18 @@ pub struct Polynomial { impl

Polynomial

where P: ECPoint, - P::Scalar: Clone, { - /// Constructs polynomial `f(x)` from list of coefficients `a`. + /// Constructs polynomial `f(x)` from list of coefficients `a` /// /// ## Order /// /// `a[i]` should corresponds to coefficient `a_i` of polynomial `f(x) = ... + a_i * x^i + ...` /// - /// ## Panics + /// ## Polynomial degree /// - /// Panics if list of coefficients is empty + /// Note that it's not guaranteed that constructed polynomial degree equals to `coefficients.len()-1` + /// as it's allowed to end with zero coefficients. Actual polynomial degree equals to index of last + /// non-zero coefficient or zero if all the coefficients are zero. /// /// ## Example /// @@ -47,13 +48,15 @@ where /// assert_eq!(coefs, poly.coefficients()); /// ``` pub fn from_coefficients(coefficients: Vec) -> Self { - assert!( - !coefficients.is_empty(), - "coefficients must have at least one coefficient" - ); Self { coefficients } } +} +impl

Polynomial

+where + P: ECPoint, + P::Scalar: PartialEq, +{ /// Sample a random polynomial of given degree /// /// ## Example @@ -62,19 +65,103 @@ where /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let polynomial = Polynomial::::sample(3); + /// let polynomial = Polynomial::::sample_exact(3); /// assert_eq!(polynomial.degree(), 3); /// ``` + pub fn sample_exact(degree: u16) -> Self { + if degree == 0 { + Self::from_coefficients(vec![ECScalar::new_random()]) + } else { + Self::from_coefficients( + iter::repeat_with(ECScalar::new_random) + .take(usize::from(degree)) + .chain(iter::once(new_random_nonzero())) + .collect(), + ) + } + } + + /// Samples random polynomial of degree `n` with fixed constant term (ie. `a_0 = constant_term`) + /// + /// ## Example + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// use curv::elliptic::curves::p256::{GE, FE}; + /// + /// let const_term: FE = ECScalar::new_random(); + /// let polynomial = Polynomial::::sample_exact_with_fixed_const_term(3, const_term); + /// assert_eq!(polynomial.degree(), 3); + /// assert_eq!(polynomial.evaluate(&FE::zero()), const_term); + /// ``` + pub fn sample_exact_with_fixed_const_term(n: u16, const_term: P::Scalar) -> Self { + if n == 0 { + Self::from_coefficients(vec![const_term]) + } else { + let random_coefficients = iter::repeat_with(ECScalar::new_random) + .take(usize::from(n - 1)) + .chain(iter::once(new_random_nonzero::())); + Self::from_coefficients(iter::once(const_term).chain(random_coefficients).collect()) + } + } + + /// Returns degree `d` of polynomial `f(x)`: `d = deg(f)` + /// + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// # use curv::arithmetic::BigInt; + /// use curv::elliptic::curves::secp256_k1::{GE, FE}; + /// + /// let polynomial = Polynomial::::from_coefficients(vec![ + /// ECScalar::from(&BigInt::from(1)), ECScalar::from(&BigInt::from(2)), + /// ]); + /// assert_eq!(polynomial.degree(), 1); + /// + /// let polynomial = Polynomial::::from_coefficients(vec![ + /// ECScalar::from(&BigInt::from(1)), ECScalar::zero(), + /// ]); + /// assert_eq!(polynomial.degree(), 0); + /// ``` + pub fn degree(&self) -> u16 { + let zero = P::Scalar::zero(); + let i = self + .coefficients() + .iter() + .enumerate() + .rev() + .find(|(_, a)| a != &&zero) + .map(|(i, _)| i) + .unwrap_or(0); + u16::try_from(i).expect("polynomial degree guaranteed to fit into u16") + } +} + +impl

Polynomial

+where + P: ECPoint, +{ + /// Samples a random polynomial of degree less or equal to given degree /// + /// ## Example + /// ```rust + /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::elliptic::curves::traits::ECScalar; + /// use curv::elliptic::curves::p256::{GE, FE}; + /// + /// let polynomial = Polynomial::::sample(3); + /// assert!(polynomial.degree() <= 3); + /// ``` pub fn sample(degree: u16) -> Self { - Polynomial { - coefficients: iter::repeat_with(ECScalar::new_random) + Polynomial::from_coefficients( + iter::repeat_with(ECScalar::new_random) .take(usize::from(degree + 1)) .collect(), - } + ) } - /// Samples random polynomial of degree `n` with fixed constant term (ie. `a_0 = constant_term`) + /// Samples a random polynomial of degree less or equal to given degree with fixed constant term + /// (ie. `a_0 = const_term`) /// /// ## Example /// ```rust @@ -82,17 +169,24 @@ where /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let const_term: FE = ECScalar::new_random(); - /// let polynomial = Polynomial::::sample_fixed_const_term(3, const_term); + /// let const_term = FE::new_random(); + /// let polynomial = Polynomial::::sample_with_fixed_const_term(3, const_term); + /// assert!(polynomial.degree() <= 3); /// assert_eq!(polynomial.evaluate(&FE::zero()), const_term); /// ``` - pub fn sample_fixed_const_term(n: u16, const_term: P::Scalar) -> Self { - let random_coefficients = iter::repeat_with(ECScalar::new_random).take(usize::from(n)); + pub fn sample_with_fixed_const_term(degree: u16, const_term: P::Scalar) -> Self { + let random_coefficients = iter::repeat_with(ECScalar::new_random).take(usize::from(degree)); Polynomial { coefficients: iter::once(const_term).chain(random_coefficients).collect(), } } +} +impl

Polynomial

+where + P: ECPoint, + P::Scalar: Clone, +{ /// Takes scalar `x` and evaluates `f(x)` /// /// ## Example @@ -102,7 +196,7 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let polynomial = Polynomial::::sample(2); + /// let polynomial = Polynomial::::sample_exact(2); /// /// let x: FE = ECScalar::from(&BigInt::from(10)); /// let y: FE = polynomial.evaluate(&x); @@ -131,7 +225,7 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let polynomial = Polynomial::::sample(2); + /// let polynomial = Polynomial::::sample_exact(2); /// /// let x: u16 = 10; /// let y: FE = polynomial.evaluate_bigint(x); @@ -156,7 +250,7 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let polynomial = Polynomial::::sample(2); + /// let polynomial = Polynomial::::sample_exact(2); /// /// let xs: &[FE] = &[ECScalar::from(&BigInt::from(10)), ECScalar::from(&BigInt::from(11))]; /// let ys = polynomial.evaluate_many(xs); @@ -183,7 +277,7 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; /// - /// let polynomial = Polynomial::::sample(2); + /// let polynomial = Polynomial::::sample_exact(2); /// /// let xs: &[u16] = &[10, 11]; /// let ys = polynomial.evaluate_many_bigint(xs.iter().copied()); @@ -204,23 +298,12 @@ where { points_x.into_iter().map(move |x| self.evaluate_bigint(x)) } +} - /// Returns degree of polynomial - /// - /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// use curv::elliptic::curves::secp256_k1::{GE, FE}; - /// - /// let polynomial = Polynomial::::sample(3); - /// assert_eq!(polynomial.degree(), 3); - /// ``` - pub fn degree(&self) -> u16 { - let len = - u16::try_from(self.coefficients.len()).expect("degree guaranteed to fit into u16"); - len - 1 - } - +impl

Polynomial

+where + P: ECPoint, +{ /// Returns list of polynomial coefficients `a`: `a[i]` corresponds to coefficient `a_i` of /// polynomial `f(x) = ... + a_i * x^i + ...` /// @@ -231,7 +314,7 @@ where /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// - /// let polynomial = Polynomial::::sample(3); + /// let polynomial = Polynomial::::sample_exact(3); /// let a = polynomial.coefficients(); /// let x: FE = ECScalar::new_random(); /// assert_eq!(polynomial.evaluate(&x), a[0] + a[1] * x + a[2] * x*x + a[3] * x*x*x); @@ -250,7 +333,7 @@ where /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// -/// let f = Polynomial::::sample(3); +/// let f = Polynomial::::sample_exact(3); /// /// let s: FE = ECScalar::new_random(); /// let g = &f * &s; @@ -285,8 +368,8 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// -/// let f = Polynomial::::sample(2); -/// let g = Polynomial::::sample(3); +/// let f = Polynomial::::sample_exact(2); +/// let g = Polynomial::::sample_exact(3); /// let h = &f + &g; /// /// let x: FE = ECScalar::from(&BigInt::from(10)); @@ -327,8 +410,8 @@ where /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// -/// let f = Polynomial::::sample(2); -/// let g = Polynomial::::sample(3); +/// let f = Polynomial::::sample_exact(2); +/// let g = Polynomial::::sample_exact(3); /// let h = &f - &g; /// /// let x: FE = ECScalar::from(&BigInt::from(10)); @@ -365,3 +448,14 @@ where Polynomial::from_coefficients(overlapped.chain(tail.into_iter()).collect()) } } + +/// Samples a scalar guaranteed to be not zero +fn new_random_nonzero() -> S { + let zero = S::zero(); + loop { + let s = S::new_random(); + if s != zero { + break s; + } + } +} diff --git a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs index 830b5e0d..2d7b29c2 100644 --- a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs +++ b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs @@ -159,7 +159,7 @@ mod tests { P: ECPoint + Clone + PartialEq, P::Scalar: ECScalar + Clone + PartialEq, { - let poly = Polynomial::

::sample(5); + let poly = Polynomial::

::sample_exact(5); let alpha: Vec = (1..=10).map(|i| ECScalar::from(&BigInt::from(i))).collect(); let g: Vec

= iter::repeat_with(ECScalar::new_random) @@ -180,7 +180,7 @@ mod tests { P: ECPoint + Clone + PartialEq + fmt::Debug, P::Scalar: ECScalar + Clone + PartialEq + fmt::Debug, { - let poly = Polynomial::

::sample(5); + let poly = Polynomial::

::sample_exact(5); // Test that prove requires alphas.len() == g.len() { diff --git a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs index 1240c9fb..6761675d 100644 --- a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs +++ b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs @@ -48,7 +48,7 @@ where let t = u16::try_from(t).unwrap(); let n = u16::try_from(n).unwrap(); - let poly = Polynomial::

::sample_fixed_const_term(t, secret.clone()); + let poly = Polynomial::

::sample_with_fixed_const_term(t, secret.clone()); let secret_shares = poly.evaluate_many_bigint(1..=n).collect(); let G: P = ECPoint::generator(); @@ -76,7 +76,7 @@ where let n = u16::try_from(self.parameters.share_count).unwrap(); let one: P::Scalar = ECScalar::from(&BigInt::one()); - let poly = Polynomial::

::sample_fixed_const_term(t, one.clone()); + let poly = Polynomial::

::sample_with_fixed_const_term(t, one.clone()); let secret_shares_biased: Vec<_> = poly.evaluate_many_bigint(1..=n).collect(); let secret_shares: Vec<_> = (0..secret_shares_biased.len()) .map(|i| secret_shares_biased[i].sub(&one.get_element())) @@ -108,7 +108,7 @@ where let n = u16::try_from(n).unwrap(); let index_vec = index_vec.iter().map(|&i| u16::try_from(i).unwrap()); - let poly = Polynomial::

::sample_fixed_const_term(t, secret.clone()); + let poly = Polynomial::

::sample_with_fixed_const_term(t, secret.clone()); let secret_shares = poly.evaluate_many_bigint(index_vec).collect(); let G: P = ECPoint::generator(); @@ -132,7 +132,7 @@ where // returns vector of coefficients #[deprecated(since = "0.7.1", note = "please use Polynomial::sample instead")] pub fn sample_polynomial(t: usize, coef0: &P::Scalar) -> Vec { - Polynomial::

::sample_fixed_const_term(t.try_into().unwrap(), coef0.clone()) + Polynomial::

::sample_with_fixed_const_term(t.try_into().unwrap(), coef0.clone()) .coefficients() .to_vec() } From 369d50c519a07ff795e45ea1be3ecef434e0ed9d Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 30 Jun 2021 12:31:38 +0300 Subject: [PATCH 08/93] Rename LdeiProveError -> LdeiProofError --- .../proofs/low_degree_exponent_interpolation.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs index 2d7b29c2..9a1e9b09 100644 --- a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs +++ b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs @@ -46,19 +46,19 @@ where w: &Polynomial

, alpha: Vec, g: Vec

, - ) -> Result<(LdeiStatement

, LdeiProof

), LdeiProveError> + ) -> Result<(LdeiStatement

, LdeiProof

), LdeiProofError> where H: Hash, { if alpha.len() != g.len() { - return Err(LdeiProveError::AlphaLengthDoesntMatchG); + return Err(LdeiProofError::AlphaLengthDoesntMatchG); } // Check that alphas are pairwise distinct for (i, a1) in alpha.iter().enumerate() { for (j, a2) in alpha.iter().enumerate() { if i != j && a1 == a2 { - return Err(LdeiProveError::AlphaNotPairwiseDistinct); + return Err(LdeiProofError::AlphaNotPairwiseDistinct); } } } @@ -135,7 +135,7 @@ where } #[derive(Debug, Error)] -pub enum LdeiProveError { +pub enum LdeiProofError { #[error("`alpha`s are not pairwise distinct")] AlphaNotPairwiseDistinct, #[error("alpha.len() != g.len()")] @@ -191,7 +191,7 @@ mod tests { .take(10) .collect(); let result = LdeiProof::prove::(&poly, alpha, g); - if !matches!(result, Err(LdeiProveError::AlphaLengthDoesntMatchG)) { + if !matches!(result, Err(LdeiProofError::AlphaLengthDoesntMatchG)) { panic!("Unexpected result: {:?}", result); } } @@ -207,7 +207,7 @@ mod tests { .take(10) .collect(); let result = LdeiProof::prove::(&poly, alpha, g); - if !matches!(result, Err(LdeiProveError::AlphaNotPairwiseDistinct)) { + if !matches!(result, Err(LdeiProofError::AlphaNotPairwiseDistinct)) { panic!("Unexpected result: {:?}", result); } } From 4f84e8abc59d48a2b0c9af75f472ba799067163f Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 30 Jun 2021 12:47:22 +0300 Subject: [PATCH 09/93] Move polynomial into secret_sharing module --- src/cryptographic_primitives/mod.rs | 3 -- .../low_degree_exponent_interpolation.rs | 2 +- .../secret_sharing/feldman_vss.rs | 2 +- .../secret_sharing/mod.rs | 3 ++ .../{ => secret_sharing}/polynomial.rs | 28 +++++++++---------- 5 files changed, 19 insertions(+), 19 deletions(-) rename src/cryptographic_primitives/{ => secret_sharing}/polynomial.rs (93%) diff --git a/src/cryptographic_primitives/mod.rs b/src/cryptographic_primitives/mod.rs index 8a98644d..2a868030 100644 --- a/src/cryptographic_primitives/mod.rs +++ b/src/cryptographic_primitives/mod.rs @@ -7,9 +7,6 @@ pub mod commitments; pub mod hashing; -mod polynomial; pub mod proofs; pub mod secret_sharing; pub mod twoparty; - -pub use polynomial::Polynomial; diff --git a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs index 9a1e9b09..1512bdd6 100644 --- a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs +++ b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs @@ -5,7 +5,7 @@ use thiserror::Error; use crate::cryptographic_primitives::hashing::traits::Hash; use crate::cryptographic_primitives::proofs::ProofError; -use crate::cryptographic_primitives::Polynomial; +use crate::cryptographic_primitives::secret_sharing::Polynomial; use crate::elliptic::curves::traits::ECPoint; /// Claims that there's polynomial `w(x)` of degree `deg(w) <= degree`, and diff --git a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs index 6761675d..a2d89b43 100644 --- a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs +++ b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs @@ -11,7 +11,7 @@ use std::convert::{TryFrom, TryInto}; use serde::{Deserialize, Serialize}; use crate::arithmetic::traits::*; -use crate::cryptographic_primitives::Polynomial; +use crate::cryptographic_primitives::secret_sharing::Polynomial; use crate::elliptic::curves::traits::*; use crate::BigInt; use crate::ErrorSS::{self, VerifyShareError}; diff --git a/src/cryptographic_primitives/secret_sharing/mod.rs b/src/cryptographic_primitives/secret_sharing/mod.rs index 56ebfc91..f50534df 100644 --- a/src/cryptographic_primitives/secret_sharing/mod.rs +++ b/src/cryptographic_primitives/secret_sharing/mod.rs @@ -6,3 +6,6 @@ */ pub mod feldman_vss; +mod polynomial; + +pub use polynomial::Polynomial; diff --git a/src/cryptographic_primitives/polynomial.rs b/src/cryptographic_primitives/secret_sharing/polynomial.rs similarity index 93% rename from src/cryptographic_primitives/polynomial.rs rename to src/cryptographic_primitives/secret_sharing/polynomial.rs index 3b9ec262..394b898b 100644 --- a/src/cryptographic_primitives/polynomial.rs +++ b/src/cryptographic_primitives/secret_sharing/polynomial.rs @@ -38,7 +38,7 @@ where /// ## Example /// /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::p256::{GE, FE}; /// @@ -61,7 +61,7 @@ where /// /// ## Example /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::p256::{GE, FE}; /// @@ -85,7 +85,7 @@ where /// /// ## Example /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::p256::{GE, FE}; /// @@ -108,7 +108,7 @@ where /// Returns degree `d` of polynomial `f(x)`: `d = deg(f)` /// /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; @@ -145,7 +145,7 @@ where /// /// ## Example /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::p256::{GE, FE}; /// @@ -165,7 +165,7 @@ where /// /// ## Example /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::p256::{GE, FE}; /// @@ -191,7 +191,7 @@ where /// /// ## Example /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; @@ -220,7 +220,7 @@ where /// /// ## Example /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; @@ -245,7 +245,7 @@ where /// /// ## Example /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; @@ -272,7 +272,7 @@ where /// /// ## Example /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::p256::{GE, FE}; @@ -310,7 +310,7 @@ where /// ## Example /// /// ```rust - /// # use curv::cryptographic_primitives::Polynomial; + /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// @@ -329,7 +329,7 @@ where /// ## Example /// /// ```rust -/// # use curv::cryptographic_primitives::Polynomial; +/// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; /// @@ -363,7 +363,7 @@ where /// ## Example /// /// ```rust -/// # use curv::cryptographic_primitives::Polynomial; +/// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; @@ -405,7 +405,7 @@ where /// ## Example /// /// ```rust -/// # use curv::cryptographic_primitives::Polynomial; +/// # use curv::cryptographic_primitives::secret_sharing::Polynomial; /// # use curv::elliptic::curves::traits::ECScalar; /// # use curv::arithmetic::BigInt; /// use curv::elliptic::curves::secp256_k1::{GE, FE}; From b5f322e16562807ca6a9025b19c9303e877ab894 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 30 Jun 2021 14:13:06 +0300 Subject: [PATCH 10/93] LDEI prove takes witness and statement --- .../low_degree_exponent_interpolation.rs | 167 ++++++++++-------- 1 file changed, 91 insertions(+), 76 deletions(-) diff --git a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs index 1512bdd6..09e03594 100644 --- a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs +++ b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs @@ -8,6 +8,14 @@ use crate::cryptographic_primitives::proofs::ProofError; use crate::cryptographic_primitives::secret_sharing::Polynomial; use crate::elliptic::curves::traits::ECPoint; +/// The prover private polynomial +#[derive(Derivative)] +#[derivative(Clone(bound = "P::Scalar: Clone"))] +#[derivative(Debug(bound = "P::Scalar: fmt::Debug"))] +pub struct LdeiWitness { + pub w: Polynomial

, +} + /// Claims that there's polynomial `w(x)` of degree `deg(w) <= degree`, and /// `forall i. x[i] = g[i] * alpha[i]` (and the prover knows `w(x)`) #[derive(Derivative)] @@ -17,7 +25,42 @@ pub struct LdeiStatement { pub alpha: Vec, pub g: Vec

, pub x: Vec

, - pub degree: u16, + pub d: u16, +} + +impl

LdeiStatement

+where + P: ECPoint + Clone, + P::Scalar: Clone + PartialEq, +{ + /// Takes [witness](LdeiWitness) (ie. secret polynomial `w(x)`), list of scalars `alpha`, + /// list of generators `g`, number `d`. Produces LdeiStatement consisting of `alpha`, `g`, `d`, + /// and list `x` such as `x_i = g_i * w(alpha_i)` + pub fn new( + witness: &LdeiWitness

, + alpha: Vec, + g: Vec

, + d: u16, + ) -> Result { + if g.len() != alpha.len() { + return Err(InvalidLdeiStatement::AlphaLengthDoesntMatchG); + } + if witness.w.degree() > d { + return Err(InvalidLdeiStatement::PolynomialDegreeMoreThanD); + } + if !ensure_list_is_pairwise_distinct(&alpha) { + return Err(InvalidLdeiStatement::AlphaNotPairwiseDistinct); + } + Ok(Self { + x: g.iter() + .zip(&alpha) + .map(|(g, a)| g.clone() * witness.w.evaluate(a)) + .collect(), + alpha, + g, + d, + }) + } } #[derive(Derivative)] @@ -43,54 +86,46 @@ where /// `z(X) = u(X) − e · w(X)`. The proof is `(a_1,...,a_m,e,z)`. #[allow(clippy::many_single_char_names)] pub fn prove( - w: &Polynomial

, - alpha: Vec, - g: Vec

, - ) -> Result<(LdeiStatement

, LdeiProof

), LdeiProofError> + witness: &LdeiWitness

, + statement: &LdeiStatement

, + ) -> Result, InvalidLdeiStatement> where H: Hash, { - if alpha.len() != g.len() { - return Err(LdeiProofError::AlphaLengthDoesntMatchG); + if statement.alpha.len() != statement.g.len() { + return Err(InvalidLdeiStatement::AlphaLengthDoesntMatchG); } - - // Check that alphas are pairwise distinct - for (i, a1) in alpha.iter().enumerate() { - for (j, a2) in alpha.iter().enumerate() { - if i != j && a1 == a2 { - return Err(LdeiProofError::AlphaNotPairwiseDistinct); - } - } + if witness.w.degree() > statement.d { + return Err(InvalidLdeiStatement::PolynomialDegreeMoreThanD); + } + if !ensure_list_is_pairwise_distinct(&statement.alpha) { + return Err(InvalidLdeiStatement::AlphaNotPairwiseDistinct); } - let x: Vec

= g + let x_expected: Vec

= statement + .g .iter() - .zip(&alpha) - .map(|(g, a)| g.clone() * w.evaluate(a)) + .zip(&statement.alpha) + .map(|(g, a)| g.clone() * witness.w.evaluate(a)) .collect(); + if statement.x != x_expected { + return Err(InvalidLdeiStatement::ListOfXDoesntMatchExpectedValue); + } - let d = w.degree(); - let u = Polynomial::

::sample(d); - let a: Vec

= g + let u = Polynomial::

::sample(statement.d); + let a: Vec

= statement + .g .iter() - .zip(&alpha) + .zip(&statement.alpha) .map(|(g, a)| g.clone() * u.evaluate(a)) .collect(); - let hash_input: Vec<&P> = g.iter().chain(&x).chain(&a).collect(); + let hash_input: Vec<&P> = statement.g.iter().chain(&statement.x).chain(&a).collect(); let e = H::create_hash_from_ge::

(hash_input.as_slice()); - let z = &u - &(w * &e); - - let statement = LdeiStatement { - alpha, - g, - x, - degree: d, - }; - let proof = LdeiProof { a, e, z }; + let z = &u - &(&witness.w * &e); - Ok((statement, proof)) + Ok(LdeiProof { a, e, z }) } /// Verifies correctness of a statement @@ -114,7 +149,7 @@ where if e != self.e { return Err(ProofError); } - if self.z.degree() > statement.degree { + if self.z.degree() > statement.d { return Err(ProofError); } @@ -134,12 +169,28 @@ where } } +/// Indicates that statement is not valid or doesn't match a witness #[derive(Debug, Error)] -pub enum LdeiProofError { +pub enum InvalidLdeiStatement { #[error("`alpha`s are not pairwise distinct")] AlphaNotPairwiseDistinct, #[error("alpha.len() != g.len()")] AlphaLengthDoesntMatchG, + #[error("deg(w) > d")] + PolynomialDegreeMoreThanD, + #[error("`statement.x` doesn't match expected value")] + ListOfXDoesntMatchExpectedValue, +} + +fn ensure_list_is_pairwise_distinct(list: &[S]) -> bool { + for (i, x1) in list.iter().enumerate() { + for (j, x2) in list.iter().enumerate() { + if i != j && x1 == x2 { + return false; + } + } + } + true } #[cfg(test)] @@ -159,7 +210,9 @@ mod tests { P: ECPoint + Clone + PartialEq, P::Scalar: ECScalar + Clone + PartialEq, { + let d = 5; let poly = Polynomial::

::sample_exact(5); + let witness = LdeiWitness { w: poly }; let alpha: Vec = (1..=10).map(|i| ECScalar::from(&BigInt::from(i))).collect(); let g: Vec

= iter::repeat_with(ECScalar::new_random) @@ -167,49 +220,11 @@ mod tests { .take(10) .collect(); - let (statement, proof) = - LdeiProof::prove::(&poly, alpha, g).expect("failed to prove"); + let statement = LdeiStatement::new(&witness, alpha, g, d).unwrap(); + + let proof = LdeiProof::prove::(&witness, &statement).expect("failed to prove"); proof .verify::(&statement) .expect("failed to validate proof"); } - - test_for_all_curves!(catches_invalid_args); - fn catches_invalid_args

() - where - P: ECPoint + Clone + PartialEq + fmt::Debug, - P::Scalar: ECScalar + Clone + PartialEq + fmt::Debug, - { - let poly = Polynomial::

::sample_exact(5); - - // Test that prove requires alphas.len() == g.len() - { - let alpha: Vec = - (2..=10).map(|i| ECScalar::from(&BigInt::from(i))).collect(); - let g: Vec

= iter::repeat_with(ECScalar::new_random) - .map(|x| P::generator() * x) - .take(10) - .collect(); - let result = LdeiProof::prove::(&poly, alpha, g); - if !matches!(result, Err(LdeiProofError::AlphaLengthDoesntMatchG)) { - panic!("Unexpected result: {:?}", result); - } - } - - // Test that prove requires alphas to be pairwise distinct - { - let alpha: Vec = iter::once(2) - .chain(2..=10) - .map(|i| ECScalar::from(&BigInt::from(i))) - .collect(); - let g: Vec

= iter::repeat_with(ECScalar::new_random) - .map(|x| P::generator() * x) - .take(10) - .collect(); - let result = LdeiProof::prove::(&poly, alpha, g); - if !matches!(result, Err(LdeiProofError::AlphaNotPairwiseDistinct)) { - panic!("Unexpected result: {:?}", result); - } - } - } } From e47d41dcdeab4461af095c392747934cd70a1ae8 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 2 Jul 2021 16:43:08 +0300 Subject: [PATCH 11/93] Comment out crypto primitives for a while --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 5356d21d..f5a31935 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ pub mod elliptic; pub mod arithmetic; pub use crate::arithmetic::BigInt; -pub mod cryptographic_primitives; +// pub mod cryptographic_primitives; #[derive(Copy, PartialEq, Eq, Clone, Debug)] pub enum ErrorKey { From d8419383e64ff0be55b7558b6bfb85b54cc1ff9a Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 2 Jul 2021 16:43:52 +0300 Subject: [PATCH 12/93] Update traits, add wrappers, and upgrade secp256k1 implementation --- Cargo.toml | 6 +- src/elliptic/curves/mod.rs | 15 +- src/elliptic/curves/secp256_k1.rs | 1133 +++++++++++-------------- src/elliptic/curves/traits.rs | 238 +++++- src/elliptic/curves/wrappers.rs | 1282 +++++++++++++++++++++++++++++ 5 files changed, 1987 insertions(+), 687 deletions(-) create mode 100644 src/elliptic/curves/wrappers.rs diff --git a/Cargo.toml b/Cargo.toml index be7fb3a7..e659cb48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,10 +19,11 @@ digest = "0.8.1" ff-zeroize = "0.6.3" funty = "=1.1.0" generic-array = "0.14" -hex = "0.4" +hex = { version = "0.4", features = ["serde"] } hmac = "0.7.1" +thiserror = "1" merkle-sha3 = "^0.1" -lazy_static = "1.4.0" +lazy_static = "1.4" num-traits = "0.2" num-integer = "0.1" pairing-plus = "0.19" @@ -33,7 +34,6 @@ serde = { version = "1.0", features = ["derive"] } serde_derive = "1.0" sha2 = "0.8.0" sha3 = "0.8.2" -thiserror = "1" zeroize = "1" rust-gmp-kzen = { version = "0.5", features = ["serde_support"], optional = true } diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index cc22a67f..2b3d2375 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -1,6 +1,11 @@ -pub mod bls12_381; -pub mod curve_ristretto; -pub mod ed25519; -pub mod p256; +// pub mod bls12_381; +// pub mod curve_ristretto; +// pub mod ed25519; +// pub mod p256; pub mod secp256_k1; -pub mod traits; + +mod traits; +mod wrappers; + +pub use self::secp256_k1::Secp256k1; +pub use self::{traits::*, wrappers::*}; diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 41f79c25..58ecbd0c 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -16,31 +16,51 @@ // The Public Key codec: Point <> SecretKey // -use super::traits::{ECPoint, ECScalar}; -use crate::arithmetic::traits::*; -use crate::BigInt; -use crate::ErrorKey; - -#[cfg(feature = "merkle")] -use crypto::digest::Digest; -#[cfg(feature = "merkle")] -use crypto::sha3::Sha3; -#[cfg(feature = "merkle")] -use merkle::Hashable; +use std::ops::{self, Deref}; +use std::ptr; +use std::sync::atomic; + use rand::thread_rng; use secp256k1::constants::{ - CURVE_ORDER, GENERATOR_X, GENERATOR_Y, SECRET_KEY_SIZE, UNCOMPRESSED_PUBLIC_KEY_SIZE, + self, GENERATOR_X, GENERATOR_Y, SECRET_KEY_SIZE, UNCOMPRESSED_PUBLIC_KEY_SIZE, }; -use secp256k1::{PublicKey, Secp256k1, SecretKey, VerifyOnly}; -use serde::de::{self, Error, MapAccess, SeqAccess, Visitor}; -use serde::ser::SerializeStruct; -use serde::ser::{Serialize, Serializer}; -use serde::{Deserialize, Deserializer}; -use std::fmt; -use std::ops::{Add, Mul}; -use std::ptr; -use std::sync::{atomic, Once}; -use zeroize::Zeroize; +use secp256k1::{PublicKey, SecretKey}; +use zeroize::{Zeroize, Zeroizing}; + +use crate::arithmetic::*; + +use super::traits::*; + +lazy_static::lazy_static! { + static ref CONTEXT: secp256k1::Secp256k1 = secp256k1::Secp256k1::verification_only(); + + static ref CURVE_ORDER: BigInt = BigInt::from_bytes(&constants::CURVE_ORDER); + + static ref GENERATOR_UNCOMRESSED: Vec = { + let mut g = vec![4_u8]; + g.extend_from_slice(&GENERATOR_X); + g.extend_from_slice(&GENERATOR_Y); + g + }; + + static ref BASE_POINT2_UNCOMPRESSED: Vec = { + let mut g = vec![4_u8]; + g.extend_from_slice(BASE_POINT2_X.as_ref()); + g.extend_from_slice(BASE_POINT2_Y.as_ref()); + g + }; + + static ref GENERATOR: Secp256k1Point = Secp256k1Point { + purpose: "generator", + ge: Some(PK(PublicKey::from_slice(&GENERATOR_UNCOMRESSED).unwrap())), + }; + + static ref BASE_POINT2: Secp256k1Point = Secp256k1Point { + purpose: "base_point2", + ge: Some(PK(PublicKey::from_slice(&BASE_POINT2_UNCOMPRESSED).unwrap())), + }; +} + /* X coordinate of a point of unknown discrete logarithm. Computed using a deterministic algorithm with the generator as input. See test_base_point2 */ @@ -54,415 +74,251 @@ const BASE_POINT2_Y: [u8; 32] = [ 0x80, 0x7b, 0xcb, 0xa1, 0xdf, 0x0d, 0xf0, 0x7a, 0x82, 0x17, 0xe9, 0xf7, 0xf7, 0xc2, 0xbe, 0x88, ]; -pub type SK = SecretKey; -pub type PK = PublicKey; +/// SK wraps secp256k1::SecretKey and implements Zeroize to it +#[derive(Clone, PartialEq, Debug)] +pub struct SK(pub SecretKey); +/// PK wraps secp256k1::PublicKey and implements Zeroize to it +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct PK(pub PublicKey); -#[derive(Clone, Debug, Copy)] -pub struct Secp256k1Scalar { - purpose: &'static str, - fe: SK, +impl ops::Deref for SK { + type Target = SecretKey; + + fn deref(&self) -> &Self::Target { + &self.0 + } } -#[derive(Clone, Debug, Copy)] -pub struct Secp256k1Point { - purpose: &'static str, - ge: PK, +impl ops::DerefMut for SK { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } } -pub type GE = Secp256k1Point; -pub type FE = Secp256k1Scalar; - -impl Secp256k1Point { - pub fn random_point() -> Secp256k1Point { - let random_scalar: Secp256k1Scalar = Secp256k1Scalar::new_random(); - let base_point = Secp256k1Point::generator(); - let pk = base_point.scalar_mul(&random_scalar.get_element()); - Secp256k1Point { - purpose: "random_point", - ge: pk.get_element(), - } + +impl ops::Deref for PK { + type Target = PublicKey; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl ops::DerefMut for PK { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 } } -impl Zeroize for Secp256k1Scalar { +impl Zeroize for SK { fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, FE::zero()) }; + let sk = self.0.as_mut_ptr(); + let sk_bytes = unsafe { std::slice::from_raw_parts_mut(sk, 32) }; + sk_bytes.zeroize() + } +} + +impl Zeroize for PK { + fn zeroize(&mut self) { + let zeroed = unsafe { secp256k1::ffi::PublicKey::new() }; + unsafe { ptr::write_volatile(self.0.as_mut_ptr(), zeroed) }; atomic::fence(atomic::Ordering::SeqCst); atomic::compiler_fence(atomic::Ordering::SeqCst); } } +#[derive(Clone, Debug, PartialEq)] +pub enum Secp256k1 {} + +impl Curve for Secp256k1 { + type Point = GE; + type Scalar = FE; + + fn curve_name() -> &'static str { + "secp256k1" + } +} + +#[derive(Clone, Debug)] +pub struct Secp256k1Scalar { + purpose: &'static str, + /// Zeroizing wraps SK and zeroize it on drop + /// + /// `fe` might be None — special case for scalar being zero + fe: zeroize::Zeroizing>, +} +#[derive(Clone, Debug, Copy)] +pub struct Secp256k1Point { + purpose: &'static str, + ge: Option, +} + +type GE = Secp256k1Point; +type FE = Secp256k1Scalar; + impl ECScalar for Secp256k1Scalar { - type SecretKey = SK; + type Underlying = Option; - fn new_random() -> Secp256k1Scalar { + fn random() -> Secp256k1Scalar { + let sk = SK(SecretKey::new(&mut thread_rng())); Secp256k1Scalar { purpose: "random", - fe: SecretKey::new(&mut thread_rng()), + fe: Zeroizing::new(Some(sk)), } } fn zero() -> Secp256k1Scalar { - let zero_arr = [0u8; 32]; - let zero = unsafe { std::mem::transmute::<[u8; 32], SecretKey>(zero_arr) }; Secp256k1Scalar { purpose: "zero", - fe: zero, + fe: Zeroizing::new(None), } } - fn get_element(&self) -> SK { - self.fe + fn is_zero(&self) -> bool { + self.fe.is_none() } - fn set_element(&mut self, element: SK) { - self.fe = element - } + fn from_bigint(n: &BigInt) -> Secp256k1Scalar { + if n.is_zero() { + return Self::zero(); + } - fn from(n: &BigInt) -> Secp256k1Scalar { - let curve_order = FE::q(); - let n_reduced = BigInt::mod_add(n, &BigInt::from(0), &curve_order); - let mut v = BigInt::to_bytes(&n_reduced); + let curve_order = Self::curve_order(); + let n_reduced = n.modulus(curve_order); + let bytes = BigInt::to_bytes(&n_reduced); - if v.len() < SECRET_KEY_SIZE { - let mut template = vec![0; SECRET_KEY_SIZE - v.len()]; - template.extend_from_slice(&v); - v = template; - } + let bytes = if bytes.len() < SECRET_KEY_SIZE { + let mut zero_prepended = vec![0; SECRET_KEY_SIZE - bytes.len()]; + zero_prepended.extend_from_slice(&bytes); + zero_prepended + } else { + bytes + }; Secp256k1Scalar { - purpose: "from_big_int", - fe: SK::from_slice(&v).unwrap(), + purpose: "from_bigint", + fe: Zeroizing::new(SecretKey::from_slice(&bytes).map(SK).ok()), } } - fn to_big_int(&self) -> BigInt { - BigInt::from_bytes(&(self.fe[0..self.fe.len()])) - } - - fn q() -> BigInt { - BigInt::from_bytes(CURVE_ORDER.as_ref()) + fn to_bigint(&self) -> BigInt { + match self.fe.deref() { + Some(sk) => BigInt::from_bytes(&sk[..]), + None => BigInt::zero(), + } } - fn add(&self, other: &SK) -> Secp256k1Scalar { - let mut other_scalar: FE = ECScalar::new_random(); - other_scalar.set_element(*other); - let res: FE = ECScalar::from(&BigInt::mod_add( - &self.to_big_int(), - &other_scalar.to_big_int(), - &FE::q(), - )); + fn add(&self, other: &Self) -> Secp256k1Scalar { + // TODO: use add_assign? + // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.add_assign + let n = BigInt::mod_add(&self.to_bigint(), &other.to_bigint(), Self::curve_order()); Secp256k1Scalar { purpose: "add", - fe: res.get_element(), + fe: Self::from_bigint(&n).fe, } } - fn mul(&self, other: &SK) -> Secp256k1Scalar { - let mut other_scalar: FE = ECScalar::new_random(); - other_scalar.set_element(*other); - let res: FE = ECScalar::from(&BigInt::mod_mul( - &self.to_big_int(), - &other_scalar.to_big_int(), - &FE::q(), - )); + fn mul(&self, other: &Self) -> Secp256k1Scalar { + // TODO: use mul_assign? + // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.mul_assign + let n = BigInt::mod_mul(&self.to_bigint(), &other.to_bigint(), Self::curve_order()); Secp256k1Scalar { purpose: "mul", - fe: res.get_element(), + fe: Self::from_bigint(&n).fe, } } - fn sub(&self, other: &SK) -> Secp256k1Scalar { - let mut other_scalar: FE = ECScalar::new_random(); - other_scalar.set_element(*other); - let res: FE = ECScalar::from(&BigInt::mod_sub( - &self.to_big_int(), - &other_scalar.to_big_int(), - &FE::q(), - )); + fn sub(&self, other: &Self) -> Secp256k1Scalar { + // TODO: use negate+add_assign? + // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.negate_assign + // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.add_assign + let n = BigInt::mod_sub(&self.to_bigint(), &other.to_bigint(), Self::curve_order()); Secp256k1Scalar { purpose: "sub", - fe: res.get_element(), + fe: Self::from_bigint(&n).fe, } } - fn invert(&self) -> Secp256k1Scalar { - let bignum = self.to_big_int(); - let bn_inv = BigInt::mod_inv(&bignum, &FE::q()).unwrap(); - ECScalar::from(&bn_inv) - } -} -impl Mul for Secp256k1Scalar { - type Output = Secp256k1Scalar; - fn mul(self, other: Secp256k1Scalar) -> Secp256k1Scalar { - (&self).mul(&other.get_element()) - } -} - -impl<'o> Mul<&'o Secp256k1Scalar> for Secp256k1Scalar { - type Output = Secp256k1Scalar; - fn mul(self, other: &'o Secp256k1Scalar) -> Secp256k1Scalar { - (&self).mul(&other.get_element()) - } -} - -impl Add for Secp256k1Scalar { - type Output = Secp256k1Scalar; - fn add(self, other: Secp256k1Scalar) -> Secp256k1Scalar { - (&self).add(&other.get_element()) + fn neg(&self) -> Self { + let n = BigInt::mod_sub(&BigInt::zero(), &self.to_bigint(), Self::curve_order()); + Secp256k1Scalar { + purpose: "neg", + fe: Self::from_bigint(&n).fe, + } } -} -impl<'o> Add<&'o Secp256k1Scalar> for Secp256k1Scalar { - type Output = Secp256k1Scalar; - fn add(self, other: &'o Secp256k1Scalar) -> Secp256k1Scalar { - (&self).add(&other.get_element()) + fn invert(&self) -> Option { + let n = self.to_bigint(); + let n_inv = BigInt::mod_inv(&n, Self::curve_order()); + n_inv.map(|i| Secp256k1Scalar { + purpose: "invert", + fe: Self::from_bigint(&i).fe, + }) } -} -impl Serialize for Secp256k1Scalar { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_big_int().to_hex()) + fn curve_order() -> &'static BigInt { + &CURVE_ORDER } -} -impl<'de> Deserialize<'de> for Secp256k1Scalar { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(Secp256k1ScalarVisitor) + fn underlying_ref(&self) -> &Self::Underlying { + &self.fe } -} - -struct Secp256k1ScalarVisitor; -impl<'de> Visitor<'de> for Secp256k1ScalarVisitor { - type Value = Secp256k1Scalar; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Secp256k1Scalar") + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.fe } - fn visit_str(self, s: &str) -> Result { - let v = BigInt::from_hex(s).map_err(E::custom)?; - Ok(ECScalar::from(&v)) + fn from_underlying(u: Self::Underlying) -> Secp256k1Scalar { + Secp256k1Scalar { + purpose: "from_underlying", + fe: Zeroizing::new(u), + } } } impl PartialEq for Secp256k1Scalar { fn eq(&self, other: &Secp256k1Scalar) -> bool { - self.get_element() == other.get_element() - } -} - -impl PartialEq for Secp256k1Point { - fn eq(&self, other: &Secp256k1Point) -> bool { - self.get_element() == other.get_element() - } -} - -impl Zeroize for Secp256k1Point { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, GE::generator()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); + self.underlying_ref() == other.underlying_ref() } } impl ECPoint for Secp256k1Point { - type SecretKey = SK; - type PublicKey = PK; type Scalar = Secp256k1Scalar; + type Underlying = Option; - fn base_point2() -> Secp256k1Point { - let mut v = vec![4_u8]; - v.extend(BASE_POINT2_X.as_ref()); - v.extend(BASE_POINT2_Y.as_ref()); - Secp256k1Point { - purpose: "random", - ge: PK::from_slice(&v).unwrap(), - } - } - - fn generator() -> Secp256k1Point { - let mut v = vec![4_u8]; - v.extend(GENERATOR_X.as_ref()); - v.extend(GENERATOR_Y.as_ref()); + fn zero() -> Secp256k1Point { Secp256k1Point { - purpose: "base_fe", - ge: PK::from_slice(&v).unwrap(), - } - } - - fn get_element(&self) -> PK { - self.ge - } - - /// to return from BigInt to PK use from_bytes: - /// 1) convert BigInt::to_vec - /// 2) remove first byte [1..33] - /// 3) call from_bytes - fn bytes_compressed_to_big_int(&self) -> BigInt { - let serial = self.ge.serialize(); - BigInt::from_bytes(&serial[0..33]) - } - - fn x_coor(&self) -> Option { - let serialized_pk = PK::serialize_uncompressed(&self.ge); - let x = &serialized_pk[1..serialized_pk.len() / 2 + 1]; - let x_vec = x.to_vec(); - Some(BigInt::from_bytes(&x_vec[..])) - } - - fn y_coor(&self) -> Option { - let serialized_pk = PK::serialize_uncompressed(&self.ge); - let y = &serialized_pk[(serialized_pk.len() - 1) / 2 + 1..serialized_pk.len()]; - let y_vec = y.to_vec(); - Some(BigInt::from_bytes(&y_vec[..])) - } - - fn from_bytes(bytes: &[u8]) -> Result { - let bytes_vec = bytes.to_vec(); - let mut bytes_array_65 = [0u8; 65]; - let mut bytes_array_33 = [0u8; 33]; - - let byte_len = bytes_vec.len(); - match byte_len { - 33..=63 => { - let mut template = vec![0; 64 - bytes_vec.len()]; - template.extend_from_slice(&bytes); - let mut bytes_vec = template; - let mut template: Vec = vec![4]; - template.append(&mut bytes_vec); - let bytes_slice = &template[..]; - - bytes_array_65.copy_from_slice(&bytes_slice[0..65]); - let result = PK::from_slice(&bytes_array_65); - let test = result.map(|pk| Secp256k1Point { - purpose: "random", - ge: pk, - }); - test.map_err(|_err| ErrorKey::InvalidPublicKey) - } - - 0..=32 => { - let mut template = vec![0; 32 - bytes_vec.len()]; - template.extend_from_slice(&bytes); - let mut bytes_vec = template; - let mut template: Vec = vec![2]; - template.append(&mut bytes_vec); - let bytes_slice = &template[..]; - - bytes_array_33.copy_from_slice(&bytes_slice[0..33]); - let result = PK::from_slice(&bytes_array_33); - let test = result.map(|pk| Secp256k1Point { - purpose: "random", - ge: pk, - }); - test.map_err(|_err| ErrorKey::InvalidPublicKey) - } - _ => { - let bytes_slice = &bytes_vec[0..64]; - let mut bytes_vec = bytes_slice.to_vec(); - let mut template: Vec = vec![4]; - template.append(&mut bytes_vec); - let bytes_slice = &template[..]; - - bytes_array_65.copy_from_slice(&bytes_slice[0..65]); - let result = PK::from_slice(&bytes_array_65); - let test = result.map(|pk| Secp256k1Point { - purpose: "random", - ge: pk, - }); - test.map_err(|_err| ErrorKey::InvalidPublicKey) - } + purpose: "zero", + ge: None, } } - fn pk_to_key_slice(&self) -> Vec { - let mut v = vec![4_u8]; - let x_vec = BigInt::to_bytes(&self.x_coor().unwrap()); - let y_vec = BigInt::to_bytes(&self.y_coor().unwrap()); - - let mut raw_x: Vec = Vec::new(); - let mut raw_y: Vec = Vec::new(); - raw_x.extend(vec![0u8; 32 - x_vec.len()]); - raw_x.extend(x_vec); - - raw_y.extend(vec![0u8; 32 - y_vec.len()]); - raw_y.extend(y_vec); - - v.extend(raw_x); - v.extend(raw_y); - v - } - fn scalar_mul(&self, fe: &SK) -> Secp256k1Point { - let mut new_point = *self; - new_point - .ge - .mul_assign(get_context(), &fe[..]) - .expect("Assignment expected"); - new_point + fn is_zero(&self) -> bool { + self.ge.is_none() } - fn add_point(&self, other: &PK) -> Secp256k1Point { - Secp256k1Point { - purpose: "combine", - ge: self.ge.combine(other).unwrap(), - } + fn generator() -> &'static Secp256k1Point { + &GENERATOR } - fn sub_point(&self, other: &PK) -> Secp256k1Point { - let point = Secp256k1Point { - purpose: "sub_point", - ge: *other, - }; - let p: Vec = vec![ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 252, 47, - ]; - let order = BigInt::from_bytes(&p[..]); - let x = point.x_coor().unwrap(); - let y = point.y_coor().unwrap(); - let minus_y = BigInt::mod_sub(&order, &y, &order); - - let x_vec = BigInt::to_bytes(&x); - let y_vec = BigInt::to_bytes(&minus_y); - - let mut template_x = vec![0; 32 - x_vec.len()]; - template_x.extend_from_slice(&x_vec); - let mut x_vec = template_x; - - let mut template_y = vec![0; 32 - y_vec.len()]; - template_y.extend_from_slice(&y_vec); - let y_vec = template_y; - - x_vec.extend_from_slice(&y_vec); - - let minus_point: GE = ECPoint::from_bytes(&x_vec).unwrap(); - //let minus_point: GE = ECPoint::from_coor(&x, &y_inv); - ECPoint::add_point(self, &minus_point.get_element()) + fn base_point2() -> &'static Secp256k1Point { + &BASE_POINT2 } - fn from_coor(x: &BigInt, y: &BigInt) -> Secp256k1Point { + fn from_coords(x: &BigInt, y: &BigInt) -> Result { let mut vec_x = BigInt::to_bytes(x); let mut vec_y = BigInt::to_bytes(y); let coor_size = (UNCOMPRESSED_PUBLIC_KEY_SIZE - 1) / 2; if vec_x.len() < coor_size { // pad - let mut x_buffer = vec![0; coor_size - vec_x.len()]; - x_buffer.extend_from_slice(&vec_x); - vec_x = x_buffer + let mut x_padded = vec![0; coor_size - vec_x.len()]; + x_padded.extend_from_slice(&vec_x); + vec_x = x_padded } if vec_y.len() < coor_size { // pad - let mut y_buffer = vec![0; coor_size - vec_y.len()]; - y_buffer.extend_from_slice(&vec_y); - vec_y = y_buffer + let mut y_padded = vec![0; coor_size - vec_y.len()]; + y_padded.extend_from_slice(&vec_y); + vec_y = y_padded } assert_eq!(x, &BigInt::from_bytes(vec_x.as_ref())); @@ -472,366 +328,359 @@ impl ECPoint for Secp256k1Point { v.extend(vec_x); v.extend(vec_y); - Secp256k1Point { - purpose: "base_fe", - ge: PK::from_slice(&v).unwrap(), - } + PublicKey::from_slice(&v) + .map(|ge| Secp256k1Point { + purpose: "from_coords", + ge: Some(PK(ge)), + }) + .map_err(|_| NotOnCurve) } -} -static mut CONTEXT: Option> = None; -pub fn get_context() -> &'static Secp256k1 { - static INIT_CONTEXT: Once = Once::new(); - INIT_CONTEXT.call_once(|| unsafe { - CONTEXT = Some(Secp256k1::verification_only()); - }); - unsafe { CONTEXT.as_ref().unwrap() } -} - -#[cfg(feature = "merkle")] -impl Hashable for Secp256k1Point { - fn update_context(&self, context: &mut Sha3) { - let bytes: Vec = self.pk_to_key_slice(); - context.input(&bytes[..]); - } -} - -impl Mul for Secp256k1Point { - type Output = Secp256k1Point; - fn mul(self, other: Secp256k1Scalar) -> Self::Output { - self.scalar_mul(&other.get_element()) + fn x_coord(&self) -> Option { + match &self.ge { + Some(ge) => { + let serialized_pk = ge.serialize_uncompressed(); + let x = &serialized_pk[1..serialized_pk.len() / 2 + 1]; + Some(BigInt::from_bytes(x)) + } + None => None, + } } -} -impl<'o> Mul<&'o Secp256k1Scalar> for Secp256k1Point { - type Output = Secp256k1Point; - fn mul(self, other: &'o Secp256k1Scalar) -> Self::Output { - self.scalar_mul(&other.get_element()) + fn y_coord(&self) -> Option { + match &self.ge { + Some(ge) => { + let serialized_pk = ge.serialize_uncompressed(); + let y = &serialized_pk[(serialized_pk.len() - 1) / 2 + 1..serialized_pk.len()]; + Some(BigInt::from_bytes(y)) + } + None => None, + } } -} -impl<'o> Mul<&'o Secp256k1Scalar> for &'o Secp256k1Point { - type Output = Secp256k1Point; - fn mul(self, other: &'o Secp256k1Scalar) -> Self::Output { - self.scalar_mul(&other.get_element()) + fn coords(&self) -> Option { + match &self.ge { + Some(ge) => { + let serialized_pk = ge.serialize_uncompressed(); + let x = &serialized_pk[1..serialized_pk.len() / 2 + 1]; + let y = &serialized_pk[(serialized_pk.len() - 1) / 2 + 1..serialized_pk.len()]; + Some(PointCoords { + x: BigInt::from_bytes(x), + y: BigInt::from_bytes(y), + }) + } + None => None, + } } -} -impl Add for Secp256k1Point { - type Output = Secp256k1Point; - fn add(self, other: Secp256k1Point) -> Self::Output { - self.add_point(&other.get_element()) + fn serialize(&self, compressed: bool) -> Option> { + let ge = self.ge.as_ref()?; + if compressed { + Some(ge.serialize().to_vec()) + } else { + // TODO: why not using ge.serialize_uncompressed()? + // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.PublicKey.html#method.serialize_uncompressed + let mut v = vec![4_u8]; + let x_vec = BigInt::to_bytes( + &self + .x_coord() + .expect("guaranteed by the first line of this function"), + ); + let y_vec = BigInt::to_bytes( + &self + .y_coord() + .expect("guaranteed by the first line of this function"), + ); + + let mut raw_x: Vec = Vec::new(); + let mut raw_y: Vec = Vec::new(); + raw_x.extend(vec![0u8; 32 - x_vec.len()]); + raw_x.extend(x_vec); + + raw_y.extend(vec![0u8; 32 - y_vec.len()]); + raw_y.extend(y_vec); + + v.extend(raw_x); + v.extend(raw_y); + Some(v) + } } -} -impl<'o> Add<&'o Secp256k1Point> for Secp256k1Point { - type Output = Secp256k1Point; - fn add(self, other: &'o Secp256k1Point) -> Self::Output { - self.add_point(&other.get_element()) + fn deserialize(bytes: &[u8]) -> Result { + let pk = PublicKey::from_slice(bytes).map_err(|_| DeserializationError)?; + Ok(Secp256k1Point { + purpose: "from_bytes", + ge: Some(PK(pk)), + }) } -} -impl<'o> Add<&'o Secp256k1Point> for &'o Secp256k1Point { - type Output = Secp256k1Point; - fn add(self, other: &'o Secp256k1Point) -> Self::Output { - self.add_point(&other.get_element()) - } -} + fn scalar_mul(&self, scalar: &Self::Scalar) -> Secp256k1Point { + let mut new_point = match &self.ge { + Some(ge) => *ge, + None => { + // Point is zero => O * a = O + return Secp256k1Point { + purpose: "mul", + ge: None, + }; + } + }; + let scalar = match scalar.fe.deref() { + Some(s) => s, + None => { + // Scalar is zero => p * 0 = O + return Secp256k1Point { + purpose: "mul", + ge: None, + }; + } + }; + let result = new_point.mul_assign(&CONTEXT, &scalar[..]); + if result.is_err() { + // Multiplication resulted into zero point + return Secp256k1Point { + purpose: "mul", + ge: None, + }; + } -impl Serialize for Secp256k1Point { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut state = serializer.serialize_struct("Secp256k1Point", 2)?; - state.serialize_field("x", &self.x_coor().unwrap().to_hex())?; - state.serialize_field("y", &self.y_coor().unwrap().to_hex())?; - state.end() + Secp256k1Point { + purpose: "mul", + ge: Some(new_point), + } } -} -impl<'de> Deserialize<'de> for Secp256k1Point { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let fields = &["x", "y"]; - deserializer.deserialize_struct("Secp256k1Point", fields, Secp256k1PointVisitor) + fn add_point(&self, other: &Self) -> Secp256k1Point { + let ge1 = match &self.ge { + Some(ge) => ge, + None => { + // Point1 is zero => O + p2 = p2 + return Secp256k1Point { + purpose: "add", + ge: other.ge, + }; + } + }; + let ge2 = match &other.ge { + Some(ge) => ge, + None => { + // Point2 is zero => p1 + O = p1 + return Secp256k1Point { + purpose: "add", + ge: Some(*ge1), + }; + } + }; + Secp256k1Point { + purpose: "add", + ge: ge1.combine(ge2).map(PK).ok(), + } } -} -struct Secp256k1PointVisitor; - -impl<'de> Visitor<'de> for Secp256k1PointVisitor { - type Value = Secp256k1Point; + fn sub_point(&self, other: &Self) -> Secp256k1Point { + let mut ge2_negated = match &other.ge { + Some(ge) => *ge, + None => { + // Point2 is zero => p1 - O = p1 + return Secp256k1Point { + purpose: "sub", + ge: self.ge, + }; + } + }; + ge2_negated.negate_assign(&CONTEXT); + + let ge1 = match &self.ge { + Some(ge) => ge, + None => { + // Point1 is zero => O - p2 = -p2 + return Secp256k1Point { + purpose: "sub", + ge: Some(ge2_negated), + }; + } + }; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Secp256k1Point") + Secp256k1Point { + purpose: "sub", + ge: ge1.combine(&ge2_negated).map(PK).ok(), + } } - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let x = seq - .next_element()? - .ok_or_else(|| V::Error::invalid_length(0, &"a single element"))?; - let y = seq - .next_element()? - .ok_or_else(|| V::Error::invalid_length(0, &"a single element"))?; - - let bx = BigInt::from_hex(x).map_err(V::Error::custom)?; - let by = BigInt::from_hex(y).map_err(V::Error::custom)?; - - Ok(Secp256k1Point::from_coor(&bx, &by)) + fn neg_point(&self) -> Secp256k1Point { + Secp256k1Point { + purpose: "neg", + ge: match self.ge { + Some(mut ge) => { + ge.negate_assign(&CONTEXT); + Some(ge) + } + None => { + // Point is zero => -O = O + None + } + }, + } } - fn visit_map>(self, mut map: E) -> Result { - let mut x = String::new(); - let mut y = String::new(); - - while let Some(ref key) = map.next_key::()? { - let v = map.next_value::()?; - if key == "x" { - x = v - } else if key == "y" { - y = v - } else { - return Err(E::Error::unknown_field(key, &["x", "y"])); + fn scalar_mul_assign(&mut self, scalar: &Self::Scalar) { + let ge = match self.ge.as_mut() { + Some(ge) => ge, + None => { + // Point is zero => O * s = O + self.ge = None; + return; } - } + }; - let bx = BigInt::from_hex(&x).map_err(E::Error::custom)?; - let by = BigInt::from_hex(&y).map_err(E::Error::custom)?; + let fe = match scalar.fe.as_ref() { + Some(fe) => fe, + None => { + // Scalar is zero => p * 0 = O + self.ge = None; + return; + } + }; - Ok(Secp256k1Point::from_coor(&bx, &by)) + if let Err(_) = ge.mul_assign(&CONTEXT, &fe[..]) { + // Multiplication resulted into zero + self.ge = None + } } -} - -#[cfg(test)] -mod tests { - use super::BigInt; - use super::Secp256k1Point; - use super::Secp256k1Scalar; - use crate::arithmetic::traits::*; - use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; - use crate::cryptographic_primitives::hashing::traits::Hash; - use crate::elliptic::curves::traits::ECPoint; - use crate::elliptic::curves::traits::ECScalar; - #[test] - fn serialize_sk() { - let scalar: Secp256k1Scalar = ECScalar::from(&BigInt::from(123456)); - let s = serde_json::to_string(&scalar).expect("Failed in serialization"); - assert_eq!(s, "\"1e240\""); + fn underlying_ref(&self) -> &Self::Underlying { + &self.ge } - - #[test] - fn serialize_rand_pk_verify_pad() { - let vx = BigInt::from_hex( - &"ccaf75ab7960a01eb421c0e2705f6e84585bd0a094eb6af928c892a4a2912508".to_string(), - ) - .unwrap(); - - let vy = BigInt::from_hex( - &"e788e294bd64eee6a73d2fc966897a31eb370b7e8e9393b0d8f4f820b48048df".to_string(), - ) - .unwrap(); - - Secp256k1Point::from_coor(&vx, &vy); // x and y of size 32 - - let x = BigInt::from_hex( - &"5f6853305467a385b56a5d87f382abb52d10835a365ec265ce510e04b3c3366f".to_string(), - ) - .unwrap(); - - let y = BigInt::from_hex( - &"b868891567ca1ee8c44706c0dc190dd7779fe6f9b92ced909ad870800451e3".to_string(), - ) - .unwrap(); - - Secp256k1Point::from_coor(&x, &y); // x and y not of size 32 each - - let r = Secp256k1Point::random_point(); - let r_expected = Secp256k1Point::from_coor(&r.x_coor().unwrap(), &r.y_coor().unwrap()); - - assert_eq!(r.x_coor().unwrap(), r_expected.x_coor().unwrap()); - assert_eq!(r.y_coor().unwrap(), r_expected.y_coor().unwrap()); + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.ge } - - #[test] - fn deserialize_sk() { - let s = "\"1e240\""; - let dummy: Secp256k1Scalar = serde_json::from_str(s).expect("Failed in serialization"); - - let sk: Secp256k1Scalar = ECScalar::from(&BigInt::from(123456)); - - assert_eq!(dummy, sk); + fn from_underlying(ge: Self::Underlying) -> Secp256k1Point { + Secp256k1Point { + purpose: "from_underlying", + ge, + } } +} - #[test] - fn serialize_pk() { - let pk = Secp256k1Point::generator(); - let x = pk.x_coor().unwrap(); - let y = pk.y_coor().unwrap(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - - let expected = format!("{{\"x\":\"{}\",\"y\":\"{}\"}}", x.to_hex(), y.to_hex()); - assert_eq!(s, expected); - - let des_pk: Secp256k1Point = serde_json::from_str(&s).expect("Failed in serialization"); - assert_eq!(des_pk.ge, pk.ge); +impl PartialEq for Secp256k1Point { + fn eq(&self, other: &Secp256k1Point) -> bool { + self.underlying_ref() == other.underlying_ref() } +} - #[test] - fn bincode_pk() { - let pk = Secp256k1Point::generator(); - let bin = bincode::serialize(&pk).unwrap(); - let decoded: Secp256k1Point = bincode::deserialize(bin.as_slice()).unwrap(); - assert_eq!(decoded, pk); +impl Zeroize for Secp256k1Point { + fn zeroize(&mut self) { + self.ge.zeroize() } +} - use crate::elliptic::curves::secp256_k1::{FE, GE}; - use crate::ErrorKey; +#[cfg(test)] +mod test { + use std::iter; - #[test] - fn test_serdes_pk() { - let pk = GE::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); + use crate::elliptic::curves::traits::*; + use crate::BigInt; - let pk = GE::base_point2(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); - } + use super::{FE, GE}; #[test] - #[should_panic] - fn test_serdes_bad_pk() { - let pk = GE::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - // we make sure that the string encodes invalid point: - let s: String = s.replace("79be", "79bf"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); + fn valid_zero_point() { + let zero = GE::zero(); + assert!(zero.is_zero()); + assert_eq!(zero, GE::zero()); } #[test] - fn test_from_bytes() { - let g = Secp256k1Point::generator(); - let hash = HSha256::create_hash(&[&g.bytes_compressed_to_big_int()]); - let hash_vec = BigInt::to_bytes(&hash); - let result = Secp256k1Point::from_bytes(&hash_vec); - assert_eq!(result.unwrap_err(), ErrorKey::InvalidPublicKey) - } + fn zero_point_arithmetic() { + let zero_point = GE::zero(); + let point = GE::generator().scalar_mul(&FE::random()); - #[test] - fn test_from_bytes_3() { - let test_vec = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 3, 4, 5, 6, - ]; - let result = Secp256k1Point::from_bytes(&test_vec); - assert!(result.is_ok() | result.is_err()) - } + assert_eq!(zero_point.add_point(&point), point, "O + P = P"); + assert_eq!(point.add_point(&zero_point), point, "P + O = P"); - #[test] - fn test_from_bytes_4() { - let test_vec = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, - ]; - let result = Secp256k1Point::from_bytes(&test_vec); - assert!(result.is_ok() | result.is_err()) - } + let point_neg = point.neg_point(); + assert!(point.add_point(&point_neg).is_zero(), "P + (-P) = O"); + assert!(point.sub_point(&point).is_zero(), "P - P = O"); - #[test] - fn test_from_bytes_5() { - let test_vec = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, - 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, - 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, - 4, 5, 6, - ]; - let result = Secp256k1Point::from_bytes(&test_vec); - assert!(result.is_ok() | result.is_err()) + let zero_scalar = FE::zero(); + assert!(point.scalar_mul(&zero_scalar).is_zero(), "P * 0 = O"); + let scalar = FE::random(); + assert!(zero_point.scalar_mul(&scalar).is_zero(), "O * s = O") } #[test] - fn test_minus_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let b_bn = b.to_big_int(); - let order = FE::q(); - let minus_b = BigInt::mod_sub(&order, &b_bn, &order); - let a_minus_b = BigInt::mod_add(&a.to_big_int(), &minus_b, &order); - let a_minus_b_fe: FE = ECScalar::from(&a_minus_b); - let base: GE = ECPoint::generator(); - let point_ab1 = base * a_minus_b_fe; - - let point_a = base * a; - let point_b = base * b; - let point_ab2 = point_a.sub_point(&point_b.get_element()); - assert_eq!(point_ab1.get_element(), point_ab2.get_element()); - } + fn scalar_modulo_curve_order() { + let n = FE::curve_order(); + let s = FE::from_bigint(n); + assert!(s.is_zero()); - #[test] - fn test_invert() { - let a: FE = ECScalar::new_random(); - let a_bn = a.to_big_int(); - let a_inv = a.invert(); - let a_inv_bn_1 = BigInt::mod_inv(&a_bn, &FE::q()).unwrap(); - let a_inv_bn_2 = a_inv.to_big_int(); - assert_eq!(a_inv_bn_1, a_inv_bn_2); + let s = FE::from_bigint(&(n + 1)); + assert_eq!(s, FE::from_bigint(&BigInt::from(1))); } #[test] - fn test_scalar_mul_scalar() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let c1 = a.mul(&b.get_element()); - let c2 = a * b; - assert_eq!(c1.get_element(), c2.get_element()); + fn zero_scalar_arithmetic() { + let s = FE::random(); + let z = FE::zero(); + assert!(s.mul(&z).is_zero()); + assert!(z.mul(&s).is_zero()); + assert_eq!(s.add(&z), s); + assert_eq!(z.add(&s), s); } #[test] - fn test_pk_to_key_slice() { - for _ in 1..200 { - let r = FE::new_random(); - let rg = GE::generator() * r; - let key_slice = rg.pk_to_key_slice(); + fn point_addition_multiplication() { + let point = GE::generator().scalar_mul(&FE::random()); + assert!(!point.is_zero(), "G * s != O"); - assert!(key_slice.len() == 65); - assert!(key_slice[0] == 4); - - let rg_prime: GE = ECPoint::from_bytes(&key_slice[1..65]).unwrap(); - assert_eq!(rg_prime.get_element(), rg.get_element()); - } + let addition = iter::successors(Some(point), |p| Some(p.add_point(&point))) + .take(10) + .collect::>(); + let multiplication = (1..=10) + .map(|i| FE::from_bigint(&BigInt::from(i))) + .map(|s| point.scalar_mul(&s)) + .collect::>(); + assert_eq!(addition, multiplication); } #[test] - fn test_base_point2() { - /* Show that base_point2() is returning a point of unknown discrete logarithm. - It is done by using SHA256 repeatedly as a pseudo-random function, with the generator - as the initial input, until receiving a valid Secp256k1 point. */ - - let base_point2 = Secp256k1Point::base_point2(); - - let g = Secp256k1Point::generator(); - let mut hash = HSha256::create_hash(&[&g.bytes_compressed_to_big_int()]); - hash = HSha256::create_hash(&[&hash]); - hash = HSha256::create_hash(&[&hash]); - - assert_eq!(hash, base_point2.x_coor().unwrap(),); - - // check that base_point2 is indeed on the curve (from_coor() will fail otherwise) - assert_eq!( - Secp256k1Point::from_coor( - &base_point2.x_coor().unwrap(), - &base_point2.y_coor().unwrap() - ), - base_point2 - ); - } + fn serialize_deserialize() { + let point = GE::generator().scalar_mul(&FE::random()); + let bytes = point + .serialize(true) + .expect("point has coordinates => must be serializable"); + let deserialized = GE::deserialize(&bytes).unwrap(); + assert_eq!(point, deserialized); + + let bytes = point + .serialize(false) + .expect("point has coordinates => must be serializable"); + let deserialized = GE::deserialize(&bytes).unwrap(); + assert_eq!(point, deserialized); + } + + // #[test] + // fn test_base_point2() { + // /* Show that base_point2() is returning a point of unknown discrete logarithm. + // It is done by using SHA256 repeatedly as a pseudo-random function, with the generator + // as the initial input, until receiving a valid Secp256k1 point. */ + // + // let base_point2 = GE::base_point2(); + // + // let g = GE::generator(); + // let mut hash = HSha256::create_hash(&[&g.bytes_compressed_to_big_int()]); + // hash = HSha256::create_hash(&[&hash]); + // hash = HSha256::create_hash(&[&hash]); + // + // assert_eq!(hash, base_point2.x_coor().unwrap(),); + // + // // check that base_point2 is indeed on the curve (from_coor() will fail otherwise) + // assert_eq!( + // Secp256k1Point::from_coor( + // &base_point2.x_coor().unwrap(), + // &base_point2.y_coor().unwrap() + // ), + // base_point2 + // ); + // } } diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index ff029c6c..bd57200a 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -5,48 +5,212 @@ License MIT: */ -use std::ops::{Add, Mul}; +use std::fmt; use crate::BigInt; -use crate::ErrorKey; +use zeroize::Zeroize; -pub trait ECScalar: Mul + Add + Sized { - type SecretKey; +/// Elliptic curve implementation +/// +/// Refers to according implementation of [ECPoint] and [ECScalar]. +pub trait Curve { + type Point: ECPoint; + type Scalar: ECScalar; - fn new_random() -> Self; + /// Returns canonical name for this curve + fn curve_name() -> &'static str; +} + +/// Scalar value modulus [curve order](Self::curve_order) +/// +/// ## Note +/// This is a low-level trait, you should not use it directly. See wrappers [Point], [PointZ], +/// [Scalar], [ScalarZ]. +/// +/// [Point]: super::wrappers::Point +/// [PointZ]: super::wrappers::PointZ +/// [Scalar]: super::wrappers::Scalar +/// [ScalarZ]: super::wrappers::ScalarZ +/// +/// Trait exposes various methods to manipulate scalars. Scalar can be zero. Scalar must zeroize its +/// value on drop. +pub trait ECScalar: Clone + PartialEq + fmt::Debug { + /// Underlying scalar type that can be retrieved in case of missing methods in this trait + type Underlying; + + /// Samples a random scalar + fn random() -> Self; + + /// Constructs a zero scalar fn zero() -> Self; - fn get_element(&self) -> Self::SecretKey; - fn set_element(&mut self, element: Self::SecretKey); - fn from(n: &BigInt) -> Self; - fn to_big_int(&self) -> BigInt; - fn q() -> BigInt; - fn add(&self, other: &Self::SecretKey) -> Self; - fn mul(&self, other: &Self::SecretKey) -> Self; - fn sub(&self, other: &Self::SecretKey) -> Self; - fn invert(&self) -> Self; + /// Checks if the scalar equals to zero + fn is_zero(&self) -> bool; + + /// Constructs a scalar `n % curve_order` + fn from_bigint(n: &BigInt) -> Self; + /// Converts a scalar to BigInt + fn to_bigint(&self) -> BigInt; + + /// Calculates `(self + other) mod curve_order` + fn add(&self, other: &Self) -> Self; + /// Calculates `(self * other) mod curve_order` + fn mul(&self, other: &Self) -> Self; + /// Calculates `(self - other) mod curve_order` + fn sub(&self, other: &Self) -> Self; + /// Calculates `-self mod curve_order` + fn neg(&self) -> Self; + /// Calculates `self^-1 (mod curve_order)`, returns None if self equals to zero + fn invert(&self) -> Option; + /// Calculates `(self + other) mod curve_order`, and assigns result to `self` + fn add_assign(&mut self, other: &Self) { + *self = self.add(other) + } + /// Calculates `(self * other) mod curve_order`, and assigns result to `self` + fn mul_assign(&mut self, other: &Self) { + *self = self.mul(other) + } + /// Calculates `(self - other) mod curve_order`, and assigns result to `self` + fn sub_assign(&mut self, other: &Self) { + *self = self.sub(other) + } + /// Calculates `-self mod curve_order`, and assigns result to `self` + fn neg_assign(&mut self) { + *self = self.neg() + } + + fn curve_order() -> &'static BigInt; + + /// Returns a reference to underlying scalar value + fn underlying_ref(&self) -> &Self::Underlying; + /// Returns a mutable reference to underlying scalar value + fn underlying_mut(&mut self) -> &mut Self::Underlying; + /// Constructs a scalar from underlying value + fn from_underlying(u: Self::Underlying) -> Self; } -// TODO: add a fn is_point -pub trait ECPoint: - Mul<::Scalar, Output = Self> + Add + PartialEq -where - Self: Sized, -{ - type SecretKey; - type PublicKey; - - type Scalar: ECScalar; - - fn base_point2() -> Self; - fn generator() -> Self; - fn get_element(&self) -> Self::PublicKey; - fn x_coor(&self) -> Option; - fn y_coor(&self) -> Option; - fn bytes_compressed_to_big_int(&self) -> BigInt; - fn from_bytes(bytes: &[u8]) -> Result; - fn pk_to_key_slice(&self) -> Vec; - fn scalar_mul(&self, fe: &Self::SecretKey) -> Self; - fn add_point(&self, other: &Self::PublicKey) -> Self; - fn sub_point(&self, other: &Self::PublicKey) -> Self; - fn from_coor(x: &BigInt, y: &BigInt) -> Self; +/// Point on elliptic curve +/// +/// ## Note +/// This is a low-level trait, you should not use it directly. See [Point], [PointZ], [Scalar], +/// [ScalarZ]. +/// +/// [Point]: super::wrappers::Point +/// [PointZ]: super::wrappers::PointZ +/// [Scalar]: super::wrappers::Scalar +/// [ScalarZ]: super::wrappers::ScalarZ +/// +/// Trait exposes various methods that make elliptic curve arithmetic. The point can +/// be [zero](ECPoint::zero). Unlike [ECScalar], ECPoint isn't required to zeroize its value on drop, +/// but it implementы [Zeroize] trait so you can force zeroizing policy on your own. +pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug { + /// Scalar value the point can be multiplied at + type Scalar: ECScalar; + /// Underlying curve implementation that can be retrieved in case of missing methods in this trait + type Underlying; + + /// Zero point + /// + /// Zero point is usually denoted as O. It's curve neutral element, i.e. `forall A. A + O = A`. + /// Weierstrass and Montgomery curves employ special "point at infinity" to add neutral elements, + /// such points don't have coordinates (i.e. [from_coords], [x_coord], [y_coord] return `None`). + /// Edwards curves' neutral element has coordinates. + /// + /// [from_coords]: Self::from_coords + /// [x_coord]: Self::x_coord + /// [y_coord]: Self::y_coord + fn zero() -> Self; + + /// Returns `true` if point is a neutral element + fn is_zero(&self) -> bool; + + /// Curve generator + /// + /// Returns a static reference at actual value because in most cases reference value is fine. + /// Use `.clone()` if you need to take it by value, i.e. `ECPoint::generator().clone()` + fn generator() -> &'static Self; + /// Curve second generator + /// + /// We provide an alternative generator value and prove that it was picked randomly + fn base_point2() -> &'static Self; + + /// Constructs a curve point from its coordinates + /// + /// Returns error if x, y are not on curve + fn from_coords(x: &BigInt, y: &BigInt) -> Result; + /// Returns `x` coordinate of the point, or `None` if point is at infinity + fn x_coord(&self) -> Option; + /// Returns `y` coordinate of the point, or `None` if point is at infinity + fn y_coord(&self) -> Option; + /// Returns point coordinates (`x` and `y`), or `None` if point is at infinity + fn coords(&self) -> Option; + + /// Serializes point into bytes either in compressed or uncompressed form + /// + /// Returns None if point doesn't have coordinates, ie. it is "at infinity". If point isn't + /// at infinity, serialize always succeeds. + fn serialize(&self, compressed: bool) -> Option>; + /// Deserializes point from bytes + /// + /// Whether point in compressed or uncompressed form will be deducted from its size + fn deserialize(bytes: &[u8]) -> Result; + + /// Multiplies the point at scalar value + fn scalar_mul(&self, scalar: &Self::Scalar) -> Self; + /// Adds two points + fn add_point(&self, other: &Self) -> Self; + /// Substrates `other` from `self` + fn sub_point(&self, other: &Self) -> Self; + /// Negates point + fn neg_point(&self) -> Self; + + /// Multiplies the point at scalar value, assigns result to `self` + fn scalar_mul_assign(&mut self, scalar: &Self::Scalar) { + *self = self.scalar_mul(scalar) + } + /// Adds two points, assigns result to `self` + fn add_point_assign(&mut self, other: &Self) { + *self = self.add_point(other) + } + /// Substrates `other` from `self`, assigns result to `self` + fn sub_point_assign(&mut self, other: &Self) { + *self = self.sub_point(other) + } + /// Negates point, assigns result to `self` + fn neg_point_assign(&mut self) { + *self = self.neg_point() + } + + /// Reference to underlying curve implementation + fn underlying_ref(&self) -> &Self::Underlying; + /// Mutual reference to underlying curve implementation + fn underlying_mut(&mut self) -> &mut Self::Underlying; + /// Construct a point from its underlying representation + fn from_underlying(u: Self::Underlying) -> Self; } + +pub struct PointCoords { + pub x: BigInt, + pub y: BigInt, +} + +#[derive(Debug)] +pub struct DeserializationError; + +impl fmt::Display for DeserializationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "failed to deserialize the point") + } +} + +impl std::error::Error for DeserializationError {} + +#[derive(Debug)] +pub struct NotOnCurve; + +impl fmt::Display for NotOnCurve { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "point not on the curve") + } +} + +impl std::error::Error for NotOnCurve {} diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs new file mode 100644 index 00000000..5411a941 --- /dev/null +++ b/src/elliptic/curves/wrappers.rs @@ -0,0 +1,1282 @@ +use std::borrow::Cow; +use std::convert::TryFrom; +use std::{fmt, iter, ops}; + +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use super::traits::*; +use crate::arithmetic::{BigInt, Converter}; + +/// Elliptic point that **might be zero** +/// +/// ## Security +/// +/// Mistakenly used zero point might break security of cryptographic algorithm. It's preferred to +/// use [`Point`](Point) that's guaranteed to be non-zero. Use [ensure_nonzero](PointZ::ensure_nonzero) +/// to convert `PointZ` into `Point`. +/// +/// ## Guarantees +/// +/// * Belongs to curve +/// +/// Any instance of `PointZ` is guaranteed to belong to curve `E`, i.e. its coordinates must +/// satisfy curve equations +/// +/// ## Arithmetics +/// +/// You can add, subtract two points, or multiply point at scalar: +/// +/// ```rust +/// # use curv::elliptic::curves::{PointZ, Scalar, Secp256k1}; +/// fn expression( +/// a: PointZ, +/// b: PointZ, +/// c: Scalar, +/// ) -> PointZ { +/// a + b * c +/// } +/// ``` +pub struct PointZ(E::Point); + +impl PointZ { + /// Checks if `self` is not zero and converts it into [`Point`](Point). Returns `None` if + /// it's zero. + pub fn ensure_nonzero(self) -> Option> { + Point::try_from(self).ok() + } + + pub fn zero() -> Self { + Self::from_raw(E::Point::zero()) + } + + pub fn iz_zero(&self) -> bool { + self.0.is_zero() + } + + pub fn coords(&self) -> Option { + self.0.coords() + } + + pub fn x_coord(&self) -> Option { + self.0.x_coord() + } + + pub fn y_coord(&self) -> Option { + self.0.y_coord() + } + + fn from_raw(point: E::Point) -> Self { + Self(point) + } +} + +impl PartialEq for PointZ { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +impl Clone for PointZ { + fn clone(&self) -> Self { + PointZ(self.0.clone()) + } +} + +impl fmt::Debug for PointZ { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +/// Elliptic point that _guaranteed_ to be non zero +/// +/// ## Security +/// Non-zero points are preferred to be used in cryptographic algorithms. Lack of checking whether +/// computation on elliptic points results into zero point might lead to vulnerabilities. Using +/// `Point` ensures you and reviewers that check on point not being zero was made. +/// +/// ## Guarantees +/// +/// * Belongs to curve +/// +/// Any instance of `Point` is guaranteed to belong to curve `E`, i.e. its coordinates must +/// satisfy curve equations +/// * Not a neutral element +/// +/// Any instance of `Point` is restricted not to be zero (neutral element), i.e. for any +/// `a: PointZ ∧ b: Point → a + b ≢ a`. +/// +/// Weierstrass and Montgomery curves represent zero point +/// using special "point at infinity", whereas Edwards curves zero point is a regular point that +/// has coordinates. `Point` cannot be instantiated with neither of these points. +/// +/// Note also that `Point` is guaranteed to have coordinates (only point at infinity doesn't). +/// +/// ## Arithmetics +/// +/// You can add, subtract two points, or multiply point at scalar. +/// +/// Any arithmetic operation on non-zero point might result into zero point, so addition, subtraction, +/// and multiplication operations output [PointZ]. Use [ensure_nonzero](PointZ::ensure_nonzero) method +/// to ensure that computation doesn't produce zero-point: +/// +/// ```rust +/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; +/// let s = Scalar::::random(); // Non-zero scalar +/// let g = Point::::generator(); // Non-zero point (curve generator) +/// let result: PointZ = s * g; // Multiplication of two non-zero points +/// // might produce zero-point +/// let nonzero_result: Option> = result.ensure_nonzero(); +/// ``` +/// +/// When evaluating complex expressions, you typically need to ensure that none of intermediate +/// results are zero-points: +/// +/// ```rust +/// # use curv::elliptic::curves::{Curve, Point, Scalar}; +/// fn expression(a: Point, b: Point, c: Scalar) -> Option> { +/// (a + (b * c).ensure_nonzero()?).ensure_nonzero() +/// } +/// ``` +pub struct Point(E::Point); + +impl Point { + fn from_raw(point: E::Point) -> Result { + if point.is_zero() { + Err(ZeroPointError(())) + } else { + Ok(Self(point)) + } + } + + /// Curve generator + /// + /// Returns a static reference on actual value because in most cases referenced value is fine. + /// Use [`.to_point_owned()`](PointRef::to_point_owned) if you need to take it by value. + pub fn generator() -> PointRef<'static, E> { + let p = E::Point::generator(); + PointRef::from_raw(p).expect("generator must be non-zero") + } + + /// Curve second generator + /// + /// We provide an alternative generator value and prove that it was picked randomly. + /// + /// Returns a static reference on actual value because in most cases referenced value is fine. + /// Use [`.to_point_owned()`](PointRef::to_point_owned) if you need to take it by value. + pub fn base_point2() -> PointRef<'static, E> { + let p = E::Point::base_point2(); + PointRef::from_raw(p).expect("base_point2 must be non-zero") + } + + /// Constructs a point from coordinates, returns error if x,y don't satisfy curve equation or + /// correspond to zero point + pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { + let p = E::Point::from_coords(x, y) + .map_err(|NotOnCurve { .. }| PointFromCoordsError::PointNotOnCurve)?; + Self::from_raw(p).map_err(|ZeroPointError(())| PointFromCoordsError::ZeroPoint) + } + + /// Tries to parse a point from its (un)compressed form + /// + /// Whether it's a compressed or uncompressed form will be deduced from its length + pub fn from_bytes(bytes: &[u8]) -> Result { + let p = E::Point::deserialize(bytes).map_err(PointFromBytesError::Deserialize)?; + Self::from_raw(p).map_err(|ZeroPointError(())| PointFromBytesError::ZeroPoint) + } + + /// Returns point coordinates (`x` and `y`) + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn coords(&self) -> PointCoords { + self.as_point_ref().coords() + } + + /// Returns `x` coordinate of point + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn x_coord(&self) -> BigInt { + self.as_point_ref().x_coord() + } + + /// Returns `y` coordinate of point + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn y_coord(&self) -> BigInt { + self.as_point_ref().y_coord() + } + + /// Adds two points, returns the result, or `None` if resulting point is zero + pub fn add_checked(&self, point: PointRef) -> Option { + self.as_point_ref().add_checked(point) + } + + /// Substrates two points, returns the result, or `None` if resulting point is zero + pub fn sub_checked(&self, point: PointRef) -> Option { + self.as_point_ref().sub_checked(point) + } + + /// Multiplies a point at scalar, returns the result, or `None` if resulting point is zero + pub fn mul_checked_z(&self, scalar: &ScalarZ) -> Option { + self.as_point_ref().mul_checked_z(scalar) + } + + /// Multiplies a point at nonzero scalar, returns the result, or `None` if resulting point is zero + pub fn mul_checked(&self, scalar: &Scalar) -> Option { + self.as_point_ref().mul_checked(scalar) + } + + /// Serializes point into (un)compressed form + pub fn to_bytes(&self, compressed: bool) -> Vec { + self.as_point_ref().to_bytes(compressed) + } + + /// Creates [PointRef] that holds a reference on `self` + pub fn as_point_ref(&self) -> PointRef { + PointRef(&self.0) + } +} + +impl Clone for Point { + fn clone(&self) -> Self { + Point(self.0.clone()) + } +} + +impl fmt::Debug for Point { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl TryFrom> for Point { + type Error = ZeroPointError; + fn try_from(point: PointZ) -> Result { + Self::from_raw(point.0) + } +} + +/// Reference on elliptic point, _guaranteed_ to be non-zero +/// +/// Holds internally a reference on [`Point`](Point), refer to its documentation to learn +/// more about Point/PointRef guarantees, security notes, and arithmetics. +pub struct PointRef<'p, E: Curve>(&'p E::Point); + +impl<'p, E: Curve> Clone for PointRef<'p, E> { + fn clone(&self) -> Self { + Self(self.0) + } +} + +impl<'p, E: Curve> Copy for PointRef<'p, E> {} + +impl<'p, E: Curve> fmt::Debug for PointRef<'p, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl PointRef<'static, E> { + pub fn generator() -> Self { + Self::from_raw(E::Point::generator()).expect("generator must be non-zero") + } + + pub fn base_point2() -> Self { + Self::from_raw(E::Point::base_point2()).expect("base_point2 must be non-zero") + } +} + +impl<'p, E> PointRef<'p, E> +where + E: Curve, +{ + fn from_raw(point: &'p E::Point) -> Option { + if point.is_zero() { + None + } else { + Some(Self(point)) + } + } + + /// Returns point coordinates (`x` and `y`) + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn coords(&self) -> PointCoords { + self.0 + .coords() + .expect("Point guaranteed to have coordinates") + } + + /// Returns `x` coordinate of point + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn x_coord(&self) -> BigInt { + self.0 + .x_coord() + .expect("Point guaranteed to have coordinates") + } + + /// Returns `y` coordinate of point + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn y_coord(&self) -> BigInt { + self.0 + .y_coord() + .expect("Point guaranteed to have coordinates") + } + + /// Adds two points, returns the result, or `None` if resulting point is at infinity + pub fn add_checked(&self, point: Self) -> Option> { + let new_point = self.0.add_point(&point.0); + if new_point.is_zero() { + None + } else { + Some(Point(new_point)) + } + } + + /// Substrates two points, returns the result, or `None` if resulting point is at infinity + pub fn sub_checked(&self, point: Self) -> Option> { + let new_point = self.0.sub_point(&point.0); + if new_point.is_zero() { + None + } else { + Some(Point(new_point)) + } + } + + /// Multiplies a point at scalar, returns the result, or `None` if resulting point is at infinity + pub fn mul_checked_z(&self, scalar: &ScalarZ) -> Option> { + let new_point = self.0.scalar_mul(&scalar.0); + if new_point.is_zero() { + None + } else { + Some(Point(new_point)) + } + } + + /// Multiplies a point at nonzero scalar, returns the result, or `None` if resulting point is at infinity + pub fn mul_checked(&self, scalar: &Scalar) -> Option> { + let new_point = self.0.scalar_mul(&scalar.0); + if new_point.is_zero() { + None + } else { + Some(Point(new_point)) + } + } + + /// Serializes point into (un)compressed form + pub fn to_bytes(&self, compressed: bool) -> Vec { + self.0 + .serialize(compressed) + .expect("non-zero point must always be serializable") + } + + /// Clones the referenced point + pub fn to_point_owned(&self) -> Point { + Point(self.0.clone()) + } +} + +/// Converting PointZ to Point error +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ZeroPointError(()); + +impl fmt::Display for ZeroPointError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "nonzero check failed: point is zero") + } +} + +impl std::error::Error for ZeroPointError {} + +/// Constructing Point from its coordinates error +#[derive(Debug, Error)] +pub enum PointFromCoordsError { + #[error("x,y correspond to zero point")] + ZeroPoint, + #[error("point is not on the curve")] + PointNotOnCurve, +} + +/// Constructing Point from its (un)compressed representation error +#[derive(Debug, Error)] +pub enum PointFromBytesError { + #[error("deserialized point corresponds to zero point")] + ZeroPoint, + #[error("{0}")] + Deserialize(#[source] DeserializationError), +} + +/// Scalar value in a prime field that **might be zero** +/// +/// ## Security +/// +/// Mistakenly used zero scalar might break security of cryptographic algorithm. It's preferred to +/// use `Scalar`[Scalar] that's guaranteed to be non-zero. Use [ensure_nonzero](ScalarZ::ensure_nonzero) +/// to convert `ScalarZ` into `Scalar`. +/// +/// ## Guarantees +/// +/// * Belongs to the curve prime field +/// +/// Denoting curve modulus as `q`, any instance `s` of `ScalarZ` is guaranteed to be non-negative +/// integer modulo `q`: `0 <= s < q` +/// +/// ## Arithmetics +/// +/// Supported operations: +/// * Unary: you can [invert](Self::invert) and negate a scalar by modulo of prime field +/// * Binary: you can add, subtract, and multiply two points +/// +/// ### Example +/// +/// ```rust +/// # use curv::elliptic::curves::{ScalarZ, Secp256k1}; +/// fn expression( +/// a: ScalarZ, +/// b: ScalarZ, +/// c: ScalarZ +/// ) -> ScalarZ { +/// a + b * c +/// } +/// ``` +#[derive(Serialize, Deserialize)] +#[serde(try_from = "ScalarFormat", into = "ScalarFormat")] +pub struct ScalarZ(E::Scalar); + +impl ScalarZ { + pub fn ensure_nonzero(self) -> Option> { + Scalar::from_raw(self.0) + } + + fn from_raw(scalar: E::Scalar) -> Self { + Self(scalar) + } + + pub fn random() -> Self { + Self::from_raw(E::Scalar::random()) + } + + pub fn zero() -> Self { + Self::from_raw(E::Scalar::zero()) + } + + pub fn is_zero(&self) -> bool { + self.0.is_zero() + } + + pub fn to_bigint(&self) -> BigInt { + self.0.to_bigint() + } + + pub fn from_bigint(n: &BigInt) -> Self { + Self::from_raw(E::Scalar::from_bigint(n)) + } + + pub fn invert(&self) -> Option { + self.0.invert().map(Self::from_raw) + } +} + +impl Clone for ScalarZ { + fn clone(&self) -> Self { + Self::from_raw(self.0.clone()) + } +} + +impl fmt::Debug for ScalarZ { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl PartialEq for ScalarZ { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +impl PartialEq> for ScalarZ { + fn eq(&self, other: &Scalar) -> bool { + self.0.eq(&other.0) + } +} + +impl From> for ScalarZ { + fn from(scalar: Scalar) -> Self { + ScalarZ::from_raw(scalar.0) + } +} + +impl From for ScalarZ { + fn from(n: u16) -> Self { + Self::from(&BigInt::from(n)) + } +} + +impl From for ScalarZ { + fn from(n: u32) -> Self { + Self::from(&BigInt::from(n)) + } +} + +impl From for ScalarZ { + fn from(n: u64) -> Self { + Self::from(&BigInt::from(n)) + } +} + +impl From for ScalarZ { + fn from(n: i32) -> Self { + Self::from(&BigInt::from(n)) + } +} + +impl From<&BigInt> for ScalarZ { + fn from(n: &BigInt) -> Self { + ScalarZ::from_raw(E::Scalar::from_bigint(n)) + } +} + +impl From for ScalarZ { + fn from(n: BigInt) -> Self { + Self::from(&n) + } +} + +/// Scalar value in a prime field that _guaranteed_ to be non zero +/// +/// ## Security +/// +/// Non-zero scalars are preferred to be used in cryptographic algorithms. Lack of checking whether +/// computation on field scalars results into zero scalar might lead to vulnerability. Using `Scalar` +/// ensures you and reviewers that check on scalar not being zero was made. +/// +/// ## Guarantees +/// +/// * Belongs to the curve prime field +/// +/// Denoting curve modulus as `q`, any instance `s` of `Scalar` is guaranteed to be less than `q`: +/// `s < q` +/// * Not a zero +/// +/// Any instance `s` of `Scalar` is guaranteed to be more than zero: `s > 0` +/// +/// Combining two rules above, any instance `s` of `Scalar` is guaranteed to be: `0 < s < q`. +/// +/// ## Arithmetic +/// +/// Supported operations: +/// * Unary: you can [invert](Self::invert) and negate a scalar by modulo of prime field +/// * Binary: you can add, subtract, and multiply two points +/// +/// Addition, subtraction, or multiplication of two (even non-zero) scalars might result into zero +/// scalar, so these operations output [ScalarZ]. Use [ensure_nonzero](ScalarZ::ensure_nonzero) method +/// to ensure that computation doesn't produce zero scalar; +/// +/// ```rust +/// # use curv::elliptic::curves::{ScalarZ, Scalar, Secp256k1}; +/// let a = Scalar::::random(); +/// let b = Scalar::::random(); +/// let result: ScalarZ = a * b; +/// let non_zero_result: Option> = result.ensure_nonzero(); +/// ``` +/// +/// When evaluating complex expressions, you typically need to ensure that none of intermediate +/// results are zero scalars: +/// ```rust +/// # use curv::elliptic::curves::{Scalar, Secp256k1}; +/// fn expression(a: Scalar, b: Scalar, c: Scalar) -> Option> { +/// (a + (b * c).ensure_nonzero()?).ensure_nonzero() +/// } +/// ``` +#[derive(Serialize, Deserialize)] +#[serde(try_from = "ScalarFormat", into = "ScalarFormat")] +pub struct Scalar(E::Scalar); + +impl Scalar { + /// Samples a random non-zero scalar + pub fn random() -> Self { + loop { + if let Some(scalar) = ScalarZ::from_raw(E::Scalar::random()).ensure_nonzero() { + break scalar; + } + } + } + + /// Returns modular multiplicative inverse of the scalar + /// + /// Inverse of non-zero scalar is always defined in a prime field, and inverted scalar is also + /// guaranteed to be non-zero. + pub fn invert(&self) -> Self { + self.0 + .invert() + .map(Self) + .expect("non-zero scalar must have corresponding inversion") + } + + /// Adds two scalars, returns the result by modulo `q`, or `None` if resulting scalar is zero + pub fn add_checked(&self, scalar: &Scalar) -> Option { + let scalar = self.0.add(&scalar.0); + Self::from_raw(scalar) + } + + /// Subtracts two scalars, returns the result by modulo `q`, or `None` if resulting scalar is zero + pub fn sub_checked(&self, scalar: &Scalar) -> Option { + let scalar = self.0.sub(&scalar.0); + Self::from_raw(scalar) + } + + /// Multiplies two scalars, returns the result by modulo `q`, or `None` if resulting scalar is zero + pub fn mul_checked(&self, scalar: &Scalar) -> Option { + let scalar = self.0.mul(&scalar.0); + Self::from_raw(scalar) + } + + fn from_raw(scalar: E::Scalar) -> Option { + if scalar.is_zero() { + None + } else { + Some(Self(scalar)) + } + } +} + +impl Clone for Scalar { + fn clone(&self) -> Self { + Scalar(self.0.clone()) + } +} + +impl fmt::Debug for Scalar { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl PartialEq for Scalar { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +impl PartialEq> for Scalar { + fn eq(&self, other: &ScalarZ) -> bool { + self.0.eq(&other.0) + } +} + +macro_rules! matrix { + ( + trait = $trait:ident, + trait_fn = $trait_fn:ident, + output = $output:ty, + output_new = $output_new:ident, + point_fn = $point_fn:ident, + point_assign_fn = $point_assign_fn:ident, + pairs = {(r_<$($l:lifetime),*> $lhs_ref:ty, $rhs:ty), $($rest:tt)*} + ) => { + impl<$($l,)* E: Curve> ops::$trait<$rhs> for $lhs_ref { + type Output = $output; + fn $trait_fn(self, rhs: $rhs) -> Self::Output { + let p = self.0.$point_fn(&rhs.0); + $output_new(p) + } + } + matrix!{ + trait = $trait, + trait_fn = $trait_fn, + output = $output, + output_new = $output_new, + point_fn = $point_fn, + point_assign_fn = $point_assign_fn, + pairs = {$($rest)*} + } + }; + + ( + trait = $trait:ident, + trait_fn = $trait_fn:ident, + output = $output:ty, + output_new = $output_new:ident, + point_fn = $point_fn:ident, + point_assign_fn = $point_assign_fn:ident, + pairs = {(_r<$($l:lifetime),*> $lhs:ty, $rhs_ref:ty), $($rest:tt)*} + ) => { + impl<$($l,)* E: Curve> ops::$trait<$rhs_ref> for $lhs { + type Output = $output; + fn $trait_fn(self, rhs: $rhs_ref) -> Self::Output { + let p = rhs.0.$point_fn(&self.0); + $output_new(p) + } + } + matrix!{ + trait = $trait, + trait_fn = $trait_fn, + output = $output, + output_new = $output_new, + point_fn = $point_fn, + point_assign_fn = $point_assign_fn, + pairs = {$($rest)*} + } + }; + + ( + trait = $trait:ident, + trait_fn = $trait_fn:ident, + output = $output:ty, + output_new = $output_new:ident, + point_fn = $point_fn:ident, + point_assign_fn = $point_assign_fn:ident, + pairs = {(o_<$($l:lifetime),*> $lhs_owned:ty, $rhs:ty), $($rest:tt)*} + ) => { + impl<$($l,)* E: Curve> ops::$trait<$rhs> for $lhs_owned { + type Output = $output; + fn $trait_fn(mut self, rhs: $rhs) -> Self::Output { + self.0.$point_assign_fn(&rhs.0); + $output_new(self.0) + } + } + matrix!{ + trait = $trait, + trait_fn = $trait_fn, + output = $output, + output_new = $output_new, + point_fn = $point_fn, + point_assign_fn = $point_assign_fn, + pairs = {$($rest)*} + } + }; + + ( + trait = $trait:ident, + trait_fn = $trait_fn:ident, + output = $output:ty, + output_new = $output_new:ident, + point_fn = $point_fn:ident, + point_assign_fn = $point_assign_fn:ident, + pairs = {(_o<$($l:lifetime),*> $lhs:ty, $rhs_owned:ty), $($rest:tt)*} + ) => { + impl<$($l,)* E: Curve> ops::$trait<$rhs_owned> for $lhs { + type Output = $output; + fn $trait_fn(self, mut rhs: $rhs_owned) -> Self::Output { + rhs.0.$point_assign_fn(&self.0); + $output_new(rhs.0) + } + } + matrix!{ + trait = $trait, + trait_fn = $trait_fn, + output = $output, + output_new = $output_new, + point_fn = $point_fn, + point_assign_fn = $point_assign_fn, + pairs = {$($rest)*} + } + }; + + ( + trait = $trait:ident, + trait_fn = $trait_fn:ident, + output = $output:ty, + output_new = $output_new:ident, + point_fn = $point_fn:ident, + point_assign_fn = $point_assign_fn:ident, + pairs = {} + ) => { + // happy termination + }; +} + +matrix! { + trait = Add, + trait_fn = add, + output = PointZ, + output_new = PointZ, + point_fn = add_point, + point_assign_fn = add_point_assign, + pairs = { + (o_<> Point, &Point), (o_<> Point, &PointZ), + (r_<> &Point, &Point), (r_<> &Point, &PointZ), + (o_<> PointZ, &Point), (o_<> PointZ, &PointZ), + (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), + (o_<> Point, Point), (o_<> PointZ, PointZ), + (o_<> Point, PointZ), (o_<> PointZ, Point), + (_o<> &Point, Point), (_o<> &Point, PointZ), + (_o<> &PointZ, Point), (_o<> &PointZ, PointZ), + + // The same as above, but replacing &Point with PointRef + (o_<'r> Point, PointRef<'r, E>), + (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'r> PointRef<'r, E>, &PointZ), + (o_<'r> PointZ, PointRef<'r, E>), + (r_<'r> &PointZ, PointRef<'r, E>), + (_o<'r> PointRef<'r, E>, Point), (_o<'r> PointRef<'r, E>, PointZ), + + // And define trait between &Point and PointRef + (r_<'r> &Point, PointRef<'r, E>), (r_<'r> PointRef<'r, E>, &Point), + } +} + +matrix! { + trait = Sub, + trait_fn = sub, + output = PointZ, + output_new = PointZ, + point_fn = sub_point, + point_assign_fn = sub_point_assign, + pairs = { + (o_<> Point, &Point), (o_<> Point, &PointZ), + (r_<> &Point, &Point), (r_<> &Point, &PointZ), + (o_<> PointZ, &Point), (o_<> PointZ, &PointZ), + (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), + (o_<> Point, Point), (o_<> PointZ, PointZ), + (o_<> Point, PointZ), (o_<> PointZ, Point), + (_o<> &Point, Point), (_o<> &Point, PointZ), + (_o<> &PointZ, Point), (_o<> &PointZ, PointZ), + + // The same as above, but replacing &Point with PointRef + (o_<'r> Point, PointRef<'r, E>), + (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'r> PointRef<'r, E>, &PointZ), + (o_<'r> PointZ, PointRef<'r, E>), + (r_<'r> &PointZ, PointRef<'r, E>), + (_o<'r> PointRef<'r, E>, Point), (_o<'r> PointRef<'r, E>, PointZ), + + // And define trait between &Point and PointRef + (r_<'r> &Point, PointRef<'r, E>), (r_<'r> PointRef<'r, E>, &Point), + } +} + +matrix! { + trait = Mul, + trait_fn = mul, + output = PointZ, + output_new = PointZ, + point_fn = scalar_mul, + point_assign_fn = scalar_mul_assign, + pairs = { + (o_<> Point, &Scalar), (o_<> Point, &ScalarZ), + (r_<> &Point, &Scalar), (r_<> &Point, &ScalarZ), + (o_<> PointZ, &Scalar), (o_<> PointZ, &ScalarZ), + (r_<> &PointZ, &Scalar), (r_<> &PointZ, &ScalarZ), + (o_<> Point, Scalar), (o_<> Point, ScalarZ), + (r_<> &Point, Scalar), (r_<> &Point, ScalarZ), + (o_<> PointZ, Scalar), (o_<> PointZ, ScalarZ), + (r_<> &PointZ, Scalar), (r_<> &PointZ, ScalarZ), + + // The same as above but replacing &Point with PointRef + (r_<'p> PointRef<'p, E>, &Scalar), (r_<'p> PointRef<'p, E>, &ScalarZ), + (r_<'p> PointRef<'p, E>, Scalar), (r_<'p> PointRef<'p, E>, ScalarZ), + + // --- And vice-versa --- + + (_o<> &Scalar, Point), (_o<> &ScalarZ, Point), + (_r<> &Scalar, &Point), (_r<> &ScalarZ, &Point), + (_o<> &Scalar, PointZ), (_o<> &ScalarZ, PointZ), + (_r<> &Scalar, &PointZ), (_r<> &ScalarZ, &PointZ), + (_o<> Scalar, Point), (_o<> ScalarZ, Point), + (_r<> Scalar, &Point), (_r<> ScalarZ, &Point), + (_o<> Scalar, PointZ), (_o<> ScalarZ, PointZ), + (_r<> Scalar, &PointZ), (_r<> ScalarZ, &PointZ), + + // The same as above but replacing &Point with PointRef + (_r<'p> &Scalar, PointRef<'p, E>), (_r<'p> &ScalarZ, PointRef<'p, E>), + (_r<'p> Scalar, PointRef<'p, E>), (_r<'p> ScalarZ, PointRef<'p, E>), + } +} + +matrix! { + trait = Add, + trait_fn = add, + output = ScalarZ, + output_new = ScalarZ, + point_fn = add, + point_assign_fn = add_assign, + pairs = { + (o_<> Scalar, Scalar), (o_<> Scalar, ScalarZ), + (o_<> Scalar, &Scalar), (o_<> Scalar, &ScalarZ), + (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), + (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), + (_o<> &Scalar, Scalar), (_o<> &Scalar, ScalarZ), + (r_<> &Scalar, &Scalar), (r_<> &Scalar, &ScalarZ), + (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), + (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), + } +} + +matrix! { + trait = Sub, + trait_fn = sub, + output = ScalarZ, + output_new = ScalarZ, + point_fn = sub, + point_assign_fn = sub_assign, + pairs = { + (o_<> Scalar, Scalar), (o_<> Scalar, ScalarZ), + (o_<> Scalar, &Scalar), (o_<> Scalar, &ScalarZ), + (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), + (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), + (_o<> &Scalar, Scalar), (_o<> &Scalar, ScalarZ), + (r_<> &Scalar, &Scalar), (r_<> &Scalar, &ScalarZ), + (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), + (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), + } +} + +matrix! { + trait = Mul, + trait_fn = mul, + output = ScalarZ, + output_new = ScalarZ, + point_fn = mul, + point_assign_fn = mul_assign, + pairs = { + (o_<> Scalar, Scalar), (o_<> Scalar, ScalarZ), + (o_<> Scalar, &Scalar), (o_<> Scalar, &ScalarZ), + (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), + (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), + (_o<> &Scalar, Scalar), (_o<> &Scalar, ScalarZ), + (r_<> &Scalar, &Scalar), (r_<> &Scalar, &ScalarZ), + (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), + (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), + } +} + +impl ops::Neg for Scalar { + type Output = Scalar; + + fn neg(self) -> Self::Output { + Scalar::from_raw(self.0.neg()).expect("neg must not produce zero point") + } +} + +impl ops::Neg for &Scalar { + type Output = Scalar; + + fn neg(self) -> Self::Output { + Scalar::from_raw(self.0.neg()).expect("neg must not produce zero point") + } +} + +impl ops::Neg for ScalarZ { + type Output = ScalarZ; + + fn neg(self) -> Self::Output { + ScalarZ::from_raw(self.0.neg()) + } +} + +impl ops::Neg for &ScalarZ { + type Output = ScalarZ; + + fn neg(self) -> Self::Output { + ScalarZ::from_raw(self.0.neg()) + } +} + +impl ops::Neg for Point { + type Output = Point; + + fn neg(self) -> Self::Output { + Point::from_raw(self.0.neg_point()).expect("neg must not produce zero point") + } +} + +impl ops::Neg for &Point { + type Output = Point; + + fn neg(self) -> Self::Output { + Point::from_raw(self.0.neg_point()).expect("neg must not produce zero point") + } +} + +impl<'p, E: Curve> ops::Neg for PointRef<'p, E> { + type Output = Point; + + fn neg(self) -> Self::Output { + Point::from_raw(self.0.neg_point()).expect("neg must not produce zero point") + } +} + +impl ops::Neg for PointZ { + type Output = PointZ; + + fn neg(self) -> Self::Output { + PointZ::from_raw(self.0.neg_point()) + } +} + +impl ops::Neg for &PointZ { + type Output = PointZ; + + fn neg(self) -> Self::Output { + PointZ::from_raw(self.0.neg_point()) + } +} + +#[derive(Serialize, Deserialize)] +#[serde(bound = "")] +struct ScalarFormat { + curve_name: Cow<'static, str>, + #[serde(with = "hex")] + scalar: ScalarHex, +} + +impl TryFrom> for ScalarZ { + type Error = ConvertParsedScalarError; + + fn try_from(parsed: ScalarFormat) -> Result { + if parsed.curve_name != E::curve_name() { + return Err(ConvertParsedScalarError::MismatchedCurve { + got: parsed.curve_name, + expected: E::curve_name(), + }); + } + + Ok(ScalarZ::from_raw(parsed.scalar.0)) + } +} + +impl From> for ScalarFormat { + fn from(s: ScalarZ) -> Self { + ScalarFormat { + curve_name: E::curve_name().into(), + scalar: ScalarHex(s.0), + } + } +} + +impl TryFrom> for Scalar { + type Error = ConvertParsedScalarError; + + fn try_from(parsed: ScalarFormat) -> Result { + if parsed.curve_name != E::curve_name() { + return Err(ConvertParsedScalarError::MismatchedCurve { + got: parsed.curve_name, + expected: E::curve_name(), + }); + } + + ScalarZ::from_raw(parsed.scalar.0) + .ensure_nonzero() + .ok_or(ConvertParsedScalarError::ZeroScalar) + } +} + +impl From> for ScalarFormat { + fn from(s: Scalar) -> Self { + ScalarFormat { + curve_name: E::curve_name().into(), + scalar: ScalarHex(s.0), + } + } +} + +#[derive(Debug, Error)] +enum ConvertParsedScalarError { + #[error("scalar must not be zero")] + ZeroScalar, + #[error("expected scalar of curve {expected}, but got scalar of curve {got}")] + MismatchedCurve { + got: Cow<'static, str>, + expected: &'static str, + }, +} + +struct ScalarHex(E::Scalar); + +impl hex::ToHex for &ScalarHex { + fn encode_hex>(&self) -> T { + self.0.to_bigint().to_bytes().encode_hex() + } + + fn encode_hex_upper>(&self) -> T { + self.0.to_bigint().to_bytes().encode_hex_upper() + } +} + +impl hex::FromHex for ScalarHex { + type Error = hex::FromHexError; + + fn from_hex>(hex: T) -> Result { + let bytes = Vec::::from_hex(hex)?; + let big_int = BigInt::from_bytes(&bytes); + Ok(ScalarHex(E::Scalar::from_bigint(&big_int))) + } +} + +#[cfg(test)] +mod test { + use super::*; + + macro_rules! assert_operator_defined_for { + ( + assert_fn = $assert_fn:ident, + lhs = {}, + rhs = {$($rhs:ty),*}, + ) => { + // Corner case + }; + ( + assert_fn = $assert_fn:ident, + lhs = {$lhs:ty $(, $lhs_tail:ty)*}, + rhs = {$($rhs:ty),*}, + ) => { + assert_operator_defined_for! { + assert_fn = $assert_fn, + lhs = $lhs, + rhs = {$($rhs),*}, + } + assert_operator_defined_for! { + assert_fn = $assert_fn, + lhs = {$($lhs_tail),*}, + rhs = {$($rhs),*}, + } + }; + ( + assert_fn = $assert_fn:ident, + lhs = $lhs:ty, + rhs = {$($rhs:ty),*}, + ) => { + $($assert_fn::());* + }; + } + + /// Function asserts that P2 can be added to P1 (ie. P1 + P2) and result is PointZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_point_addition_defined() + where + P1: ops::Add>, + E: Curve, + { + // no-op + } + + #[test] + fn test_point_addition_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_point_addition_defined, + lhs = {Point, PointZ, &Point, &PointZ, PointRef}, + rhs = {Point, PointZ, &Point, &PointZ, PointRef}, + } + } + } + + /// Function asserts that P2 can be subtracted from P1 (ie. P1 - P2) and result is PointZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_point_subtraction_defined() + where + P1: ops::Sub>, + E: Curve, + { + // no-op + } + + #[test] + fn test_point_subtraction_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_point_subtraction_defined, + lhs = {Point, PointZ, &Point, &PointZ, PointRef}, + rhs = {Point, PointZ, &Point, &PointZ, PointRef}, + } + } + } + + /// Function asserts that M can be multiplied by N (ie. M * N) and result is PointZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_point_multiplication_defined() + where + M: ops::Mul>, + E: Curve, + { + // no-op + } + + #[test] + fn test_point_multiplication_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_point_multiplication_defined, + lhs = {Point, PointZ, &Point, &PointZ, PointRef}, + rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + } + assert_operator_defined_for! { + assert_fn = assert_point_multiplication_defined, + lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + rhs = {Point, PointZ, &Point, &PointZ, PointRef}, + } + } + } + + /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is ScalarZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_scalars_addition_defined() + where + S1: ops::Add>, + E: Curve, + { + // no-op + } + + #[test] + fn test_scalars_addition_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_scalars_addition_defined, + lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + } + } + } + + /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is ScalarZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_scalars_subtraction_defined() + where + S1: ops::Sub>, + E: Curve, + { + // no-op + } + + #[test] + fn test_scalars_subtraction_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_scalars_subtraction_defined, + lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + } + } + } + + /// Function asserts that S1 can be multiplied by S2 (ie. S1 * S2) and result is ScalarZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_scalars_multiplication_defined() + where + S1: ops::Mul>, + E: Curve, + { + // no-op + } + + #[test] + fn test_scalars_multiplication_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_scalars_multiplication_defined, + lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + } + } + } +} From b335da5a5fe55a94bbd346e4c905c19b0f4ea565 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 2 Jul 2021 17:41:07 +0300 Subject: [PATCH 13/93] Update polynomial --- src/cryptographic_primitives/mod.rs | 8 +- .../secret_sharing/mod.rs | 2 +- .../secret_sharing/polynomial.rs | 274 ++++++------------ src/lib.rs | 2 +- 4 files changed, 100 insertions(+), 186 deletions(-) diff --git a/src/cryptographic_primitives/mod.rs b/src/cryptographic_primitives/mod.rs index 2a868030..cd3817e1 100644 --- a/src/cryptographic_primitives/mod.rs +++ b/src/cryptographic_primitives/mod.rs @@ -5,8 +5,8 @@ License MIT: */ -pub mod commitments; -pub mod hashing; -pub mod proofs; +// pub mod commitments; +// pub mod hashing; +// pub mod proofs; pub mod secret_sharing; -pub mod twoparty; +// pub mod twoparty; diff --git a/src/cryptographic_primitives/secret_sharing/mod.rs b/src/cryptographic_primitives/secret_sharing/mod.rs index f50534df..6da64435 100644 --- a/src/cryptographic_primitives/secret_sharing/mod.rs +++ b/src/cryptographic_primitives/secret_sharing/mod.rs @@ -5,7 +5,7 @@ License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE */ -pub mod feldman_vss; +// pub mod feldman_vss; mod polynomial; pub use polynomial::Polynomial; diff --git a/src/cryptographic_primitives/secret_sharing/polynomial.rs b/src/cryptographic_primitives/secret_sharing/polynomial.rs index 394b898b..2faf1c07 100644 --- a/src/cryptographic_primitives/secret_sharing/polynomial.rs +++ b/src/cryptographic_primitives/secret_sharing/polynomial.rs @@ -1,10 +1,7 @@ use std::convert::TryFrom; -use std::{fmt, iter, ops}; +use std::{iter, ops}; -use derivative::Derivative; - -use crate::elliptic::curves::traits::{ECPoint, ECScalar}; -use crate::BigInt; +use crate::elliptic::curves::{Curve, Scalar, ScalarZ}; /// Polynomial of some degree `n` /// @@ -12,17 +9,12 @@ use crate::BigInt; /// /// Coefficients `a_i` and indeterminate `x` are scalars in curve prime field, /// ie. their type is `ECScalar` implementor. -#[derive(Derivative)] -#[derivative(Clone(bound = "P::Scalar: Clone"))] -#[derivative(Debug(bound = "P::Scalar: fmt::Debug"))] -pub struct Polynomial { - coefficients: Vec, +#[derive(Clone, Debug)] +pub struct Polynomial { + coefficients: Vec>, } -impl

Polynomial

-where - P: ECPoint, -{ +impl Polynomial { /// Constructs polynomial `f(x)` from list of coefficients `a` /// /// ## Order @@ -39,43 +31,35 @@ where /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// use curv::elliptic::curves::p256::{GE, FE}; + /// use curv::elliptic::curves::{ScalarZ, PointZ, Secp256k1}; /// - /// let coefs = vec![ECScalar::new_random(), ECScalar::new_random()]; - /// let poly = Polynomial::::from_coefficients(coefs.clone()); + /// let coefs = vec![ScalarZ::random(), ScalarZ::random()]; + /// let poly = Polynomial::::from_coefficients(coefs.clone()); /// /// assert_eq!(coefs, poly.coefficients()); /// ``` - pub fn from_coefficients(coefficients: Vec) -> Self { + pub fn from_coefficients(coefficients: Vec>) -> Self { Self { coefficients } } -} -impl

Polynomial

-where - P: ECPoint, - P::Scalar: PartialEq, -{ /// Sample a random polynomial of given degree /// /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// use curv::elliptic::curves::p256::{GE, FE}; + /// use curv::elliptic::curves::Secp256k1; /// - /// let polynomial = Polynomial::::sample_exact(3); + /// let polynomial = Polynomial::::sample_exact(3); /// assert_eq!(polynomial.degree(), 3); /// ``` pub fn sample_exact(degree: u16) -> Self { if degree == 0 { - Self::from_coefficients(vec![ECScalar::new_random()]) + Self::from_coefficients(vec![ScalarZ::random()]) } else { Self::from_coefficients( - iter::repeat_with(ECScalar::new_random) + iter::repeat_with(ScalarZ::random) .take(usize::from(degree)) - .chain(iter::once(new_random_nonzero())) + .chain(iter::once(ScalarZ::from(Scalar::random()))) .collect(), ) } @@ -86,21 +70,20 @@ where /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// use curv::elliptic::curves::p256::{GE, FE}; + /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// - /// let const_term: FE = ECScalar::new_random(); - /// let polynomial = Polynomial::::sample_exact_with_fixed_const_term(3, const_term); + /// let const_term = ScalarZ::::random(); + /// let polynomial = Polynomial::::sample_exact_with_fixed_const_term(3, const_term.clone()); /// assert_eq!(polynomial.degree(), 3); - /// assert_eq!(polynomial.evaluate(&FE::zero()), const_term); + /// assert_eq!(polynomial.evaluate(&ScalarZ::zero()), const_term); /// ``` - pub fn sample_exact_with_fixed_const_term(n: u16, const_term: P::Scalar) -> Self { + pub fn sample_exact_with_fixed_const_term(n: u16, const_term: ScalarZ) -> Self { if n == 0 { Self::from_coefficients(vec![const_term]) } else { - let random_coefficients = iter::repeat_with(ECScalar::new_random) + let random_coefficients = iter::repeat_with(ScalarZ::random) .take(usize::from(n - 1)) - .chain(iter::once(new_random_nonzero::())); + .chain(iter::once(ScalarZ::from(Scalar::random()))); Self::from_coefficients(iter::once(const_term).chain(random_coefficients).collect()) } } @@ -109,52 +92,43 @@ where /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// # use curv::arithmetic::BigInt; - /// use curv::elliptic::curves::secp256_k1::{GE, FE}; + /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// - /// let polynomial = Polynomial::::from_coefficients(vec![ - /// ECScalar::from(&BigInt::from(1)), ECScalar::from(&BigInt::from(2)), + /// let polynomial = Polynomial::::from_coefficients(vec![ + /// ScalarZ::from(1), ScalarZ::from(2), /// ]); /// assert_eq!(polynomial.degree(), 1); /// - /// let polynomial = Polynomial::::from_coefficients(vec![ - /// ECScalar::from(&BigInt::from(1)), ECScalar::zero(), + /// let polynomial = Polynomial::::from_coefficients(vec![ + /// ScalarZ::from(1), ScalarZ::zero(), /// ]); /// assert_eq!(polynomial.degree(), 0); /// ``` pub fn degree(&self) -> u16 { - let zero = P::Scalar::zero(); let i = self .coefficients() .iter() .enumerate() .rev() - .find(|(_, a)| a != &&zero) + .find(|(_, a)| !a.is_zero()) .map(|(i, _)| i) .unwrap_or(0); u16::try_from(i).expect("polynomial degree guaranteed to fit into u16") } -} -impl

Polynomial

-where - P: ECPoint, -{ /// Samples a random polynomial of degree less or equal to given degree /// /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// use curv::elliptic::curves::p256::{GE, FE}; + /// use curv::elliptic::curves::Secp256k1; /// - /// let polynomial = Polynomial::::sample(3); + /// let polynomial = Polynomial::::sample(3); /// assert!(polynomial.degree() <= 3); /// ``` pub fn sample(degree: u16) -> Self { Polynomial::from_coefficients( - iter::repeat_with(ECScalar::new_random) + iter::repeat_with(ScalarZ::random) .take(usize::from(degree + 1)) .collect(), ) @@ -166,53 +140,44 @@ where /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// use curv::elliptic::curves::p256::{GE, FE}; + /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// - /// let const_term = FE::new_random(); - /// let polynomial = Polynomial::::sample_with_fixed_const_term(3, const_term); + /// let const_term = ScalarZ::random(); + /// let polynomial = Polynomial::::sample_with_fixed_const_term(3, const_term.clone()); /// assert!(polynomial.degree() <= 3); - /// assert_eq!(polynomial.evaluate(&FE::zero()), const_term); + /// assert_eq!(polynomial.evaluate(&ScalarZ::zero()), const_term); /// ``` - pub fn sample_with_fixed_const_term(degree: u16, const_term: P::Scalar) -> Self { - let random_coefficients = iter::repeat_with(ECScalar::new_random).take(usize::from(degree)); + pub fn sample_with_fixed_const_term(degree: u16, const_term: ScalarZ) -> Self { + let random_coefficients = iter::repeat_with(ScalarZ::random).take(usize::from(degree)); Polynomial { coefficients: iter::once(const_term).chain(random_coefficients).collect(), } } -} -impl

Polynomial

-where - P: ECPoint, - P::Scalar: Clone, -{ /// Takes scalar `x` and evaluates `f(x)` /// /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// # use curv::arithmetic::BigInt; - /// use curv::elliptic::curves::p256::{GE, FE}; + /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// - /// let polynomial = Polynomial::::sample_exact(2); + /// let polynomial = Polynomial::::sample_exact(2); /// - /// let x: FE = ECScalar::from(&BigInt::from(10)); - /// let y: FE = polynomial.evaluate(&x); + /// let x = ScalarZ::from(10); + /// let y = polynomial.evaluate(&x); /// /// let a = polynomial.coefficients(); - /// assert_eq!(y, a[0] + a[1] * x + a[2] * x*x); + /// assert_eq!(y, &a[0] + &a[1] * &x + &a[2] * &x*&x); /// ``` - pub fn evaluate(&self, point_x: &P::Scalar) -> P::Scalar { + pub fn evaluate(&self, point_x: &ScalarZ) -> ScalarZ { let mut reversed_coefficients = self.coefficients.iter().rev(); let head = reversed_coefficients .next() .expect("at least one coefficient is guaranteed to be present"); let tail = reversed_coefficients; tail.fold(head.clone(), |partial, coef| { - let partial_times_point_x = partial * point_x.clone(); - partial_times_point_x + coef.clone() + let partial_times_point_x = partial * point_x; + partial_times_point_x + coef }) } @@ -221,24 +186,22 @@ where /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// # use curv::arithmetic::BigInt; - /// use curv::elliptic::curves::p256::{GE, FE}; + /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// - /// let polynomial = Polynomial::::sample_exact(2); + /// let polynomial = Polynomial::::sample_exact(2); /// /// let x: u16 = 10; - /// let y: FE = polynomial.evaluate_bigint(x); + /// let y: ScalarZ = polynomial.evaluate_bigint(x); /// /// let a = polynomial.coefficients(); - /// let x: FE = ECScalar::from(&BigInt::from(x)); - /// assert_eq!(y, a[0] + a[1] * x + a[2] * x*x); + /// let x = ScalarZ::from(x); + /// assert_eq!(y, &a[0] + &a[1] * &x + &a[2] * &x*&x); /// ``` - pub fn evaluate_bigint(&self, point_x: B) -> P::Scalar + pub fn evaluate_bigint(&self, point_x: B) -> ScalarZ where - BigInt: From, + ScalarZ: From, { - self.evaluate(&::from(&BigInt::from(point_x))) + self.evaluate(&ScalarZ::from(point_x)) } /// Takes list of points `xs` and returns iterator over `f(xs[i])` @@ -246,23 +209,21 @@ where /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// # use curv::arithmetic::BigInt; - /// use curv::elliptic::curves::p256::{GE, FE}; + /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// - /// let polynomial = Polynomial::::sample_exact(2); + /// let polynomial = Polynomial::::sample_exact(2); /// - /// let xs: &[FE] = &[ECScalar::from(&BigInt::from(10)), ECScalar::from(&BigInt::from(11))]; + /// let xs = &[ScalarZ::from(10), ScalarZ::from(11)]; /// let ys = polynomial.evaluate_many(xs); /// /// let a = polynomial.coefficients(); /// for (y, x) in ys.zip(xs) { - /// assert_eq!(y, a[0] + a[1] * x + a[2] * x*x); + /// assert_eq!(y, &a[0] + &a[1] * x + &a[2] * x*x); /// } /// ``` - pub fn evaluate_many<'i, I>(&'i self, points_x: I) -> impl Iterator + 'i + pub fn evaluate_many<'i, I>(&'i self, points_x: I) -> impl Iterator> + 'i where - I: IntoIterator + 'i, + I: IntoIterator> + 'i, { points_x.into_iter().map(move |x| self.evaluate(x)) } @@ -273,37 +234,30 @@ where /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// # use curv::arithmetic::BigInt; - /// use curv::elliptic::curves::p256::{GE, FE}; + /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// - /// let polynomial = Polynomial::::sample_exact(2); + /// let polynomial = Polynomial::::sample_exact(2); /// /// let xs: &[u16] = &[10, 11]; /// let ys = polynomial.evaluate_many_bigint(xs.iter().copied()); /// /// let a = polynomial.coefficients(); /// for (y, x) in ys.zip(xs) { - /// let x: FE = ECScalar::from(&BigInt::from(*x)); - /// assert_eq!(y, a[0] + a[1] * x + a[2] * x*x); + /// let x = ScalarZ::from(*x); + /// assert_eq!(y, &a[0] + &a[1] * &x + &a[2] * &x*&x); /// } /// ``` pub fn evaluate_many_bigint<'i, B, I>( &'i self, points_x: I, - ) -> impl Iterator + 'i + ) -> impl Iterator> + 'i where I: IntoIterator + 'i, - BigInt: From, + ScalarZ: From, { points_x.into_iter().map(move |x| self.evaluate_bigint(x)) } -} -impl

Polynomial

-where - P: ECPoint, -{ /// Returns list of polynomial coefficients `a`: `a[i]` corresponds to coefficient `a_i` of /// polynomial `f(x) = ... + a_i * x^i + ...` /// @@ -311,15 +265,14 @@ where /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// # use curv::elliptic::curves::traits::ECScalar; - /// use curv::elliptic::curves::secp256_k1::{GE, FE}; + /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// - /// let polynomial = Polynomial::::sample_exact(3); + /// let polynomial = Polynomial::::sample_exact(3); /// let a = polynomial.coefficients(); - /// let x: FE = ECScalar::new_random(); - /// assert_eq!(polynomial.evaluate(&x), a[0] + a[1] * x + a[2] * x*x + a[3] * x*x*x); + /// let x = ScalarZ::::random(); + /// assert_eq!(polynomial.evaluate(&x), &a[0] + &a[1] * &x + &a[2] * &x*&x + &a[3] * &x*&x*&x); /// ``` - pub fn coefficients(&self) -> &[P::Scalar] { + pub fn coefficients(&self) -> &[ScalarZ] { &self.coefficients } } @@ -330,30 +283,21 @@ where /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; -/// # use curv::elliptic::curves::traits::ECScalar; -/// use curv::elliptic::curves::secp256_k1::{GE, FE}; +/// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// -/// let f = Polynomial::::sample_exact(3); +/// let f = Polynomial::::sample_exact(3); /// -/// let s: FE = ECScalar::new_random(); +/// let s = ScalarZ::::random(); /// let g = &f * &s; /// /// for (f_coef, g_coef) in f.coefficients().iter().zip(g.coefficients()) { -/// assert_eq!(*f_coef * s, *g_coef); +/// assert_eq!(&(f_coef * &s), g_coef); /// } /// ``` -impl

ops::Mul<&P::Scalar> for &Polynomial

-where - P: ECPoint, - P::Scalar: Clone, -{ - type Output = Polynomial

; - fn mul(self, scalar: &P::Scalar) -> Self::Output { - let coefficients = self - .coefficients - .iter() - .map(|c| c.clone() * scalar.clone()) - .collect(); +impl ops::Mul<&ScalarZ> for &Polynomial { + type Output = Polynomial; + fn mul(self, scalar: &ScalarZ) -> Self::Output { + let coefficients = self.coefficients.iter().map(|c| c * scalar).collect(); Polynomial::from_coefficients(coefficients) } } @@ -364,23 +308,17 @@ where /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; -/// # use curv::elliptic::curves::traits::ECScalar; -/// # use curv::arithmetic::BigInt; -/// use curv::elliptic::curves::secp256_k1::{GE, FE}; +/// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// -/// let f = Polynomial::::sample_exact(2); -/// let g = Polynomial::::sample_exact(3); +/// let f = Polynomial::::sample_exact(2); +/// let g = Polynomial::::sample_exact(3); /// let h = &f + &g; /// -/// let x: FE = ECScalar::from(&BigInt::from(10)); +/// let x = ScalarZ::::from(10); /// assert_eq!(h.evaluate(&x), f.evaluate(&x) + g.evaluate(&x)); /// ``` -impl

ops::Add for &Polynomial

-where - P: ECPoint, - P::Scalar: Clone, -{ - type Output = Polynomial

; +impl ops::Add for &Polynomial { + type Output = Polynomial; fn add(self, g: Self) -> Self::Output { let len1 = self.coefficients.len(); let len2 = g.coefficients.len(); @@ -389,7 +327,7 @@ where .coefficients() .iter() .zip(g.coefficients()) - .map(|(f_coef, g_coef)| f_coef.clone() + g_coef.clone()); + .map(|(f_coef, g_coef)| f_coef + g_coef); let tail = if len1 < len2 { &g.coefficients()[len1..] } else { @@ -406,23 +344,17 @@ where /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; -/// # use curv::elliptic::curves::traits::ECScalar; -/// # use curv::arithmetic::BigInt; -/// use curv::elliptic::curves::secp256_k1::{GE, FE}; +/// use curv::elliptic::curves::{Secp256k1, ScalarZ}; /// -/// let f = Polynomial::::sample_exact(2); -/// let g = Polynomial::::sample_exact(3); +/// let f = Polynomial::::sample_exact(2); +/// let g = Polynomial::::sample_exact(3); /// let h = &f - &g; /// -/// let x: FE = ECScalar::from(&BigInt::from(10)); -/// assert_eq!(h.evaluate(&x), f.evaluate(&x).sub(&g.evaluate(&x).get_element())); +/// let x = ScalarZ::::from(10); +/// assert_eq!(h.evaluate(&x), f.evaluate(&x) - &g.evaluate(&x)); /// ``` -impl

ops::Sub for &Polynomial

-where - P: ECPoint, - P::Scalar: Clone, -{ - type Output = Polynomial

; +impl ops::Sub for &Polynomial { + type Output = Polynomial; fn sub(self, g: Self) -> Self::Output { let len1 = self.coefficients.len(); let len2 = g.coefficients.len(); @@ -431,16 +363,9 @@ where .coefficients() .iter() .zip(g.coefficients()) - .map(|(f_coef, g_coef)| f_coef.sub(&g_coef.get_element())); + .map(|(f_coef, g_coef)| f_coef - g_coef); let tail = if len1 < len2 { - // Instead of evaluating (0 - s), we use a trick and evaluate ((1 - s) - 1). - // The reason why we do this - some of scalars cannot be constructed to be zero ( - // panic will be raised) - let one: P::Scalar = ECScalar::from(&BigInt::from(1)); - g.coefficients()[len1..] - .iter() - .map(|x| one.sub(&x.get_element()).sub(&one.get_element())) - .collect() + g.coefficients()[len1..].iter().map(|x| -x).collect() } else { self.coefficients()[len2..].to_vec() }; @@ -448,14 +373,3 @@ where Polynomial::from_coefficients(overlapped.chain(tail.into_iter()).collect()) } } - -/// Samples a scalar guaranteed to be not zero -fn new_random_nonzero() -> S { - let zero = S::zero(); - loop { - let s = S::new_random(); - if s != zero { - break s; - } - } -} diff --git a/src/lib.rs b/src/lib.rs index f5a31935..5356d21d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ pub mod elliptic; pub mod arithmetic; pub use crate::arithmetic::BigInt; -// pub mod cryptographic_primitives; +pub mod cryptographic_primitives; #[derive(Copy, PartialEq, Eq, Clone, Debug)] pub enum ErrorKey { From ef8d6f91e8860a6c7cd6c2bc53e9d5274f28873e Mon Sep 17 00:00:00 2001 From: Denis Date: Sat, 3 Jul 2021 15:35:51 +0300 Subject: [PATCH 14/93] Do not access wrappers internal state directly, improve docs --- src/elliptic/curves/wrappers.rs | 406 +++++++++++++++++++++----------- 1 file changed, 263 insertions(+), 143 deletions(-) diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index 5411a941..3d4c2b37 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -46,29 +46,65 @@ impl PointZ { Point::try_from(self).ok() } + /// Constructs zero point + /// + /// Zero point is usually denoted as O. It's curve neutral element, i.e. `forall A. A + O = A`. + /// + /// Weierstrass and Montgomery curves employ special "point at infinity" that represent a neutral + /// element, such points don't have coordinates (i.e. [from_coords], [x_coord], [y_coord] return + /// `None`). Edwards curves' neutral element has coordinates. + /// + /// [from_coords]: Self::from_coords + /// [x_coord]: Self::x_coord + /// [y_coord]: Self::y_coord pub fn zero() -> Self { Self::from_raw(E::Point::zero()) } + /// Checks whether point is zero pub fn iz_zero(&self) -> bool { - self.0.is_zero() + self.as_raw().is_zero() } + /// Returns point coordinates + /// + /// Point might not have coordinates (specifically, "point at infinity" doesn't), in this case + /// `None` is returned pub fn coords(&self) -> Option { - self.0.coords() + self.as_raw().coords() } + /// Returns point x coordinate + /// + /// See [coords](Self::coords) method that retrieves both x and y at once. pub fn x_coord(&self) -> Option { - self.0.x_coord() + self.as_raw().x_coord() } + /// Returns point y coordinate + /// + /// See [coords](Self::coords) method that retrieves both x and y at once. pub fn y_coord(&self) -> Option { - self.0.y_coord() + self.as_raw().y_coord() + } + + /// Constructs a point from its coordinates, returns error if coordinates don't satisfy + /// curve equation + pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { + E::Point::from_coords(x, y).map(Self::from_raw) } fn from_raw(point: E::Point) -> Self { Self(point) } + + fn as_raw(&self) -> &E::Point { + &self.0 + } + + fn into_raw(self) -> E::Point { + self.0 + } } impl PartialEq for PointZ { @@ -139,17 +175,11 @@ impl fmt::Debug for PointZ { /// (a + (b * c).ensure_nonzero()?).ensure_nonzero() /// } /// ``` -pub struct Point(E::Point); +pub struct Point { + raw_point: E::Point, +} impl Point { - fn from_raw(point: E::Point) -> Result { - if point.is_zero() { - Err(ZeroPointError(())) - } else { - Ok(Self(point)) - } - } - /// Curve generator /// /// Returns a static reference on actual value because in most cases referenced value is fine. @@ -208,22 +238,22 @@ impl Point { } /// Adds two points, returns the result, or `None` if resulting point is zero - pub fn add_checked(&self, point: PointRef) -> Option { + pub fn add_checked(&self, point: PointRef) -> Result { self.as_point_ref().add_checked(point) } /// Substrates two points, returns the result, or `None` if resulting point is zero - pub fn sub_checked(&self, point: PointRef) -> Option { + pub fn sub_checked(&self, point: PointRef) -> Result { self.as_point_ref().sub_checked(point) } /// Multiplies a point at scalar, returns the result, or `None` if resulting point is zero - pub fn mul_checked_z(&self, scalar: &ScalarZ) -> Option { + pub fn mul_checked_z(&self, scalar: &ScalarZ) -> Result { self.as_point_ref().mul_checked_z(scalar) } /// Multiplies a point at nonzero scalar, returns the result, or `None` if resulting point is zero - pub fn mul_checked(&self, scalar: &Scalar) -> Option { + pub fn mul_checked(&self, scalar: &Scalar) -> Result { self.as_point_ref().mul_checked(scalar) } @@ -234,26 +264,47 @@ impl Point { /// Creates [PointRef] that holds a reference on `self` pub fn as_point_ref(&self) -> PointRef { - PointRef(&self.0) + PointRef::from(self) + } + + fn from_raw(raw_point: E::Point) -> Result { + if raw_point.is_zero() { + Err(ZeroPointError(())) + } else { + Ok(Self { raw_point }) + } + } + + unsafe fn from_raw_unchecked(point: E::Point) -> Self { + Point { raw_point: point } + } + + fn as_raw(&self) -> &E::Point { + &self.raw_point + } + + fn into_raw(self) -> E::Point { + self.raw_point } } impl Clone for Point { fn clone(&self) -> Self { - Point(self.0.clone()) + // Safety: `self` is guaranteed to be non-zero + unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } } } impl fmt::Debug for Point { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) + self.as_raw().fmt(f) } } impl TryFrom> for Point { type Error = ZeroPointError; fn try_from(point: PointZ) -> Result { - Self::from_raw(point.0) + Self::from_raw(point.into_raw()) } } @@ -261,20 +312,8 @@ impl TryFrom> for Point { /// /// Holds internally a reference on [`Point`](Point), refer to its documentation to learn /// more about Point/PointRef guarantees, security notes, and arithmetics. -pub struct PointRef<'p, E: Curve>(&'p E::Point); - -impl<'p, E: Curve> Clone for PointRef<'p, E> { - fn clone(&self) -> Self { - Self(self.0) - } -} - -impl<'p, E: Curve> Copy for PointRef<'p, E> {} - -impl<'p, E: Curve> fmt::Debug for PointRef<'p, E> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } +pub struct PointRef<'p, E: Curve> { + raw_point: &'p E::Point, } impl PointRef<'static, E> { @@ -291,19 +330,11 @@ impl<'p, E> PointRef<'p, E> where E: Curve, { - fn from_raw(point: &'p E::Point) -> Option { - if point.is_zero() { - None - } else { - Some(Self(point)) - } - } - /// Returns point coordinates (`x` and `y`) /// /// Method never fails as Point is guaranteed to have coordinates pub fn coords(&self) -> PointCoords { - self.0 + self.as_raw() .coords() .expect("Point guaranteed to have coordinates") } @@ -312,7 +343,7 @@ where /// /// Method never fails as Point is guaranteed to have coordinates pub fn x_coord(&self) -> BigInt { - self.0 + self.as_raw() .x_coord() .expect("Point guaranteed to have coordinates") } @@ -321,65 +352,88 @@ where /// /// Method never fails as Point is guaranteed to have coordinates pub fn y_coord(&self) -> BigInt { - self.0 + self.as_raw() .y_coord() .expect("Point guaranteed to have coordinates") } /// Adds two points, returns the result, or `None` if resulting point is at infinity - pub fn add_checked(&self, point: Self) -> Option> { - let new_point = self.0.add_point(&point.0); - if new_point.is_zero() { - None - } else { - Some(Point(new_point)) - } + pub fn add_checked(&self, point: Self) -> Result, ZeroPointError> { + let new_point = self.as_raw().add_point(point.as_raw()); + Point::from_raw(new_point) } /// Substrates two points, returns the result, or `None` if resulting point is at infinity - pub fn sub_checked(&self, point: Self) -> Option> { - let new_point = self.0.sub_point(&point.0); - if new_point.is_zero() { - None - } else { - Some(Point(new_point)) - } + pub fn sub_checked(&self, point: Self) -> Result, ZeroPointError> { + let new_point = self.as_raw().sub_point(point.as_raw()); + Point::from_raw(new_point) } /// Multiplies a point at scalar, returns the result, or `None` if resulting point is at infinity - pub fn mul_checked_z(&self, scalar: &ScalarZ) -> Option> { - let new_point = self.0.scalar_mul(&scalar.0); - if new_point.is_zero() { - None - } else { - Some(Point(new_point)) - } + pub fn mul_checked_z(&self, scalar: &ScalarZ) -> Result, ZeroPointError> { + let new_point = self.as_raw().scalar_mul(scalar.as_raw()); + Point::from_raw(new_point) } /// Multiplies a point at nonzero scalar, returns the result, or `None` if resulting point is at infinity - pub fn mul_checked(&self, scalar: &Scalar) -> Option> { - let new_point = self.0.scalar_mul(&scalar.0); - if new_point.is_zero() { - None - } else { - Some(Point(new_point)) - } + pub fn mul_checked(&self, scalar: &Scalar) -> Result, ZeroPointError> { + let new_point = self.as_raw().scalar_mul(scalar.as_raw()); + Point::from_raw(new_point) } /// Serializes point into (un)compressed form pub fn to_bytes(&self, compressed: bool) -> Vec { - self.0 + self.as_raw() .serialize(compressed) .expect("non-zero point must always be serializable") } /// Clones the referenced point pub fn to_point_owned(&self) -> Point { - Point(self.0.clone()) + // Safety: `self` is guaranteed to be non-zero + unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } + } + + fn from_raw(raw_point: &'p E::Point) -> Option { + if raw_point.is_zero() { + None + } else { + Some(Self { raw_point }) + } + } + + unsafe fn from_raw_unchecked(raw_point: &'p E::Point) -> Self { + PointRef { raw_point } + } + + fn as_raw(self) -> &'p E::Point { + self.raw_point } } -/// Converting PointZ to Point error +impl<'p, E: Curve> Clone for PointRef<'p, E> { + fn clone(&self) -> Self { + // Safety: `self` is guaranteed to be non-zero + unsafe { Self::from_raw_unchecked(self.as_raw()) } + } +} + +impl<'p, E: Curve> Copy for PointRef<'p, E> {} + +impl<'p, E: Curve> fmt::Debug for PointRef<'p, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.as_raw().fmt(f) + } +} + +impl<'p, E: Curve> From<&'p Point> for PointRef<'p, E> { + fn from(point: &'p Point) -> Self { + // Safety: `point` is guaranteed to be non-zero + unsafe { PointRef::from_raw_unchecked(point.as_raw()) } + } +} + +/// Indicates that conversion or computation failed due to occurred zero point #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct ZeroPointError(()); @@ -391,6 +445,18 @@ impl fmt::Display for ZeroPointError { impl std::error::Error for ZeroPointError {} +/// Indicates that conversion or computation failed due to occurred zero scalar +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ZeroScalarError(()); + +impl fmt::Display for ZeroScalarError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "nonzero check failed: scalar is zero") + } +} + +impl std::error::Error for ZeroScalarError {} + /// Constructing Point from its coordinates error #[derive(Debug, Error)] pub enum PointFromCoordsError { @@ -421,8 +487,8 @@ pub enum PointFromBytesError { /// /// * Belongs to the curve prime field /// -/// Denoting curve modulus as `q`, any instance `s` of `ScalarZ` is guaranteed to be non-negative -/// integer modulo `q`: `0 <= s < q` +/// Denoting [curve order](Self::curve_order) as `n`, any instance `s` of `ScalarZ` is guaranteed +/// to be non-negative integer modulo `n`: `0 <= s < n` /// /// ## Arithmetics /// @@ -444,69 +510,91 @@ pub enum PointFromBytesError { /// ``` #[derive(Serialize, Deserialize)] #[serde(try_from = "ScalarFormat", into = "ScalarFormat")] -pub struct ScalarZ(E::Scalar); +pub struct ScalarZ { + raw_scalar: E::Scalar, +} impl ScalarZ { + /// Converts a scalar into [`Scalar`](ScalarZ) if it's non-zero, returns None otherwise pub fn ensure_nonzero(self) -> Option> { - Scalar::from_raw(self.0) - } - - fn from_raw(scalar: E::Scalar) -> Self { - Self(scalar) + Scalar::from_raw(self.into_raw()).ok() } + /// Samples a random scalar pub fn random() -> Self { Self::from_raw(E::Scalar::random()) } + /// Constructs zero scalar pub fn zero() -> Self { Self::from_raw(E::Scalar::zero()) } + /// Checks if a scalar is zero pub fn is_zero(&self) -> bool { - self.0.is_zero() + self.as_raw().is_zero() } + /// Converts a scalar to [BigInt] pub fn to_bigint(&self) -> BigInt { - self.0.to_bigint() + self.as_raw().to_bigint() } + /// Constructs a scalar `n % curve_order` from give `n` pub fn from_bigint(n: &BigInt) -> Self { Self::from_raw(E::Scalar::from_bigint(n)) } + /// Returns a curve order + pub fn curve_order() -> &'static BigInt { + E::Scalar::curve_order() + } + + /// Returns inversion `self^-1 mod curve_order`, or None if `self` is zero pub fn invert(&self) -> Option { - self.0.invert().map(Self::from_raw) + self.as_raw().invert().map(Self::from_raw) + } + + fn from_raw(raw_scalar: E::Scalar) -> Self { + Self { raw_scalar } + } + + fn as_raw(&self) -> &E::Scalar { + &self.raw_scalar + } + + fn into_raw(self) -> E::Scalar { + self.raw_scalar } } impl Clone for ScalarZ { fn clone(&self) -> Self { - Self::from_raw(self.0.clone()) + Self::from_raw(self.as_raw().clone()) } } impl fmt::Debug for ScalarZ { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) + self.as_raw().fmt(f) } } impl PartialEq for ScalarZ { fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) + self.as_raw().eq(other.as_raw()) } } impl PartialEq> for ScalarZ { fn eq(&self, other: &Scalar) -> bool { - self.0.eq(&other.0) + self.as_raw().eq(other.as_raw()) } } impl From> for ScalarZ { fn from(scalar: Scalar) -> Self { - ScalarZ::from_raw(scalar.0) + ScalarZ::from_raw(scalar.into_raw()) } } @@ -558,13 +646,13 @@ impl From for ScalarZ { /// /// * Belongs to the curve prime field /// -/// Denoting curve modulus as `q`, any instance `s` of `Scalar` is guaranteed to be less than `q`: -/// `s < q` +/// Denoting curve order as `n`, any instance `s` of `Scalar` is guaranteed to be less than `q`: +/// `s < n` /// * Not a zero /// /// Any instance `s` of `Scalar` is guaranteed to be more than zero: `s > 0` /// -/// Combining two rules above, any instance `s` of `Scalar` is guaranteed to be: `0 < s < q`. +/// Combining two rules above, any instance `s` of `Scalar` is guaranteed to be: `0 < s < n`. /// /// ## Arithmetic /// @@ -594,7 +682,9 @@ impl From for ScalarZ { /// ``` #[derive(Serialize, Deserialize)] #[serde(try_from = "ScalarFormat", into = "ScalarFormat")] -pub struct Scalar(E::Scalar); +pub struct Scalar { + raw_scalar: E::Scalar, +} impl Scalar { /// Samples a random non-zero scalar @@ -611,60 +701,88 @@ impl Scalar { /// Inverse of non-zero scalar is always defined in a prime field, and inverted scalar is also /// guaranteed to be non-zero. pub fn invert(&self) -> Self { - self.0 + self.as_raw() .invert() - .map(Self) + .map(|s| Scalar::from_raw(s).expect("inversion must be non-zero")) .expect("non-zero scalar must have corresponding inversion") } + /// Returns a curve order + pub fn curve_order() -> &'static BigInt { + E::Scalar::curve_order() + } + + /// Converts a scalar to [BigInt] + pub fn to_bigint(&self) -> BigInt { + self.as_raw().to_bigint() + } + + /// Constructs a scalar from [BigInt] or returns error if it's zero + pub fn from_bigint(n: &BigInt) -> Result { + Self::from_raw(E::Scalar::from_bigint(n)) + } + /// Adds two scalars, returns the result by modulo `q`, or `None` if resulting scalar is zero - pub fn add_checked(&self, scalar: &Scalar) -> Option { - let scalar = self.0.add(&scalar.0); + pub fn add_checked(&self, scalar: &Scalar) -> Result { + let scalar = self.as_raw().add(scalar.as_raw()); Self::from_raw(scalar) } /// Subtracts two scalars, returns the result by modulo `q`, or `None` if resulting scalar is zero - pub fn sub_checked(&self, scalar: &Scalar) -> Option { - let scalar = self.0.sub(&scalar.0); + pub fn sub_checked(&self, scalar: &Scalar) -> Result { + let scalar = self.as_raw().sub(scalar.as_raw()); Self::from_raw(scalar) } /// Multiplies two scalars, returns the result by modulo `q`, or `None` if resulting scalar is zero - pub fn mul_checked(&self, scalar: &Scalar) -> Option { - let scalar = self.0.mul(&scalar.0); + pub fn mul_checked(&self, scalar: &Scalar) -> Result { + let scalar = self.as_raw().mul(scalar.as_raw()); Self::from_raw(scalar) } - fn from_raw(scalar: E::Scalar) -> Option { - if scalar.is_zero() { - None + fn from_raw(raw_scalar: E::Scalar) -> Result { + if raw_scalar.is_zero() { + Err(ZeroScalarError(())) } else { - Some(Self(scalar)) + Ok(Self { raw_scalar }) } } + + unsafe fn from_raw_unchecked(raw_scalar: E::Scalar) -> Self { + Self { raw_scalar } + } + + fn as_raw(&self) -> &E::Scalar { + &self.raw_scalar + } + + fn into_raw(self) -> E::Scalar { + self.raw_scalar + } } impl Clone for Scalar { fn clone(&self) -> Self { - Scalar(self.0.clone()) + // Safety: `self` is guaranteed to be non-zero + unsafe { Scalar::from_raw_unchecked(self.as_raw().clone()) } } } impl fmt::Debug for Scalar { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) + self.as_raw().fmt(f) } } impl PartialEq for Scalar { fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) + self.as_raw().eq(other.as_raw()) } } impl PartialEq> for Scalar { fn eq(&self, other: &ScalarZ) -> bool { - self.0.eq(&other.0) + self.as_raw().eq(other.as_raw()) } } @@ -673,7 +791,7 @@ macro_rules! matrix { trait = $trait:ident, trait_fn = $trait_fn:ident, output = $output:ty, - output_new = $output_new:ident, + output_new = $output_new:expr, point_fn = $point_fn:ident, point_assign_fn = $point_assign_fn:ident, pairs = {(r_<$($l:lifetime),*> $lhs_ref:ty, $rhs:ty), $($rest:tt)*} @@ -681,7 +799,7 @@ macro_rules! matrix { impl<$($l,)* E: Curve> ops::$trait<$rhs> for $lhs_ref { type Output = $output; fn $trait_fn(self, rhs: $rhs) -> Self::Output { - let p = self.0.$point_fn(&rhs.0); + let p = self.as_raw().$point_fn(rhs.as_raw()); $output_new(p) } } @@ -700,7 +818,7 @@ macro_rules! matrix { trait = $trait:ident, trait_fn = $trait_fn:ident, output = $output:ty, - output_new = $output_new:ident, + output_new = $output_new:expr, point_fn = $point_fn:ident, point_assign_fn = $point_assign_fn:ident, pairs = {(_r<$($l:lifetime),*> $lhs:ty, $rhs_ref:ty), $($rest:tt)*} @@ -708,7 +826,7 @@ macro_rules! matrix { impl<$($l,)* E: Curve> ops::$trait<$rhs_ref> for $lhs { type Output = $output; fn $trait_fn(self, rhs: $rhs_ref) -> Self::Output { - let p = rhs.0.$point_fn(&self.0); + let p = rhs.as_raw().$point_fn(self.as_raw()); $output_new(p) } } @@ -727,16 +845,17 @@ macro_rules! matrix { trait = $trait:ident, trait_fn = $trait_fn:ident, output = $output:ty, - output_new = $output_new:ident, + output_new = $output_new:expr, point_fn = $point_fn:ident, point_assign_fn = $point_assign_fn:ident, pairs = {(o_<$($l:lifetime),*> $lhs_owned:ty, $rhs:ty), $($rest:tt)*} ) => { impl<$($l,)* E: Curve> ops::$trait<$rhs> for $lhs_owned { type Output = $output; - fn $trait_fn(mut self, rhs: $rhs) -> Self::Output { - self.0.$point_assign_fn(&rhs.0); - $output_new(self.0) + fn $trait_fn(self, rhs: $rhs) -> Self::Output { + let mut raw = self.into_raw(); + raw.$point_assign_fn(rhs.as_raw()); + $output_new(raw) } } matrix!{ @@ -754,16 +873,17 @@ macro_rules! matrix { trait = $trait:ident, trait_fn = $trait_fn:ident, output = $output:ty, - output_new = $output_new:ident, + output_new = $output_new:expr, point_fn = $point_fn:ident, point_assign_fn = $point_assign_fn:ident, pairs = {(_o<$($l:lifetime),*> $lhs:ty, $rhs_owned:ty), $($rest:tt)*} ) => { impl<$($l,)* E: Curve> ops::$trait<$rhs_owned> for $lhs { type Output = $output; - fn $trait_fn(self, mut rhs: $rhs_owned) -> Self::Output { - rhs.0.$point_assign_fn(&self.0); - $output_new(rhs.0) + fn $trait_fn(self, rhs: $rhs_owned) -> Self::Output { + let mut raw = rhs.into_raw(); + raw.$point_assign_fn(self.as_raw()); + $output_new(raw) } } matrix!{ @@ -781,7 +901,7 @@ macro_rules! matrix { trait = $trait:ident, trait_fn = $trait_fn:ident, output = $output:ty, - output_new = $output_new:ident, + output_new = $output_new:expr, point_fn = $point_fn:ident, point_assign_fn = $point_assign_fn:ident, pairs = {} @@ -794,7 +914,7 @@ matrix! { trait = Add, trait_fn = add, output = PointZ, - output_new = PointZ, + output_new = PointZ::from_raw, point_fn = add_point, point_assign_fn = add_point_assign, pairs = { @@ -823,7 +943,7 @@ matrix! { trait = Sub, trait_fn = sub, output = PointZ, - output_new = PointZ, + output_new = PointZ::from_raw, point_fn = sub_point, point_assign_fn = sub_point_assign, pairs = { @@ -852,7 +972,7 @@ matrix! { trait = Mul, trait_fn = mul, output = PointZ, - output_new = PointZ, + output_new = PointZ::from_raw, point_fn = scalar_mul, point_assign_fn = scalar_mul_assign, pairs = { @@ -890,7 +1010,7 @@ matrix! { trait = Add, trait_fn = add, output = ScalarZ, - output_new = ScalarZ, + output_new = ScalarZ::from_raw, point_fn = add, point_assign_fn = add_assign, pairs = { @@ -909,7 +1029,7 @@ matrix! { trait = Sub, trait_fn = sub, output = ScalarZ, - output_new = ScalarZ, + output_new = ScalarZ::from_raw, point_fn = sub, point_assign_fn = sub_assign, pairs = { @@ -928,7 +1048,7 @@ matrix! { trait = Mul, trait_fn = mul, output = ScalarZ, - output_new = ScalarZ, + output_new = ScalarZ::from_raw, point_fn = mul, point_assign_fn = mul_assign, pairs = { @@ -947,7 +1067,7 @@ impl ops::Neg for Scalar { type Output = Scalar; fn neg(self) -> Self::Output { - Scalar::from_raw(self.0.neg()).expect("neg must not produce zero point") + Scalar::from_raw(self.as_raw().neg()).expect("neg must not produce zero point") } } @@ -955,7 +1075,7 @@ impl ops::Neg for &Scalar { type Output = Scalar; fn neg(self) -> Self::Output { - Scalar::from_raw(self.0.neg()).expect("neg must not produce zero point") + Scalar::from_raw(self.as_raw().neg()).expect("neg must not produce zero point") } } @@ -963,7 +1083,7 @@ impl ops::Neg for ScalarZ { type Output = ScalarZ; fn neg(self) -> Self::Output { - ScalarZ::from_raw(self.0.neg()) + ScalarZ::from_raw(self.as_raw().neg()) } } @@ -971,7 +1091,7 @@ impl ops::Neg for &ScalarZ { type Output = ScalarZ; fn neg(self) -> Self::Output { - ScalarZ::from_raw(self.0.neg()) + ScalarZ::from_raw(self.as_raw().neg()) } } @@ -979,7 +1099,7 @@ impl ops::Neg for Point { type Output = Point; fn neg(self) -> Self::Output { - Point::from_raw(self.0.neg_point()).expect("neg must not produce zero point") + Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") } } @@ -987,7 +1107,7 @@ impl ops::Neg for &Point { type Output = Point; fn neg(self) -> Self::Output { - Point::from_raw(self.0.neg_point()).expect("neg must not produce zero point") + Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") } } @@ -995,7 +1115,7 @@ impl<'p, E: Curve> ops::Neg for PointRef<'p, E> { type Output = Point; fn neg(self) -> Self::Output { - Point::from_raw(self.0.neg_point()).expect("neg must not produce zero point") + Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") } } @@ -1003,7 +1123,7 @@ impl ops::Neg for PointZ { type Output = PointZ; fn neg(self) -> Self::Output { - PointZ::from_raw(self.0.neg_point()) + PointZ::from_raw(self.as_raw().neg_point()) } } @@ -1011,7 +1131,7 @@ impl ops::Neg for &PointZ { type Output = PointZ; fn neg(self) -> Self::Output { - PointZ::from_raw(self.0.neg_point()) + PointZ::from_raw(self.as_raw().neg_point()) } } @@ -1042,7 +1162,7 @@ impl From> for ScalarFormat { fn from(s: ScalarZ) -> Self { ScalarFormat { curve_name: E::curve_name().into(), - scalar: ScalarHex(s.0), + scalar: ScalarHex(s.into_raw()), } } } @@ -1068,7 +1188,7 @@ impl From> for ScalarFormat { fn from(s: Scalar) -> Self { ScalarFormat { curve_name: E::curve_name().into(), - scalar: ScalarHex(s.0), + scalar: ScalarHex(s.into_raw()), } } } From 24e35c778d9cb44400eba83d0a009b4033a5f816 Mon Sep 17 00:00:00 2001 From: Denis Date: Sat, 3 Jul 2021 16:40:11 +0300 Subject: [PATCH 15/93] Add generator wrapper --- src/elliptic/curves/traits.rs | 6 +- src/elliptic/curves/wrappers.rs | 248 +++++++++++++++++++++++++------- 2 files changed, 196 insertions(+), 58 deletions(-) diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index bd57200a..7c2c7cbb 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -34,7 +34,7 @@ pub trait Curve { /// /// Trait exposes various methods to manipulate scalars. Scalar can be zero. Scalar must zeroize its /// value on drop. -pub trait ECScalar: Clone + PartialEq + fmt::Debug { +pub trait ECScalar: Clone + PartialEq + fmt::Debug + 'static { /// Underlying scalar type that can be retrieved in case of missing methods in this trait type Underlying; @@ -101,8 +101,8 @@ pub trait ECScalar: Clone + PartialEq + fmt::Debug { /// /// Trait exposes various methods that make elliptic curve arithmetic. The point can /// be [zero](ECPoint::zero). Unlike [ECScalar], ECPoint isn't required to zeroize its value on drop, -/// but it implementы [Zeroize] trait so you can force zeroizing policy on your own. -pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug { +/// but it implements [Zeroize] trait so you can force zeroizing policy on your own. +pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug + 'static { /// Scalar value the point can be multiplied at type Scalar: ECScalar; /// Underlying curve implementation that can be retrieved in case of missing methods in this trait diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index 3d4c2b37..cb98af52 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::convert::TryFrom; +use std::marker::PhantomData; use std::{fmt, iter, ops}; use serde::{Deserialize, Serialize}; @@ -159,13 +160,26 @@ impl fmt::Debug for PointZ { /// /// ```rust /// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; -/// let s = Scalar::::random(); // Non-zero scalar -/// let g = Point::::generator(); // Non-zero point (curve generator) -/// let result: PointZ = s * g; // Multiplication of two non-zero points -/// // might produce zero-point +/// let p1: Point = +/// Point::generator() * Scalar::random(); // Non-zero point +/// let p2: Point = +/// Point::generator() * Scalar::random(); // Non-zero point +/// let result: PointZ = p1 + p2; // Addition of two (even non-zero) +/// // points might produce zero point /// let nonzero_result: Option> = result.ensure_nonzero(); /// ``` /// +/// Exception is [curve generator](Self::generator) that can be multiplied at non-zero scalar, and +/// resulting point is guaranteed to be non-zero: +/// +/// ```rust +/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; +/// let s = Scalar::::random(); // Non-zero scalar +/// let g = Point::::generator(); // Curve generator +/// let result: Point = s * g; // Generator multiplied at non-zero scalar is +/// // always a non-zero point +/// ``` +/// /// When evaluating complex expressions, you typically need to ensure that none of intermediate /// results are zero-points: /// @@ -184,9 +198,8 @@ impl Point { /// /// Returns a static reference on actual value because in most cases referenced value is fine. /// Use [`.to_point_owned()`](PointRef::to_point_owned) if you need to take it by value. - pub fn generator() -> PointRef<'static, E> { - let p = E::Point::generator(); - PointRef::from_raw(p).expect("generator must be non-zero") + pub fn generator() -> Generator { + Generator::default() } /// Curve second generator @@ -308,6 +321,51 @@ impl TryFrom> for Point { } } +/// Elliptic curve generator +/// +/// Holds internally a static reference on curve generator. Can be used in arithmetic interchangeably +/// as [`PointRef`](PointRef). +/// +/// Generator multiplied at non-zero scalar always produce non-zero point, thus output type of +/// the multiplication is [`Point`](Point). This is the only difference compared to `Point` and +/// `PointRef`. Use [`to_point_owned`](Self::to_point_owned) and [`as_point_ref`](Self::as_point_ref) +/// methods to convert the generator into `Point` and `PointRef`. +pub struct Generator { + _ph: PhantomData<&'static E::Point>, +} + +impl Default for Generator { + fn default() -> Self { + Self { _ph: PhantomData } + } +} + +impl Generator { + fn as_raw(self) -> &'static E::Point { + E::Point::generator() + } + + /// Clones generator point, returns `Point` + pub fn to_point_owned(self) -> Point { + // Safety: curve generator must be non-zero point, otherwise nothing will work at all + unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } + } + + /// Converts generator into `PointRef` + pub fn as_point_ref(self) -> PointRef<'static, E> { + // Safety: curve generator must be non-zero point, otherwise nothing will work at all + unsafe { PointRef::from_raw_unchecked(self.as_raw()) } + } +} + +impl Clone for Generator { + fn clone(&self) -> Self { + Self { _ph: PhantomData } + } +} + +impl Copy for Generator {} + /// Reference on elliptic point, _guaranteed_ to be non-zero /// /// Holds internally a reference on [`Point`](Point), refer to its documentation to learn @@ -918,24 +976,29 @@ matrix! { point_fn = add_point, point_assign_fn = add_point_assign, pairs = { + (o_<> Point, Point), (o_<> Point, PointZ), (o_<> Point, &Point), (o_<> Point, &PointZ), - (r_<> &Point, &Point), (r_<> &Point, &PointZ), + (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), + + (o_<> PointZ, Point), (o_<> PointZ, PointZ), (o_<> PointZ, &Point), (o_<> PointZ, &PointZ), - (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), - (o_<> Point, Point), (o_<> PointZ, PointZ), - (o_<> Point, PointZ), (o_<> PointZ, Point), + (o_<'p> PointZ, PointRef<'p, E>), (o_<> PointZ, Generator), + (_o<> &Point, Point), (_o<> &Point, PointZ), + (r_<> &Point, &Point), (r_<> &Point, &PointZ), + (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), + (_o<> &PointZ, Point), (_o<> &PointZ, PointZ), + (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), + (r_<'p> &PointZ, PointRef<'p, E>), (r_<> &PointZ, Generator), - // The same as above, but replacing &Point with PointRef - (o_<'r> Point, PointRef<'r, E>), - (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'r> PointRef<'r, E>, &PointZ), - (o_<'r> PointZ, PointRef<'r, E>), - (r_<'r> &PointZ, PointRef<'r, E>), - (_o<'r> PointRef<'r, E>, Point), (_o<'r> PointRef<'r, E>, PointZ), + (_o<'p> PointRef<'p, E>, Point), (_o<'p> PointRef<'p, E>, PointZ), + (r_<'p> PointRef<'p, E>, &Point), (r_<'p> PointRef<'p, E>, &PointZ), + (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), - // And define trait between &Point and PointRef - (r_<'r> &Point, PointRef<'r, E>), (r_<'r> PointRef<'r, E>, &Point), + (_o<> Generator, Point), (_o<> Generator, PointZ), + (r_<> Generator, &Point), (r_<> Generator, &PointZ), + (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), } } @@ -947,24 +1010,29 @@ matrix! { point_fn = sub_point, point_assign_fn = sub_point_assign, pairs = { + (o_<> Point, Point), (o_<> Point, PointZ), (o_<> Point, &Point), (o_<> Point, &PointZ), - (r_<> &Point, &Point), (r_<> &Point, &PointZ), + (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), + + (o_<> PointZ, Point), (o_<> PointZ, PointZ), (o_<> PointZ, &Point), (o_<> PointZ, &PointZ), - (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), - (o_<> Point, Point), (o_<> PointZ, PointZ), - (o_<> Point, PointZ), (o_<> PointZ, Point), + (o_<'p> PointZ, PointRef<'p, E>), (o_<> PointZ, Generator), + (_o<> &Point, Point), (_o<> &Point, PointZ), + (r_<> &Point, &Point), (r_<> &Point, &PointZ), + (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), + (_o<> &PointZ, Point), (_o<> &PointZ, PointZ), + (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), + (r_<'p> &PointZ, PointRef<'p, E>), (r_<> &PointZ, Generator), - // The same as above, but replacing &Point with PointRef - (o_<'r> Point, PointRef<'r, E>), - (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'r> PointRef<'r, E>, &PointZ), - (o_<'r> PointZ, PointRef<'r, E>), - (r_<'r> &PointZ, PointRef<'r, E>), - (_o<'r> PointRef<'r, E>, Point), (_o<'r> PointRef<'r, E>, PointZ), + (_o<'p> PointRef<'p, E>, Point), (_o<'p> PointRef<'p, E>, PointZ), + (r_<'p> PointRef<'p, E>, &Point), (r_<'p> PointRef<'p, E>, &PointZ), + (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), - // And define trait between &Point and PointRef - (r_<'r> &Point, PointRef<'r, E>), (r_<'r> PointRef<'r, E>, &Point), + (_o<> Generator, Point), (_o<> Generator, PointZ), + (r_<> Generator, &Point), (r_<> Generator, &PointZ), + (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), } } @@ -976,33 +1044,41 @@ matrix! { point_fn = scalar_mul, point_assign_fn = scalar_mul_assign, pairs = { + (_o<> Scalar, Point), (_o<> Scalar, PointZ), + (_r<> Scalar, &Point), (_r<> Scalar, &PointZ), + (_r<'p> Scalar, PointRef<'p, E>), /*(_r<> Scalar, Generator),*/ + + (_o<> ScalarZ, Point), (_o<> ScalarZ, PointZ), + (_r<> ScalarZ, &Point), (_r<> ScalarZ, &PointZ), + (_r<'p> ScalarZ, PointRef<'p, E>), (_r<> ScalarZ, Generator), + + (_o<> &Scalar, Point), (_o<> &Scalar, PointZ), + (_r<> &Scalar, &Point), (_r<> &Scalar, &PointZ), + (_r<'p> &Scalar, PointRef<'p, E>), /*(_r<> &Scalar, Generator),*/ + + (_o<> &ScalarZ, Point), (_o<> &ScalarZ, PointZ), + (_r<> &ScalarZ, &Point), (_r<> &ScalarZ, &PointZ), + (_r<'p> &ScalarZ, PointRef<'p, E>), (_r<> &ScalarZ, Generator), + + // --- and vice-versa --- + + (o_<> Point, Scalar), (o_<> Point, ScalarZ), (o_<> Point, &Scalar), (o_<> Point, &ScalarZ), - (r_<> &Point, &Scalar), (r_<> &Point, &ScalarZ), + + (o_<> PointZ, Scalar), (o_<> PointZ, ScalarZ), (o_<> PointZ, &Scalar), (o_<> PointZ, &ScalarZ), - (r_<> &PointZ, &Scalar), (r_<> &PointZ, &ScalarZ), - (o_<> Point, Scalar), (o_<> Point, ScalarZ), + (r_<> &Point, Scalar), (r_<> &Point, ScalarZ), - (o_<> PointZ, Scalar), (o_<> PointZ, ScalarZ), + (r_<> &Point, &Scalar), (r_<> &Point, &ScalarZ), + (r_<> &PointZ, Scalar), (r_<> &PointZ, ScalarZ), + (r_<> &PointZ, &Scalar), (r_<> &PointZ, &ScalarZ), - // The same as above but replacing &Point with PointRef - (r_<'p> PointRef<'p, E>, &Scalar), (r_<'p> PointRef<'p, E>, &ScalarZ), (r_<'p> PointRef<'p, E>, Scalar), (r_<'p> PointRef<'p, E>, ScalarZ), + (r_<'p> PointRef<'p, E>, &Scalar), (r_<'p> PointRef<'p, E>, &ScalarZ), - // --- And vice-versa --- - - (_o<> &Scalar, Point), (_o<> &ScalarZ, Point), - (_r<> &Scalar, &Point), (_r<> &ScalarZ, &Point), - (_o<> &Scalar, PointZ), (_o<> &ScalarZ, PointZ), - (_r<> &Scalar, &PointZ), (_r<> &ScalarZ, &PointZ), - (_o<> Scalar, Point), (_o<> ScalarZ, Point), - (_r<> Scalar, &Point), (_r<> ScalarZ, &Point), - (_o<> Scalar, PointZ), (_o<> ScalarZ, PointZ), - (_r<> Scalar, &PointZ), (_r<> ScalarZ, &PointZ), - - // The same as above but replacing &Point with PointRef - (_r<'p> &Scalar, PointRef<'p, E>), (_r<'p> &ScalarZ, PointRef<'p, E>), - (_r<'p> Scalar, PointRef<'p, E>), (_r<'p> ScalarZ, PointRef<'p, E>), + /*(r_<> Generator, Scalar),*/ (r_<> Generator, ScalarZ), + /*(r_<> Generator, &Scalar),*/ (r_<> Generator, &ScalarZ), } } @@ -1063,6 +1139,35 @@ matrix! { } } +impl ops::Mul<&Scalar> for Generator { + type Output = Point; + fn mul(self, rhs: &Scalar) -> Self::Output { + Point::from_raw(self.as_raw().scalar_mul(&rhs.as_raw())) + .expect("generator multiplied by non-zero scalar is always non-zero point") + } +} + +impl ops::Mul> for Generator { + type Output = Point; + fn mul(self, rhs: Scalar) -> Self::Output { + self.mul(&rhs) + } +} + +impl ops::Mul> for &Scalar { + type Output = Point; + fn mul(self, rhs: Generator) -> Self::Output { + rhs.mul(self) + } +} + +impl ops::Mul> for Scalar { + type Output = Point; + fn mul(self, rhs: Generator) -> Self::Output { + rhs.mul(self) + } +} + impl ops::Neg for Scalar { type Output = Scalar; @@ -1279,8 +1384,8 @@ mod test { fn _curve() { assert_operator_defined_for! { assert_fn = assert_point_addition_defined, - lhs = {Point, PointZ, &Point, &PointZ, PointRef}, - rhs = {Point, PointZ, &Point, &PointZ, PointRef}, + lhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, + rhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, } } } @@ -1301,8 +1406,8 @@ mod test { fn _curve() { assert_operator_defined_for! { assert_fn = assert_point_subtraction_defined, - lhs = {Point, PointZ, &Point, &PointZ, PointRef}, - rhs = {Point, PointZ, &Point, &PointZ, PointRef}, + lhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, + rhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, } } } @@ -1318,6 +1423,17 @@ mod test { // no-op } + /// Function asserts that M can be multiplied by N (ie. M * N) and result is **non-zero** Point. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_point_nonzero_multiplication_defined() + where + M: ops::Mul>, + E: Curve, + { + // no-op + } + #[test] fn test_point_multiplication_defined() { fn _curve() { @@ -1331,6 +1447,28 @@ mod test { lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, rhs = {Point, PointZ, &Point, &PointZ, PointRef}, } + + // Checking generator's arithmetic + assert_operator_defined_for! { + assert_fn = assert_point_multiplication_defined, + lhs = {Generator}, + rhs = {ScalarZ, &ScalarZ}, + } + assert_operator_defined_for! { + assert_fn = assert_point_nonzero_multiplication_defined, + lhs = {Generator}, + rhs = {Scalar, &Scalar}, + } + assert_operator_defined_for! { + assert_fn = assert_point_multiplication_defined, + lhs = {ScalarZ, &ScalarZ}, + rhs = {Generator}, + } + assert_operator_defined_for! { + assert_fn = assert_point_nonzero_multiplication_defined, + lhs = {Scalar, &Scalar}, + rhs = {Generator}, + } } } From 45c96b169993883628bd97d87b66858f0ca8afb5 Mon Sep 17 00:00:00 2001 From: Denis Date: Sat, 3 Jul 2021 18:35:14 +0300 Subject: [PATCH 16/93] Add secp256k1 test --- src/elliptic/curves/secp256_k1.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 58ecbd0c..c6043fc2 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -659,6 +659,14 @@ mod test { assert_eq!(point, deserialized); } + #[test] + fn generator_mul_curve_order_is_zero() { + let g = GE::generator(); + let n = FE::curve_order() - 1; + let s = FE::from_bigint(&n); + assert!(g.scalar_mul(&s).add_point(&g).is_zero()); + } + // #[test] // fn test_base_point2() { // /* Show that base_point2() is returning a point of unknown discrete logarithm. From 03d1c25d41124a59d1ec53587062769838fbf631 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 5 Jul 2021 07:10:30 +0300 Subject: [PATCH 17/93] Implement Serialize, Deserialize for Point(Z) --- src/elliptic/curves/traits.rs | 5 +- src/elliptic/curves/wrappers.rs | 151 ++++++++++++++++++++++++++++++-- 2 files changed, 146 insertions(+), 10 deletions(-) diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 7c2c7cbb..d1837a76 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -7,9 +7,11 @@ use std::fmt; -use crate::BigInt; +use serde::{Deserialize, Serialize}; use zeroize::Zeroize; +use crate::BigInt; + /// Elliptic curve implementation /// /// Refers to according implementation of [ECPoint] and [ECScalar]. @@ -188,6 +190,7 @@ pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug + 'static { fn from_underlying(u: Self::Underlying) -> Self; } +#[derive(Serialize, Deserialize)] pub struct PointCoords { pub x: BigInt, pub y: BigInt, diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index cb98af52..9fcd48bd 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -38,6 +38,8 @@ use crate::arithmetic::{BigInt, Converter}; /// a + b * c /// } /// ``` +#[derive(Serialize, Deserialize)] +#[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] pub struct PointZ(E::Point); impl PointZ { @@ -189,6 +191,8 @@ impl fmt::Debug for PointZ { /// (a + (b * c).ensure_nonzero()?).ensure_nonzero() /// } /// ``` +#[derive(Serialize, Deserialize)] +#[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] pub struct Point { raw_point: E::Point, } @@ -567,7 +571,7 @@ pub enum PointFromBytesError { /// } /// ``` #[derive(Serialize, Deserialize)] -#[serde(try_from = "ScalarFormat", into = "ScalarFormat")] +#[serde(try_from = "ScalarFormat", into = "ScalarFormat", bound = "")] pub struct ScalarZ { raw_scalar: E::Scalar, } @@ -739,7 +743,7 @@ impl From for ScalarZ { /// } /// ``` #[derive(Serialize, Deserialize)] -#[serde(try_from = "ScalarFormat", into = "ScalarFormat")] +#[serde(try_from = "ScalarFormat", into = "ScalarFormat", bound = "")] pub struct Scalar { raw_scalar: E::Scalar, } @@ -844,6 +848,48 @@ impl PartialEq> for Scalar { } } +impl TryFrom for Scalar { + type Error = ZeroScalarError; + fn try_from(n: u16) -> Result { + Self::from_bigint(&BigInt::from(n)) + } +} + +impl TryFrom for Scalar { + type Error = ZeroScalarError; + fn try_from(n: u32) -> Result { + Self::from_bigint(&BigInt::from(n)) + } +} + +impl TryFrom for Scalar { + type Error = ZeroScalarError; + fn try_from(n: u64) -> Result { + Self::from_bigint(&BigInt::from(n)) + } +} + +impl TryFrom for Scalar { + type Error = ZeroScalarError; + fn try_from(n: i32) -> Result { + Self::from_bigint(&BigInt::from(n)) + } +} + +impl TryFrom<&BigInt> for Scalar { + type Error = ZeroScalarError; + fn try_from(n: &BigInt) -> Result { + Self::from_bigint(n) + } +} + +impl TryFrom for Scalar { + type Error = ZeroScalarError; + fn try_from(n: BigInt) -> Result { + Self::from_bigint(&n) + } +} + macro_rules! matrix { ( trait = $trait:ident, @@ -1240,10 +1286,97 @@ impl ops::Neg for &PointZ { } } +#[derive(Serialize, Deserialize)] +#[serde(bound = "")] +struct PointFormat { + curve: Cow<'static, str>, + point: Option, + #[serde(skip, default = "PointFormat::::_ph")] + _ph: PhantomData, +} + +impl PointFormat { + fn _ph() -> PhantomData { + PhantomData + } +} + +impl TryFrom> for PointZ { + type Error = ConvertParsedPointError; + fn try_from(parsed: PointFormat) -> Result { + if parsed.curve != E::curve_name() { + return Err(ConvertParsedPointError::MismatchedCurve { + expected: E::curve_name(), + got: parsed.curve, + }); + } + match parsed.point { + None => Ok(PointZ::zero()), + Some(coords) => PointZ::from_coords(&coords.x, &coords.y) + .map_err(|_: NotOnCurve| ConvertParsedPointError::NotOnCurve), + } + } +} + +impl From> for PointFormat { + fn from(point: PointZ) -> Self { + Self { + curve: E::curve_name().into(), + point: point.coords(), + _ph: PhantomData, + } + } +} + +impl TryFrom> for Point { + type Error = ConvertParsedPointError; + fn try_from(parsed: PointFormat) -> Result { + if parsed.curve != E::curve_name() { + return Err(ConvertParsedPointError::MismatchedCurve { + expected: E::curve_name(), + got: parsed.curve, + }); + } + match parsed.point { + None => Err(ConvertParsedPointError::ZeroPoint), + Some(coords) => match Point::from_coords(&coords.x, &coords.y) { + Ok(p) => Ok(p), + Err(PointFromCoordsError::PointNotOnCurve) => { + Err(ConvertParsedPointError::NotOnCurve) + } + Err(PointFromCoordsError::ZeroPoint) => Err(ConvertParsedPointError::ZeroPoint), + }, + } + } +} + +impl From> for PointFormat { + fn from(point: Point) -> Self { + Self { + curve: E::curve_name().into(), + point: Some(point.coords()), + _ph: PhantomData, + } + } +} + +#[derive(Debug, Error)] +enum ConvertParsedPointError { + #[error("point must not be zero")] + ZeroPoint, + #[error("expected point of curve {expected}, but got point of curve {got}")] + MismatchedCurve { + got: Cow<'static, str>, + expected: &'static str, + }, + #[error("point not on the curve: x,y don't satisfy curve equation")] + NotOnCurve, +} + #[derive(Serialize, Deserialize)] #[serde(bound = "")] struct ScalarFormat { - curve_name: Cow<'static, str>, + curve: Cow<'static, str>, #[serde(with = "hex")] scalar: ScalarHex, } @@ -1252,9 +1385,9 @@ impl TryFrom> for ScalarZ { type Error = ConvertParsedScalarError; fn try_from(parsed: ScalarFormat) -> Result { - if parsed.curve_name != E::curve_name() { + if parsed.curve != E::curve_name() { return Err(ConvertParsedScalarError::MismatchedCurve { - got: parsed.curve_name, + got: parsed.curve, expected: E::curve_name(), }); } @@ -1266,7 +1399,7 @@ impl TryFrom> for ScalarZ { impl From> for ScalarFormat { fn from(s: ScalarZ) -> Self { ScalarFormat { - curve_name: E::curve_name().into(), + curve: E::curve_name().into(), scalar: ScalarHex(s.into_raw()), } } @@ -1276,9 +1409,9 @@ impl TryFrom> for Scalar { type Error = ConvertParsedScalarError; fn try_from(parsed: ScalarFormat) -> Result { - if parsed.curve_name != E::curve_name() { + if parsed.curve != E::curve_name() { return Err(ConvertParsedScalarError::MismatchedCurve { - got: parsed.curve_name, + got: parsed.curve, expected: E::curve_name(), }); } @@ -1292,7 +1425,7 @@ impl TryFrom> for Scalar { impl From> for ScalarFormat { fn from(s: Scalar) -> Self { ScalarFormat { - curve_name: E::curve_name().into(), + curve: E::curve_name().into(), scalar: ScalarHex(s.into_raw()), } } From 36cddf0226d027d018c53ad04b8ca4d3625f4084 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 5 Jul 2021 07:11:19 +0300 Subject: [PATCH 18/93] Update feldman_vss --- .../secret_sharing/feldman_vss.rs | 313 ++++++++---------- .../secret_sharing/mod.rs | 2 +- src/lib.rs | 42 +-- 3 files changed, 159 insertions(+), 198 deletions(-) diff --git a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs index a2d89b43..fd5f6e38 100644 --- a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs +++ b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs @@ -10,10 +10,8 @@ use std::convert::{TryFrom, TryInto}; use serde::{Deserialize, Serialize}; -use crate::arithmetic::traits::*; use crate::cryptographic_primitives::secret_sharing::Polynomial; -use crate::elliptic::curves::traits::*; -use crate::BigInt; +use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; use crate::ErrorSS::{self, VerifyShareError}; #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] @@ -21,42 +19,39 @@ pub struct ShamirSecretSharing { pub threshold: usize, //t pub share_count: usize, //n } + /// Feldman VSS, based on Paul Feldman. 1987. A practical scheme for non-interactive verifiable secret sharing. /// In Foundations of Computer Science, 1987., 28th Annual Symposium on.IEEE, 427–43 /// /// implementation details: The code is using FE and GE. Each party is given an index from 1,..,n and a secret share of type FE. /// The index of the party is also the point on the polynomial where we treat this number as u32 but converting it to FE internally. #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct VerifiableSS

{ +pub struct VerifiableSS { pub parameters: ShamirSecretSharing, - pub commitments: Vec

, + pub commitments: Vec>, } -impl

VerifiableSS

-where - P: ECPoint + Clone, - P::Scalar: Clone, -{ +impl VerifiableSS { pub fn reconstruct_limit(&self) -> usize { self.parameters.threshold + 1 } // TODO: share should accept u16 rather than usize // generate VerifiableSS from a secret - pub fn share(t: usize, n: usize, secret: &P::Scalar) -> (VerifiableSS

, Vec) { + pub fn share(t: usize, n: usize, secret: &ScalarZ) -> (VerifiableSS, Vec>) { assert!(t < n); let t = u16::try_from(t).unwrap(); let n = u16::try_from(n).unwrap(); - let poly = Polynomial::

::sample_with_fixed_const_term(t, secret.clone()); + let poly = Polynomial::::sample_with_fixed_const_term(t, secret.clone()); let secret_shares = poly.evaluate_many_bigint(1..=n).collect(); - let G: P = ECPoint::generator(); + let g = Point::::generator(); let commitments = poly .coefficients() .iter() - .map(|coef| G.clone() * coef.clone()) - .collect::>(); + .map(|coef| g * coef) + .collect::>(); ( VerifiableSS { parameters: ShamirSecretSharing { @@ -70,21 +65,21 @@ where } // takes given VSS and generates a new VSS for the same secret and a secret shares vector to match the new commitments - pub fn reshare(&self) -> (VerifiableSS

, Vec) { + pub fn reshare(&self) -> (VerifiableSS, Vec>) { // TODO: ShamirSecretSharing::{threshold, share_count} should be u16 rather than usize let t = u16::try_from(self.parameters.threshold).unwrap(); let n = u16::try_from(self.parameters.share_count).unwrap(); - let one: P::Scalar = ECScalar::from(&BigInt::one()); - let poly = Polynomial::

::sample_with_fixed_const_term(t, one.clone()); + let one = ScalarZ::::from(1); + let poly = Polynomial::::sample_with_fixed_const_term(t, one.clone()); let secret_shares_biased: Vec<_> = poly.evaluate_many_bigint(1..=n).collect(); let secret_shares: Vec<_> = (0..secret_shares_biased.len()) - .map(|i| secret_shares_biased[i].sub(&one.get_element())) + .map(|i| &secret_shares_biased[i] - &one) .collect(); - let G: P = ECPoint::generator(); + let g = Point::::generator(); let mut new_commitments = vec![self.commitments[0].clone()]; for (poly, commitment) in poly.coefficients().iter().zip(&self.commitments).skip(1) { - new_commitments.push((G.clone() * poly.clone()) + commitment.clone()) + new_commitments.push((g * poly) + commitment) } ( VerifiableSS { @@ -99,24 +94,24 @@ where pub fn share_at_indices( t: usize, n: usize, - secret: &P::Scalar, + secret: &ScalarZ, index_vec: &[usize], - ) -> (VerifiableSS

, Vec) { + ) -> (VerifiableSS, Vec>) { assert_eq!(n, index_vec.len()); // TODO: share_at_indices should accept u16 rather than usize (t, n, index_vec) let t = u16::try_from(t).unwrap(); let n = u16::try_from(n).unwrap(); let index_vec = index_vec.iter().map(|&i| u16::try_from(i).unwrap()); - let poly = Polynomial::

::sample_with_fixed_const_term(t, secret.clone()); + let poly = Polynomial::::sample_with_fixed_const_term(t, secret.clone()); let secret_shares = poly.evaluate_many_bigint(index_vec).collect(); - let G: P = ECPoint::generator(); + let g = Point::::generator(); let commitments = poly .coefficients() .iter() - .map(|coef| G.clone() * coef.clone()) - .collect::>(); + .map(|coef| g * coef) + .collect::>>(); ( VerifiableSS { parameters: ShamirSecretSharing { @@ -131,8 +126,8 @@ where // returns vector of coefficients #[deprecated(since = "0.7.1", note = "please use Polynomial::sample instead")] - pub fn sample_polynomial(t: usize, coef0: &P::Scalar) -> Vec { - Polynomial::

::sample_with_fixed_const_term(t.try_into().unwrap(), coef0.clone()) + pub fn sample_polynomial(t: usize, coef0: &ScalarZ) -> Vec> { + Polynomial::::sample_with_fixed_const_term(t.try_into().unwrap(), coef0.clone()) .coefficients() .to_vec() } @@ -141,38 +136,29 @@ where since = "0.7.1", note = "please use Polynomial::evaluate_many_bigint instead" )] - pub fn evaluate_polynomial(coefficients: &[P::Scalar], index_vec: &[usize]) -> Vec { - Polynomial::

::from_coefficients(coefficients.to_vec()) + pub fn evaluate_polynomial( + coefficients: &[ScalarZ], + index_vec: &[usize], + ) -> Vec> { + Polynomial::::from_coefficients(coefficients.to_vec()) .evaluate_many_bigint(index_vec.iter().map(|&i| u64::try_from(i).unwrap())) .collect() } #[deprecated(since = "0.7.1", note = "please use Polynomial::evaluate instead")] - pub fn mod_evaluate_polynomial(coefficients: &[P::Scalar], point: P::Scalar) -> P::Scalar { - // evaluate using Horner's rule - // - to combine with fold we consider the coefficients in reverse order - let mut reversed_coefficients = coefficients.iter().rev(); - // manually split due to fold insisting on an initial value - let head = reversed_coefficients.next().unwrap(); - let tail = reversed_coefficients; - tail.fold(head.clone(), |partial, coef| { - let partial_times_point = partial.mul(&point.get_element()); - partial_times_point.add(&coef.get_element()) - }) + pub fn mod_evaluate_polynomial(coefficients: &[ScalarZ], point: ScalarZ) -> ScalarZ { + Polynomial::::from_coefficients(coefficients.to_vec()).evaluate(&point) } - pub fn reconstruct(&self, indices: &[usize], shares: &[P::Scalar]) -> P::Scalar { + pub fn reconstruct(&self, indices: &[usize], shares: &[ScalarZ]) -> ScalarZ { assert_eq!(shares.len(), indices.len()); assert!(shares.len() >= self.reconstruct_limit()); // add one to indices to get points let points = indices .iter() - .map(|i| { - let index_bn = BigInt::from(*i as u32 + 1); - ECScalar::from(&index_bn) - }) - .collect::>(); - VerifiableSS::

::lagrange_interpolation_at_zero(&points, &shares) + .map(|i| ScalarZ::from(*i as u32 + 1)) + .collect::>(); + VerifiableSS::::lagrange_interpolation_at_zero(&points, &shares) } // Performs a Lagrange interpolation in field Zp at the origin @@ -185,50 +171,54 @@ where // This is obviously less general than `newton_interpolation_general` as we // only get a single value, but it is much faster. - pub fn lagrange_interpolation_at_zero(points: &[P::Scalar], values: &[P::Scalar]) -> P::Scalar { + pub fn lagrange_interpolation_at_zero( + points: &[ScalarZ], + values: &[ScalarZ], + ) -> ScalarZ { let vec_len = values.len(); assert_eq!(points.len(), vec_len); // Lagrange interpolation for point 0 // let mut acc = 0i64; - let lag_coef = (0..vec_len) - .map(|i| { - let xi = &points[i]; - let yi = &values[i]; - let num: P::Scalar = ECScalar::from(&BigInt::one()); - let denum: P::Scalar = ECScalar::from(&BigInt::one()); - let num = points.iter().zip(0..vec_len).fold(num, |acc, x| { - if i != x.1 { - acc * x.0.clone() - } else { - acc - } - }); - let denum = points.iter().zip(0..vec_len).fold(denum, |acc, x| { - if i != x.1 { - let xj_sub_xi = x.0.sub(&xi.get_element()); - acc * xj_sub_xi - } else { - acc - } - }); - let denum = denum.invert(); - num * denum * yi.clone() - }) - .collect::>(); + let lag_coef = + (0..vec_len) + .map(|i| { + let xi = &points[i]; + let yi = &values[i]; + let num = ScalarZ::from(1); + let denum = ScalarZ::from(1); + let num = points.iter().zip(0..vec_len).fold(num, |acc, x| { + if i != x.1 { + acc * x.0 + } else { + acc + } + }); + let denum = points.iter().zip(0..vec_len).fold(denum, |acc, x| { + if i != x.1 { + let xj_sub_xi = x.0 - xi; + acc * xj_sub_xi + } else { + acc + } + }); + let denum = denum.invert().unwrap(); + num * denum * yi + }) + .collect::>(); let mut lag_coef_iter = lag_coef.iter(); let head = lag_coef_iter.next().unwrap(); let tail = lag_coef_iter; - tail.fold(head.clone(), |acc, x| acc.add(&x.get_element())) + tail.fold(head.clone(), |acc, x| acc + x) } - pub fn validate_share(&self, secret_share: &P::Scalar, index: usize) -> Result<(), ErrorSS> { - let G: P = ECPoint::generator(); - let ss_point = G * secret_share.clone(); + pub fn validate_share(&self, secret_share: &ScalarZ, index: usize) -> Result<(), ErrorSS> { + let g = Point::generator(); + let ss_point = g * secret_share; self.validate_share_public(&ss_point, index) } - pub fn validate_share_public(&self, ss_point: &P, index: usize) -> Result<(), ErrorSS> { + pub fn validate_share_public(&self, ss_point: &PointZ, index: usize) -> Result<(), ErrorSS> { let comm_to_point = self.get_point_commitment(index); if *ss_point == comm_to_point { Ok(()) @@ -237,14 +227,12 @@ where } } - pub fn get_point_commitment(&self, index: usize) -> P { - let index_fe: P::Scalar = ECScalar::from(&BigInt::from(index as u32)); + pub fn get_point_commitment(&self, index: usize) -> PointZ { + let index_fe = ScalarZ::from(index as u32); let mut comm_iterator = self.commitments.iter().rev(); let head = comm_iterator.next().unwrap(); let tail = comm_iterator; - tail.fold(head.clone(), |acc, x: &P| { - x.clone() + acc * index_fe.clone() - }) + tail.fold(head.clone(), |acc, x| x + acc * &index_fe) } //compute \lambda_{index,S}, a lagrangian coefficient that change the (t,n) scheme to (|S|,|S|) @@ -253,36 +241,33 @@ where params: &ShamirSecretSharing, index: usize, s: &[usize], - ) -> P::Scalar { + ) -> ScalarZ { let s_len = s.len(); // assert!(s_len > self.reconstruct_limit()); // add one to indices to get points - let points: Vec = (0..params.share_count) - .map(|i| { - let index_bn = BigInt::from(i as u32 + 1); - ECScalar::from(&index_bn) - }) + let points: Vec> = (0..params.share_count) + .map(|i| Scalar::try_from(i as u32 + 1).expect("guaranteed to be positive")) .collect(); let xi = &points[index]; - let num: P::Scalar = ECScalar::from(&BigInt::one()); - let denum: P::Scalar = ECScalar::from(&BigInt::one()); + let num = ScalarZ::from(1); + let denum = ScalarZ::from(1); let num = (0..s_len).fold(num, |acc, i| { if s[i] != index { - acc * points[s[i]].clone() + acc * &points[s[i]] } else { acc } }); let denum = (0..s_len).fold(denum, |acc, i| { if s[i] != index { - let xj_sub_xi = points[s[i]].sub(&xi.get_element()); + let xj_sub_xi = &points[s[i]] - xi; acc * xj_sub_xi } else { acc } }); - let denum = denum.invert(); + let denum = denum.invert().unwrap(); num * denum } } @@ -294,15 +279,11 @@ mod tests { test_for_all_curves!(test_secret_sharing_3_out_of_5_at_indices); - fn test_secret_sharing_3_out_of_5_at_indices

() - where - P: ECPoint + Clone, - P::Scalar: Clone + PartialEq + std::fmt::Debug, - { - let secret: P::Scalar = ECScalar::new_random(); + fn test_secret_sharing_3_out_of_5_at_indices() { + let secret = ScalarZ::random(); let parties = [1, 2, 4, 5, 6]; let (vss_scheme, secret_shares) = - VerifiableSS::

::share_at_indices(3, 5, &secret, &parties); + VerifiableSS::::share_at_indices(3, 5, &secret, &parties); let shares_vec = vec![ secret_shares[0].clone(), @@ -319,14 +300,10 @@ mod tests { test_for_all_curves!(test_secret_sharing_3_out_of_5); - fn test_secret_sharing_3_out_of_5

() - where - P: ECPoint + Clone, - P::Scalar: Clone + PartialEq + std::fmt::Debug, - { - let secret: P::Scalar = ECScalar::new_random(); + fn test_secret_sharing_3_out_of_5() { + let secret = ScalarZ::random(); - let (vss_scheme, secret_shares) = VerifiableSS::

::share(3, 5, &secret); + let (vss_scheme, secret_shares) = VerifiableSS::::share(3, 5, &secret); let shares_vec = vec![ secret_shares[0].clone(), @@ -346,36 +323,32 @@ mod tests { assert!(valid3.is_ok()); assert!(valid1.is_ok()); - let g: P = ECPoint::generator(); - let share1_public = g * secret_shares[0].clone(); + let g = Point::generator(); + let share1_public = g * &secret_shares[0]; let valid1_public = vss_scheme.validate_share_public(&share1_public, 1); assert!(valid1_public.is_ok()); // test map (t,n) - (t',t') let s = &vec![0, 1, 2, 3, 4]; - let l0 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 0, &s); - let l1 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 1, &s); - let l2 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 2, &s); - let l3 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 3, &s); - let l4 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 4, &s); - let w = l0 * secret_shares[0].clone() - + l1 * secret_shares[1].clone() - + l2 * secret_shares[2].clone() - + l3 * secret_shares[3].clone() - + l4 * secret_shares[4].clone(); + let l0 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 0, &s); + let l1 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 1, &s); + let l2 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 2, &s); + let l3 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 3, &s); + let l4 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 4, &s); + let w = l0 * &secret_shares[0] + + l1 * &secret_shares[1] + + l2 * &secret_shares[2] + + l3 * &secret_shares[3] + + l4 * &secret_shares[4]; assert_eq!(w, secret_reconstructed); } test_for_all_curves!(test_secret_sharing_3_out_of_7); - fn test_secret_sharing_3_out_of_7

() - where - P: ECPoint + Clone, - P::Scalar: Clone + PartialEq + std::fmt::Debug, - { - let secret: P::Scalar = ECScalar::new_random(); + fn test_secret_sharing_3_out_of_7() { + let secret = ScalarZ::random(); - let (vss_scheme, secret_shares) = VerifiableSS::

::share(3, 7, &secret); + let (vss_scheme, secret_shares) = VerifiableSS::::share(3, 7, &secret); let shares_vec = vec![ secret_shares[0].clone(), @@ -396,30 +369,26 @@ mod tests { // test map (t,n) - (t',t') let s = &vec![0, 1, 3, 4, 6]; - let l0 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 0, &s); - let l1 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 1, &s); - let l3 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 3, &s); - let l4 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 4, &s); - let l6 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 6, &s); - - let w = l0 * secret_shares[0].clone() - + l1 * secret_shares[1].clone() - + l3 * secret_shares[3].clone() - + l4 * secret_shares[4].clone() - + l6 * secret_shares[6].clone(); + let l0 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 0, &s); + let l1 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 1, &s); + let l3 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 3, &s); + let l4 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 4, &s); + let l6 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 6, &s); + + let w = l0 * &secret_shares[0] + + l1 * &secret_shares[1] + + l3 * &secret_shares[3] + + l4 * &secret_shares[4] + + l6 * &secret_shares[6]; assert_eq!(w, secret_reconstructed); } test_for_all_curves!(test_secret_sharing_1_out_of_2); - fn test_secret_sharing_1_out_of_2

() - where - P: ECPoint + Clone, - P::Scalar: Clone + PartialEq + std::fmt::Debug, - { - let secret: P::Scalar = ECScalar::new_random(); + fn test_secret_sharing_1_out_of_2() { + let secret = ScalarZ::random(); - let (vss_scheme, secret_shares) = VerifiableSS::

::share(1, 2, &secret); + let (vss_scheme, secret_shares) = VerifiableSS::::share(1, 2, &secret); let shares_vec = vec![secret_shares[0].clone(), secret_shares[1].clone()]; @@ -435,34 +404,30 @@ mod tests { // test map (t,n) - (t',t') let s = &vec![0, 1]; - let l0 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 0, &s); - let l1 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 1, &s); - let w = l0 * secret_shares[0].clone() + l1 * secret_shares[1].clone(); + let l0 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 0, &s); + let l1 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 1, &s); + let w = l0 * &secret_shares[0] + l1 * &secret_shares[1]; assert_eq!(w, secret_reconstructed); } test_for_all_curves!(test_secret_sharing_1_out_of_3); - fn test_secret_sharing_1_out_of_3

() - where - P: ECPoint + Clone + std::fmt::Debug, - P::Scalar: Clone + PartialEq + std::fmt::Debug, - { - let secret: P::Scalar = ECScalar::new_random(); + fn test_secret_sharing_1_out_of_3() { + let secret = ScalarZ::random(); - let (vss_scheme, secret_shares) = VerifiableSS::

::share(1, 3, &secret); + let (vss_scheme, secret_shares) = VerifiableSS::::share(1, 3, &secret); let shares_vec = vec![secret_shares[0].clone(), secret_shares[1].clone()]; // test commitment to point and sum of commitments - let (vss_scheme2, secret_shares2) = VerifiableSS::

::share(1, 3, &secret); - let sum = secret_shares[0].clone() + secret_shares2[0].clone(); + let (vss_scheme2, secret_shares2) = VerifiableSS::::share(1, 3, &secret); + let sum = &secret_shares[0] + &secret_shares2[0]; let point_comm1 = vss_scheme.get_point_commitment(1); let point_comm2 = vss_scheme.get_point_commitment(2); - let g: P = ECPoint::generator(); - let g_sum = g.clone() * sum; - assert_eq!(g.clone() * secret_shares[0].clone(), point_comm1); - assert_eq!(g * secret_shares[1].clone(), point_comm2); + let g = Point::generator(); + let g_sum = g * sum; + assert_eq!(g * &secret_shares[0], point_comm1); + assert_eq!(g * &secret_shares[1], point_comm2); let point1_sum_com = vss_scheme.get_point_commitment(1) + vss_scheme2.get_point_commitment(1); assert_eq!(point1_sum_com, g_sum); @@ -479,28 +444,24 @@ mod tests { // test map (t,n) - (t',t') let s = &vec![0, 2]; - let l0 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 0, &s); - let l2 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 2, &s); + let l0 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 0, &s); + let l2 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 2, &s); - let w = l0 * secret_shares[0].clone() + l2 * secret_shares[2].clone(); + let w = l0 * &secret_shares[0] + l2 * &secret_shares[2]; assert_eq!(w, secret_reconstructed); } test_for_all_curves!(test_secret_resharing); - fn test_secret_resharing

() - where - P: ECPoint + Clone + std::fmt::Debug, - P::Scalar: Clone + PartialEq + std::fmt::Debug, - { - let secret: P::Scalar = ECScalar::new_random(); + fn test_secret_resharing() { + let secret = ScalarZ::random(); - let (vss_scheme, secret_shares) = VerifiableSS::

::share(1, 3, &secret); + let (vss_scheme, secret_shares) = VerifiableSS::::share(1, 3, &secret); let (new_vss_scheme, zero_secret_shares) = vss_scheme.reshare(); - let new_share_party_1 = secret_shares[0].clone() + zero_secret_shares[0].clone(); - let new_share_party_2 = secret_shares[1].clone() + zero_secret_shares[1].clone(); - let new_share_party_3 = secret_shares[2].clone() + zero_secret_shares[2].clone(); + let new_share_party_1 = &secret_shares[0] + &zero_secret_shares[0]; + let new_share_party_2 = &secret_shares[1] + &zero_secret_shares[1]; + let new_share_party_3 = &secret_shares[2] + &zero_secret_shares[2]; let shares_vec = vec![new_share_party_1.clone(), new_share_party_3.clone()]; diff --git a/src/cryptographic_primitives/secret_sharing/mod.rs b/src/cryptographic_primitives/secret_sharing/mod.rs index 6da64435..f50534df 100644 --- a/src/cryptographic_primitives/secret_sharing/mod.rs +++ b/src/cryptographic_primitives/secret_sharing/mod.rs @@ -5,7 +5,7 @@ License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE */ -// pub mod feldman_vss; +pub mod feldman_vss; mod polynomial; pub use polynomial::Polynomial; diff --git a/src/lib.rs b/src/lib.rs index 5356d21d..c41fbea3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,28 +37,28 @@ macro_rules! test_for_all_curves { #[test] $($attrs)* fn [<$fn _secp256k1>]() { - $fn::() - } - #[test] - $($attrs)* - fn [<$fn _ristretto>]() { - $fn::() - } - #[test] - $($attrs)* - fn [<$fn _ed25519>]() { - $fn::() - } - #[test] - $($attrs)* - fn [<$fn _bls12_381>]() { - $fn::() - } - #[test] - $($attrs)* - fn [<$fn _p256>]() { - $fn::() + $fn::() } + // #[test] + // $($attrs)* + // fn [<$fn _ristretto>]() { + // $fn::() + // } + // #[test] + // $($attrs)* + // fn [<$fn _ed25519>]() { + // $fn::() + // } + // #[test] + // $($attrs)* + // fn [<$fn _bls12_381>]() { + // $fn::() + // } + // #[test] + // $($attrs)* + // fn [<$fn _p256>]() { + // $fn::() + // } } }; } From 08764b7604fa1c11719ae85ad6dc9157472d6cde Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 5 Jul 2021 14:02:40 +0300 Subject: [PATCH 19/93] Add {to,from}_bytes functions to PointZ --- src/elliptic/curves/wrappers.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index 9fcd48bd..29b0224b 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -97,6 +97,19 @@ impl PointZ { E::Point::from_coords(x, y).map(Self::from_raw) } + /// Tries to parse a point from its (un)compressed form + /// + /// Whether it's a compressed or uncompressed form will be deduced from its length + pub fn from_bytes(bytes: &[u8]) -> Result { + let p = E::Point::deserialize(bytes)?; + Ok(Self::from_raw(p)) + } + + /// Serializes point into (un)compressed form + pub fn to_bytes(&self, compressed: bool) -> Option> { + self.as_raw().serialize(compressed) + } + fn from_raw(point: E::Point) -> Self { Self(point) } @@ -128,6 +141,12 @@ impl fmt::Debug for PointZ { } } +impl From> for PointZ { + fn from(p: Point) -> Self { + PointZ::from_raw(p.into_raw()) + } +} + /// Elliptic point that _guaranteed_ to be non zero /// /// ## Security From 877721e46a03a57da07317df1528c0d86393e283 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 5 Jul 2021 14:03:03 +0300 Subject: [PATCH 20/93] Update hashing --- .../hashing/blake2b512.rs | 44 ++++++++++------ .../hashing/hash_sha256.rs | 43 +++++++++------ .../hashing/hash_sha512.rs | 45 ++++++++++------ .../hashing/merkle_tree.rs | 52 ++++++++++--------- .../hashing/traits.rs | 5 +- src/cryptographic_primitives/mod.rs | 2 +- 6 files changed, 114 insertions(+), 77 deletions(-) diff --git a/src/cryptographic_primitives/hashing/blake2b512.rs b/src/cryptographic_primitives/hashing/blake2b512.rs index 3b273858..6092857c 100644 --- a/src/cryptographic_primitives/hashing/blake2b512.rs +++ b/src/cryptographic_primitives/hashing/blake2b512.rs @@ -5,7 +5,7 @@ License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE */ use crate::arithmetic::traits::*; -use crate::elliptic::curves::traits::{ECPoint, ECScalar}; +use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; use crate::BigInt; use blake2b_simd::Params; @@ -14,7 +14,6 @@ pub struct Blake; impl Blake { pub fn create_hash(big_ints: &[&BigInt], persona: &[u8]) -> BigInt { let mut digest = Params::new().hash_length(64).personal(persona).to_state(); - // let mut digest = Blake2b::with_params(64, &[], &[], persona); for value in big_ints { digest.update(&BigInt::to_bytes(value)); } @@ -22,16 +21,31 @@ impl Blake { BigInt::from_bytes(digest.finalize().as_ref()) } - pub fn create_hash_from_ge(ge_vec: &[&P], persona: &[u8]) -> P::Scalar { + pub fn create_hash_from_ge(ge_vec: &[&Point], persona: &[u8]) -> ScalarZ { let mut digest = Params::new().hash_length(64).personal(persona).to_state(); // let mut digest = Blake2b::with_params(64, &[], &[], persona); for value in ge_vec { - digest.update(&value.pk_to_key_slice()); + digest.update(&value.to_bytes(false)); } let result = BigInt::from_bytes(digest.finalize().as_ref()); - ECScalar::from(&result) + ScalarZ::from(&result) + } + + pub fn create_hash_from_ge_z(ge_vec: &[&PointZ], persona: &[u8]) -> ScalarZ { + let mut digest = Params::new().hash_length(64).personal(persona).to_state(); + // let mut digest = Blake2b::with_params(64, &[], &[], persona); + + for value in ge_vec { + match value.to_bytes(false) { + Some(serialized) => digest.update(&serialized), + None => digest.update(b"infinity point"), + }; + } + + let result = BigInt::from_bytes(digest.finalize().as_ref()); + ScalarZ::from(&result) } } @@ -39,7 +53,7 @@ impl Blake { mod tests { use super::Blake; use crate::arithmetic::traits::*; - use crate::elliptic::curves::traits::{ECPoint, ECScalar}; + use crate::elliptic::curves::{Curve, Point}; use crate::BigInt; #[test] @@ -51,17 +65,15 @@ mod tests { crate::test_for_all_curves!(create_hash_from_ge_test); - fn create_hash_from_ge_test

() - where - P: ECPoint, - P::Scalar: PartialEq + std::fmt::Debug, - { - let point = P::base_point2(); - let result1 = Blake::create_hash_from_ge(&[&point, &P::generator()], b"Zcash_RedJubjubH"); - assert!(result1.to_big_int().bit_length() > 240); - let result2 = Blake::create_hash_from_ge(&[&P::generator(), &point], b"Zcash_RedJubjubH"); + fn create_hash_from_ge_test() { + let base_point2 = Point::base_point2().to_point_owned(); + let generator = Point::generator().to_point_owned(); + let result1 = + Blake::create_hash_from_ge::(&[&base_point2, &generator], b"Zcash_RedJubjubH"); + assert!(result1.to_bigint().bit_length() > 240); + let result2 = Blake::create_hash_from_ge(&[&generator, &base_point2], b"Zcash_RedJubjubH"); assert_ne!(result1, result2); - let result3 = Blake::create_hash_from_ge(&[&P::generator(), &point], b"Zcash_RedJubjubH"); + let result3 = Blake::create_hash_from_ge(&[&generator, &base_point2], b"Zcash_RedJubjubH"); assert_eq!(result2, result3); } } diff --git a/src/cryptographic_primitives/hashing/hash_sha256.rs b/src/cryptographic_primitives/hashing/hash_sha256.rs index 09ebba36..89574411 100644 --- a/src/cryptographic_primitives/hashing/hash_sha256.rs +++ b/src/cryptographic_primitives/hashing/hash_sha256.rs @@ -7,12 +7,13 @@ use super::traits::Hash; use crate::arithmetic::traits::*; -use crate::elliptic::curves::traits::{ECPoint, ECScalar}; +use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; use digest::Digest; use sha2::Sha256; use crate::BigInt; + pub struct HSha256; impl Hash for HSha256 { @@ -27,15 +28,29 @@ impl Hash for HSha256 { BigInt::from_bytes(&result_hex[..]) } - fn create_hash_from_ge(ge_vec: &[&P]) -> P::Scalar { + fn create_hash_from_ge(ge_vec: &[&Point]) -> ScalarZ { + let mut hasher = Sha256::new(); + for value in ge_vec { + hasher.input(&value.to_bytes(false)); + } + + let result_hex = hasher.result(); + let result = BigInt::from_bytes(&result_hex[..]); + ScalarZ::from(&result) + } + + fn create_hash_from_ge_z(ge_vec: &[&PointZ]) -> ScalarZ { let mut hasher = Sha256::new(); for value in ge_vec { - hasher.input(&value.pk_to_key_slice()); + match value.to_bytes(false) { + Some(serialized) => hasher.input(&serialized), + None => hasher.input(b"infinity"), + } } let result_hex = hasher.result(); let result = BigInt::from_bytes(&result_hex[..]); - ECScalar::from(&result) + ScalarZ::from(&result) } fn create_hash_from_slice(byte_slice: &[u8]) -> BigInt { @@ -51,8 +66,7 @@ mod tests { use super::HSha256; use super::Hash; use crate::arithmetic::traits::*; - use crate::elliptic::curves::traits::ECPoint; - use crate::elliptic::curves::traits::ECScalar; + use crate::elliptic::curves::{Curve, Point}; use crate::BigInt; use sha2::Digest; use sha2::Sha256; @@ -111,17 +125,14 @@ mod tests { crate::test_for_all_curves!(create_sha256_from_ge_test); - fn create_sha256_from_ge_test

() - where - P: ECPoint, - P::Scalar: PartialEq + std::fmt::Debug, - { - let point = P::base_point2(); - let result1 = HSha256::create_hash_from_ge(&[&point, &P::generator()]); - assert!(result1.to_big_int().bit_length() > 240); - let result2 = HSha256::create_hash_from_ge(&[&P::generator(), &point]); + fn create_sha256_from_ge_test() { + let generator = Point::generator().to_point_owned(); + let base_point2 = Point::base_point2().to_point_owned(); + let result1 = HSha256::create_hash_from_ge::(&[&base_point2, &generator]); + assert!(result1.to_bigint().bit_length() > 240); + let result2 = HSha256::create_hash_from_ge(&[&generator, &base_point2]); assert_ne!(result1, result2); - let result3 = HSha256::create_hash_from_ge(&[&P::generator(), &point]); + let result3 = HSha256::create_hash_from_ge(&[&generator, &base_point2]); assert_eq!(result2, result3); } } diff --git a/src/cryptographic_primitives/hashing/hash_sha512.rs b/src/cryptographic_primitives/hashing/hash_sha512.rs index bb6d3321..d39fcf07 100644 --- a/src/cryptographic_primitives/hashing/hash_sha512.rs +++ b/src/cryptographic_primitives/hashing/hash_sha512.rs @@ -7,7 +7,7 @@ use super::traits::Hash; use crate::arithmetic::traits::*; -use crate::elliptic::curves::traits::{ECPoint, ECScalar}; +use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; use digest::Digest; use sha2::Sha512; @@ -28,15 +28,29 @@ impl Hash for HSha512 { BigInt::from_bytes(&result_hex[..]) } - fn create_hash_from_ge(ge_vec: &[&P]) -> P::Scalar { + fn create_hash_from_ge(ge_vec: &[&Point]) -> ScalarZ { let mut hasher = Sha512::new(); for value in ge_vec { - hasher.input(&value.pk_to_key_slice()); + hasher.input(&value.to_bytes(false)); } let result_hex = hasher.result(); let result = BigInt::from_bytes(&result_hex[..]); - ECScalar::from(&result) + ScalarZ::from(&result) + } + + fn create_hash_from_ge_z(ge_vec: &[&PointZ]) -> ScalarZ { + let mut hasher = Sha512::new(); + for value in ge_vec { + match value.to_bytes(false) { + Some(serialized) => hasher.input(&serialized), + None => hasher.input(b"infinity"), + } + } + + let result_hex = hasher.result(); + let result = BigInt::from_bytes(&result_hex[..]); + ScalarZ::from(&result) } fn create_hash_from_slice(byte_slice: &[u8]) -> BigInt { @@ -49,11 +63,11 @@ impl Hash for HSha512 { #[cfg(test)] mod tests { + use crate::arithmetic::*; + use crate::elliptic::curves::{Curve, Point}; + use super::HSha512; use super::Hash; - use crate::arithmetic::traits::*; - use crate::elliptic::curves::traits::{ECPoint, ECScalar}; - use crate::BigInt; #[test] // Test Vectors taken from: @@ -99,17 +113,14 @@ mod tests { crate::test_for_all_curves!(create_sha512_from_ge_test); - fn create_sha512_from_ge_test

() - where - P: ECPoint, - P::Scalar: PartialEq + std::fmt::Debug, - { - let point = P::base_point2(); - let result1 = HSha512::create_hash_from_ge(&[&point, &P::generator()]); - assert!(result1.to_big_int().bit_length() > 240); - let result2 = HSha512::create_hash_from_ge(&[&P::generator(), &point]); + fn create_sha512_from_ge_test() { + let generator = Point::generator().to_point_owned(); + let base_point2 = Point::base_point2().to_point_owned(); + let result1 = HSha512::create_hash_from_ge::(&[&base_point2, &generator]); + assert!(result1.to_bigint().bit_length() > 240); + let result2 = HSha512::create_hash_from_ge(&[&generator, &base_point2]); assert_ne!(result1, result2); - let result3 = HSha512::create_hash_from_ge(&[&P::generator(), &point]); + let result3 = HSha512::create_hash_from_ge(&[&generator, &base_point2]); assert_eq!(result2, result3); } } diff --git a/src/cryptographic_primitives/hashing/merkle_tree.rs b/src/cryptographic_primitives/hashing/merkle_tree.rs index 3456a181..f8cd940e 100644 --- a/src/cryptographic_primitives/hashing/merkle_tree.rs +++ b/src/cryptographic_primitives/hashing/merkle_tree.rs @@ -12,26 +12,28 @@ use std::marker::PhantomData; use crypto::sha3::Sha3; use merkle::{MerkleTree, Proof}; -use crate::elliptic::curves::traits::ECPoint; +use crate::elliptic::curves::{Curve, PointZ}; /* pub struct MT256<'a> { tree: MerkleTree, root: & 'a Vec, } */ -pub struct MT256

{ +pub struct MT256 { tree: MerkleTree<[u8; 32]>, - _ph: PhantomData

, + _ph: PhantomData, } //impl <'a> MT256<'a>{ -impl MT256

{ - pub fn create_tree(vec: &[P]) -> MT256

{ +impl MT256 { + pub fn create_tree(vec: &[PointZ]) -> MT256 { let digest = Sha3::keccak256(); - let mut array = [0u8; 32]; let vec_bytes = (0..vec.len()) .map(|i| { - let bytes = vec[i].pk_to_key_slice(); + let mut array = [0u8; 32]; + let bytes = vec[i] + .to_bytes(false) + .unwrap_or_else(|| b"infinity point".to_vec()); array.copy_from_slice(&bytes[0..32]); array }) @@ -44,9 +46,11 @@ impl MT256

{ } } - pub fn gen_proof_for_ge(&self, value: &P) -> Proof<[u8; 32]> { + pub fn gen_proof_for_ge(&self, value: &PointZ) -> Proof<[u8; 32]> { let mut array = [0u8; 32]; - let pk_slice = value.pk_to_key_slice(); + let pk_slice = value + .to_bytes(false) + .unwrap_or_else(|| b"infinity point".to_vec()); array.copy_from_slice(&pk_slice[0..32]); MerkleTree::gen_proof::<[u8; 32]>(&self.tree, array).expect("not found in tree") } @@ -68,38 +72,36 @@ impl MT256

{ #[cfg(test)] mod tests { use super::MT256; - use crate::elliptic::curves::traits::ECPoint; + use crate::elliptic::curves::{Curve, Point, PointZ}; use crate::test_for_all_curves; test_for_all_curves!(test_mt_functionality_four_leaves); - fn test_mt_functionality_four_leaves() { - let ge1: P = ECPoint::generator(); - let ge2: P = ECPoint::generator(); - let ge3: P = ge1.add_point(&ge2.get_element()); - let ge4: P = ge1.add_point(&ge3.get_element()); - let ge_vec = vec![ge1, ge2, ge3, ge4]; + fn test_mt_functionality_four_leaves() { + let ge1: PointZ = Point::generator().to_point_owned().into(); + let ge2: PointZ = ge1.clone(); + let ge3: PointZ = &ge1 + &ge2; + let ge4: PointZ = &ge1 + &ge3; + let ge_vec = vec![ge1.clone(), ge2, ge3, ge4]; let mt256 = MT256::create_tree(&ge_vec); - let ge1: P = ECPoint::generator(); let proof1 = mt256.gen_proof_for_ge(&ge1); let root = mt256.get_root(); - let valid_proof = MT256::

::validate_proof(&proof1, root).is_ok(); + let valid_proof = MT256::::validate_proof(&proof1, root).is_ok(); assert!(valid_proof); } test_for_all_curves!(test_mt_functionality_three_leaves); - fn test_mt_functionality_three_leaves() { - let ge1: P = ECPoint::generator(); - let ge2: P = ECPoint::generator(); - let ge3: P = ge1.add_point(&ge2.get_element()); + fn test_mt_functionality_three_leaves() { + let ge1: PointZ = Point::generator().to_point_owned().into(); + let ge2: PointZ = ge1.clone(); + let ge3: PointZ = &ge1 + &ge2; - let ge_vec = vec![ge1, ge2, ge3]; + let ge_vec = vec![ge1.clone(), ge2, ge3]; let mt256 = MT256::create_tree(&ge_vec); - let ge1: P = ECPoint::generator(); let proof1 = mt256.gen_proof_for_ge(&ge1); let root = mt256.get_root(); - assert!(MT256::

::validate_proof(&proof1, root).is_ok()); + assert!(MT256::::validate_proof(&proof1, root).is_ok()); } } diff --git a/src/cryptographic_primitives/hashing/traits.rs b/src/cryptographic_primitives/hashing/traits.rs index d2d3dd1f..e6864acb 100644 --- a/src/cryptographic_primitives/hashing/traits.rs +++ b/src/cryptographic_primitives/hashing/traits.rs @@ -5,13 +5,14 @@ License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE */ -use crate::elliptic::curves::traits::ECPoint; +use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; use crate::BigInt; pub trait Hash { fn create_hash(big_ints: &[&BigInt]) -> BigInt; fn create_hash_from_slice(byte_slice: &[u8]) -> BigInt; - fn create_hash_from_ge(ge_vec: &[&P]) -> P::Scalar; + fn create_hash_from_ge(ge_vec: &[&Point]) -> ScalarZ; + fn create_hash_from_ge_z(ge_vec: &[&PointZ]) -> ScalarZ; } pub trait KeyedHash { diff --git a/src/cryptographic_primitives/mod.rs b/src/cryptographic_primitives/mod.rs index cd3817e1..f099ecd6 100644 --- a/src/cryptographic_primitives/mod.rs +++ b/src/cryptographic_primitives/mod.rs @@ -6,7 +6,7 @@ */ // pub mod commitments; -// pub mod hashing; +pub mod hashing; // pub mod proofs; pub mod secret_sharing; // pub mod twoparty; From 94a6459c24ef18fcf8266adf2deb14c29c5b9f74 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 6 Jul 2021 10:29:58 +0300 Subject: [PATCH 21/93] Change curve_name method with associated constant --- src/elliptic/curves/secp256_k1.rs | 4 +--- src/elliptic/curves/traits.rs | 4 ++-- src/elliptic/curves/wrappers.rs | 24 ++++++++++++------------ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index c6043fc2..4073774d 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -131,9 +131,7 @@ impl Curve for Secp256k1 { type Point = GE; type Scalar = FE; - fn curve_name() -> &'static str { - "secp256k1" - } + const CURVE_NAME: &'static str = "secp256k1"; } #[derive(Clone, Debug)] diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index d1837a76..4fe15bc1 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -19,8 +19,8 @@ pub trait Curve { type Point: ECPoint; type Scalar: ECScalar; - /// Returns canonical name for this curve - fn curve_name() -> &'static str; + /// Canonical name for this curve + const CURVE_NAME: &'static str; } /// Scalar value modulus [curve order](Self::curve_order) diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index 29b0224b..a02cd505 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -1323,9 +1323,9 @@ impl PointFormat { impl TryFrom> for PointZ { type Error = ConvertParsedPointError; fn try_from(parsed: PointFormat) -> Result { - if parsed.curve != E::curve_name() { + if parsed.curve != E::CURVE_NAME { return Err(ConvertParsedPointError::MismatchedCurve { - expected: E::curve_name(), + expected: E::CURVE_NAME, got: parsed.curve, }); } @@ -1340,7 +1340,7 @@ impl TryFrom> for PointZ { impl From> for PointFormat { fn from(point: PointZ) -> Self { Self { - curve: E::curve_name().into(), + curve: E::CURVE_NAME.into(), point: point.coords(), _ph: PhantomData, } @@ -1350,9 +1350,9 @@ impl From> for PointFormat { impl TryFrom> for Point { type Error = ConvertParsedPointError; fn try_from(parsed: PointFormat) -> Result { - if parsed.curve != E::curve_name() { + if parsed.curve != E::CURVE_NAME { return Err(ConvertParsedPointError::MismatchedCurve { - expected: E::curve_name(), + expected: E::CURVE_NAME, got: parsed.curve, }); } @@ -1372,7 +1372,7 @@ impl TryFrom> for Point { impl From> for PointFormat { fn from(point: Point) -> Self { Self { - curve: E::curve_name().into(), + curve: E::CURVE_NAME.into(), point: Some(point.coords()), _ph: PhantomData, } @@ -1404,10 +1404,10 @@ impl TryFrom> for ScalarZ { type Error = ConvertParsedScalarError; fn try_from(parsed: ScalarFormat) -> Result { - if parsed.curve != E::curve_name() { + if parsed.curve != E::CURVE_NAME { return Err(ConvertParsedScalarError::MismatchedCurve { got: parsed.curve, - expected: E::curve_name(), + expected: E::CURVE_NAME, }); } @@ -1418,7 +1418,7 @@ impl TryFrom> for ScalarZ { impl From> for ScalarFormat { fn from(s: ScalarZ) -> Self { ScalarFormat { - curve: E::curve_name().into(), + curve: E::CURVE_NAME.into(), scalar: ScalarHex(s.into_raw()), } } @@ -1428,10 +1428,10 @@ impl TryFrom> for Scalar { type Error = ConvertParsedScalarError; fn try_from(parsed: ScalarFormat) -> Result { - if parsed.curve != E::curve_name() { + if parsed.curve != E::CURVE_NAME { return Err(ConvertParsedScalarError::MismatchedCurve { got: parsed.curve, - expected: E::curve_name(), + expected: E::CURVE_NAME, }); } @@ -1444,7 +1444,7 @@ impl TryFrom> for Scalar { impl From> for ScalarFormat { fn from(s: Scalar) -> Self { ScalarFormat { - curve: E::curve_name().into(), + curve: E::CURVE_NAME.into(), scalar: ScalarHex(s.into_raw()), } } From c50e75768092ebdb09c1278ecb591ea1ea076bd8 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 6 Jul 2021 11:05:22 +0300 Subject: [PATCH 22/93] Deref stylistic fix --- src/elliptic/curves/secp256_k1.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 4073774d..eba26940 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -16,7 +16,7 @@ // The Public Key codec: Point <> SecretKey // -use std::ops::{self, Deref}; +use std::ops; use std::ptr; use std::sync::atomic; @@ -197,7 +197,7 @@ impl ECScalar for Secp256k1Scalar { } fn to_bigint(&self) -> BigInt { - match self.fe.deref() { + match &*self.fe { Some(sk) => BigInt::from_bytes(&sk[..]), None => BigInt::zero(), } @@ -423,7 +423,7 @@ impl ECPoint for Secp256k1Point { }; } }; - let scalar = match scalar.fe.deref() { + let scalar = match &*scalar.fe { Some(s) => s, None => { // Scalar is zero => p * 0 = O From ce61396c7583e847a17b43ea1731306d280f5df8 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 6 Jul 2021 13:54:42 +0300 Subject: [PATCH 23/93] Optimise generator multiplication --- src/elliptic/curves/secp256_k1.rs | 15 +++++++++- src/elliptic/curves/traits.rs | 12 ++++++++ src/elliptic/curves/wrappers.rs | 49 ++++++++++++++++++++++++++----- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index eba26940..a89f756f 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -32,7 +32,7 @@ use crate::arithmetic::*; use super::traits::*; lazy_static::lazy_static! { - static ref CONTEXT: secp256k1::Secp256k1 = secp256k1::Secp256k1::verification_only(); + static ref CONTEXT: secp256k1::Secp256k1 = secp256k1::Secp256k1::new(); static ref CURVE_ORDER: BigInt = BigInt::from_bytes(&constants::CURVE_ORDER); @@ -448,6 +448,19 @@ impl ECPoint for Secp256k1Point { } } + fn generator_mul(scalar: &Self::Scalar) -> Self { + match &*scalar.fe { + Some(sk) => Secp256k1Point { + purpose: "generator_mul", + ge: Some(PK(PublicKey::from_secret_key(&CONTEXT, sk))), + }, + None => Secp256k1Point { + purpose: "generator_mul", + ge: None, + }, + } + } + fn add_point(&self, other: &Self) -> Secp256k1Point { let ge1 = match &self.ge { Some(ge) => ge, diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 4fe15bc1..e029cedf 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -158,6 +158,18 @@ pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug + 'static { /// Multiplies the point at scalar value fn scalar_mul(&self, scalar: &Self::Scalar) -> Self; + /// Multiplies curve generator at given scalar + /// + /// Basically, it's the same as `ECPoint::generator().scalar_mul(&s)`, but can be more efficient + /// because most curve libs have constant time high performance generator multiplication. + /// + /// ## Correctness + /// + /// Note that scalar is modulo [curve order](ECScalar::curve_order), so multiplying generator + /// at non-zero scalar **must** always produce non-zero point. + fn generator_mul(scalar: &Self::Scalar) -> Self { + Self::generator().scalar_mul(scalar) + } /// Adds two points fn add_point(&self, other: &Self) -> Self; /// Substrates `other` from `self` diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index a02cd505..a88de2c5 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -1111,19 +1111,19 @@ matrix! { pairs = { (_o<> Scalar, Point), (_o<> Scalar, PointZ), (_r<> Scalar, &Point), (_r<> Scalar, &PointZ), - (_r<'p> Scalar, PointRef<'p, E>), /*(_r<> Scalar, Generator),*/ + (_r<'p> Scalar, PointRef<'p, E>), (_o<> ScalarZ, Point), (_o<> ScalarZ, PointZ), (_r<> ScalarZ, &Point), (_r<> ScalarZ, &PointZ), - (_r<'p> ScalarZ, PointRef<'p, E>), (_r<> ScalarZ, Generator), + (_r<'p> ScalarZ, PointRef<'p, E>), (_o<> &Scalar, Point), (_o<> &Scalar, PointZ), (_r<> &Scalar, &Point), (_r<> &Scalar, &PointZ), - (_r<'p> &Scalar, PointRef<'p, E>), /*(_r<> &Scalar, Generator),*/ + (_r<'p> &Scalar, PointRef<'p, E>), (_o<> &ScalarZ, Point), (_o<> &ScalarZ, PointZ), (_r<> &ScalarZ, &Point), (_r<> &ScalarZ, &PointZ), - (_r<'p> &ScalarZ, PointRef<'p, E>), (_r<> &ScalarZ, Generator), + (_r<'p> &ScalarZ, PointRef<'p, E>), // --- and vice-versa --- @@ -1141,9 +1141,6 @@ matrix! { (r_<'p> PointRef<'p, E>, Scalar), (r_<'p> PointRef<'p, E>, ScalarZ), (r_<'p> PointRef<'p, E>, &Scalar), (r_<'p> PointRef<'p, E>, &ScalarZ), - - /*(r_<> Generator, Scalar),*/ (r_<> Generator, ScalarZ), - /*(r_<> Generator, &Scalar),*/ (r_<> Generator, &ScalarZ), } } @@ -1207,7 +1204,7 @@ matrix! { impl ops::Mul<&Scalar> for Generator { type Output = Point; fn mul(self, rhs: &Scalar) -> Self::Output { - Point::from_raw(self.as_raw().scalar_mul(&rhs.as_raw())) + Point::from_raw(E::Point::generator_mul(rhs.as_raw())) .expect("generator multiplied by non-zero scalar is always non-zero point") } } @@ -1233,6 +1230,34 @@ impl ops::Mul> for Scalar { } } +impl ops::Mul<&ScalarZ> for Generator { + type Output = PointZ; + fn mul(self, rhs: &ScalarZ) -> Self::Output { + PointZ::from_raw(E::Point::generator_mul(rhs.as_raw())) + } +} + +impl ops::Mul> for Generator { + type Output = PointZ; + fn mul(self, rhs: ScalarZ) -> Self::Output { + self.mul(&rhs) + } +} + +impl ops::Mul> for &ScalarZ { + type Output = PointZ; + fn mul(self, rhs: Generator) -> Self::Output { + rhs.mul(self) + } +} + +impl ops::Mul> for ScalarZ { + type Output = PointZ; + fn mul(self, rhs: Generator) -> Self::Output { + rhs.mul(self) + } +} + impl ops::Neg for Scalar { type Output = Scalar; @@ -1289,6 +1314,14 @@ impl<'p, E: Curve> ops::Neg for PointRef<'p, E> { } } +impl ops::Neg for Generator { + type Output = Point; + + fn neg(self) -> Self::Output { + Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") + } +} + impl ops::Neg for PointZ { type Output = PointZ; From dfd6ee9aaaeb443e2628dcfe7a9be94cfb574107 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 6 Jul 2021 14:09:08 +0300 Subject: [PATCH 24/93] Update docs --- src/elliptic/curves/wrappers.rs | 36 +++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index a88de2c5..ec7bd22c 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -349,10 +349,42 @@ impl TryFrom> for Point { /// Holds internally a static reference on curve generator. Can be used in arithmetic interchangeably /// as [`PointRef`](PointRef). /// +/// You can convert the generator into `Point` and `PointRef` using +/// [`to_point_owned`](Self::to_point_owned) and [`as_point_ref`](Self::as_point_ref) +/// methods respectively. +/// +/// ## Guarantees +/// /// Generator multiplied at non-zero scalar always produce non-zero point, thus output type of /// the multiplication is [`Point`](Point). This is the only difference compared to `Point` and -/// `PointRef`. Use [`to_point_owned`](Self::to_point_owned) and [`as_point_ref`](Self::as_point_ref) -/// methods to convert the generator into `Point` and `PointRef`. +/// `PointRef`. +/// +/// ```rust +/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; +/// let s = Scalar::::random(); // Non-zero scalar +/// let g = Point::::generator(); // Curve generator +/// let result: Point = s * g; // Generator multiplied at non-zero scalar is +/// // always a non-zero point +/// ``` +/// +/// ## Performance +/// +/// Generator multiplication is often more efficient than regular point multiplication, so avoid +/// converting generator into the `Point` as long as it's possible: +/// +/// ```rust +/// # use curv::elliptic::curves::{Point, Scalar, Secp256k1, Generator, PointZ}; +/// let s: Scalar = Scalar::random(); +/// // Generator multiplication: +/// let g: Generator = Point::generator(); +/// let p1: Point = g * &s; +/// // Point multiplication: +/// let g: Point = g.to_point_owned(); +/// let p2: PointZ = g * &s; +/// // Result will be the same, but generator multiplication is usually faster. +/// // Plus, generator multiplication produces `Point` instead of `PointZ` +/// assert_eq!(PointZ::from(p1), p2); +/// ``` pub struct Generator { _ph: PhantomData<&'static E::Point>, } From 483d70fe21943089f921a7bc1ff46864bcde0090 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 6 Jul 2021 19:49:59 +0300 Subject: [PATCH 25/93] Update commitments --- .../commitments/pedersen_commitment.rs | 21 ++++++++----------- src/cryptographic_primitives/mod.rs | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/cryptographic_primitives/commitments/pedersen_commitment.rs b/src/cryptographic_primitives/commitments/pedersen_commitment.rs index b48feb20..c44cb21e 100644 --- a/src/cryptographic_primitives/commitments/pedersen_commitment.rs +++ b/src/cryptographic_primitives/commitments/pedersen_commitment.rs @@ -11,33 +11,30 @@ use super::traits::Commitment; use super::SECURITY_BITS; use crate::arithmetic::traits::*; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; use crate::BigInt; /// compute c = mG + rH /// where m is the commited value, G is the group generator, /// H is a random point and r is a blinding value. /// -pub struct PedersenCommitment

(PhantomData

); +pub struct PedersenCommitment(PhantomData); -impl

Commitment

for PedersenCommitment

-where - P: ECPoint, -{ +impl Commitment> for PedersenCommitment { fn create_commitment_with_user_defined_randomness( message: &BigInt, blinding_factor: &BigInt, - ) -> P { - let g: P = ECPoint::generator(); - let h = P::base_point2(); - let message_scalar: P::Scalar = ECScalar::from(message); - let blinding_scalar: P::Scalar = ECScalar::from(blinding_factor); + ) -> PointZ { + let g = Point::generator(); + let h = Point::base_point2(); + let message_scalar: ScalarZ = ScalarZ::from(message); + let blinding_scalar: ScalarZ = ScalarZ::from(blinding_factor); let mg = g * message_scalar; let rh = h * blinding_scalar; mg + rh } - fn create_commitment(message: &BigInt) -> (P, BigInt) { + fn create_commitment(message: &BigInt) -> (PointZ, BigInt) { let blinding_factor = BigInt::sample(SECURITY_BITS); let com = PedersenCommitment::create_commitment_with_user_defined_randomness( message, diff --git a/src/cryptographic_primitives/mod.rs b/src/cryptographic_primitives/mod.rs index f099ecd6..0ef3a403 100644 --- a/src/cryptographic_primitives/mod.rs +++ b/src/cryptographic_primitives/mod.rs @@ -5,7 +5,7 @@ License MIT: */ -// pub mod commitments; +pub mod commitments; pub mod hashing; // pub mod proofs; pub mod secret_sharing; From e0b2da7e54d802fefeee52d022c41c9c871f9402 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 6 Jul 2021 20:18:24 +0300 Subject: [PATCH 26/93] Update low_degree_exponent_interpolation --- src/cryptographic_primitives/mod.rs | 2 +- .../low_degree_exponent_interpolation.rs | 111 ++++++++---------- src/cryptographic_primitives/proofs/mod.rs | 12 +- 3 files changed, 54 insertions(+), 71 deletions(-) diff --git a/src/cryptographic_primitives/mod.rs b/src/cryptographic_primitives/mod.rs index 0ef3a403..075f5b90 100644 --- a/src/cryptographic_primitives/mod.rs +++ b/src/cryptographic_primitives/mod.rs @@ -7,6 +7,6 @@ pub mod commitments; pub mod hashing; -// pub mod proofs; +pub mod proofs; pub mod secret_sharing; // pub mod twoparty; diff --git a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs index 09e03594..b347cae8 100644 --- a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs +++ b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs @@ -1,45 +1,34 @@ -use std::fmt; - -use derivative::Derivative; use thiserror::Error; use crate::cryptographic_primitives::hashing::traits::Hash; use crate::cryptographic_primitives::proofs::ProofError; use crate::cryptographic_primitives::secret_sharing::Polynomial; -use crate::elliptic::curves::traits::ECPoint; +use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; /// The prover private polynomial -#[derive(Derivative)] -#[derivative(Clone(bound = "P::Scalar: Clone"))] -#[derivative(Debug(bound = "P::Scalar: fmt::Debug"))] -pub struct LdeiWitness { - pub w: Polynomial

, +#[derive(Clone, Debug)] +pub struct LdeiWitness { + pub w: Polynomial, } /// Claims that there's polynomial `w(x)` of degree `deg(w) <= degree`, and /// `forall i. x[i] = g[i] * alpha[i]` (and the prover knows `w(x)`) -#[derive(Derivative)] -#[derivative(Clone(bound = "P: Clone, P::Scalar: Clone"))] -#[derivative(Debug(bound = "P: fmt::Debug, P::Scalar: fmt::Debug"))] -pub struct LdeiStatement { - pub alpha: Vec, - pub g: Vec

, - pub x: Vec

, +#[derive(Clone, Debug)] +pub struct LdeiStatement { + pub alpha: Vec>, + pub g: Vec>, + pub x: Vec>, pub d: u16, } -impl

LdeiStatement

-where - P: ECPoint + Clone, - P::Scalar: Clone + PartialEq, -{ +impl LdeiStatement { /// Takes [witness](LdeiWitness) (ie. secret polynomial `w(x)`), list of scalars `alpha`, /// list of generators `g`, number `d`. Produces LdeiStatement consisting of `alpha`, `g`, `d`, /// and list `x` such as `x_i = g_i * w(alpha_i)` pub fn new( - witness: &LdeiWitness

, - alpha: Vec, - g: Vec

, + witness: &LdeiWitness, + alpha: Vec>, + g: Vec>, d: u16, ) -> Result { if g.len() != alpha.len() { @@ -54,7 +43,7 @@ where Ok(Self { x: g.iter() .zip(&alpha) - .map(|(g, a)| g.clone() * witness.w.evaluate(a)) + .map(|(g, a)| g * witness.w.evaluate(a)) .collect(), alpha, g, @@ -63,20 +52,14 @@ where } } -#[derive(Derivative)] -#[derivative(Clone(bound = "P: Clone, P::Scalar: Clone"))] -#[derivative(Debug(bound = "P: fmt::Debug, P::Scalar: fmt::Debug"))] -pub struct LdeiProof { - pub a: Vec

, - pub e: P::Scalar, - pub z: Polynomial

, +#[derive(Clone, Debug)] +pub struct LdeiProof { + pub a: Vec>, + pub e: ScalarZ, + pub z: Polynomial, } -impl

LdeiProof

-where - P: ECPoint + Clone + PartialEq, - P::Scalar: Clone + PartialEq, -{ +impl LdeiProof { /// Constructs [LdeiStatement] and proves it correctness /// /// ## Protocol @@ -86,9 +69,9 @@ where /// `z(X) = u(X) − e · w(X)`. The proof is `(a_1,...,a_m,e,z)`. #[allow(clippy::many_single_char_names)] pub fn prove( - witness: &LdeiWitness

, - statement: &LdeiStatement

, - ) -> Result, InvalidLdeiStatement> + witness: &LdeiWitness, + statement: &LdeiStatement, + ) -> Result, InvalidLdeiStatement> where H: Hash, { @@ -102,26 +85,31 @@ where return Err(InvalidLdeiStatement::AlphaNotPairwiseDistinct); } - let x_expected: Vec

= statement + let x_expected: Vec> = statement .g .iter() .zip(&statement.alpha) - .map(|(g, a)| g.clone() * witness.w.evaluate(a)) + .map(|(g, a)| g * witness.w.evaluate(a)) .collect(); if statement.x != x_expected { return Err(InvalidLdeiStatement::ListOfXDoesntMatchExpectedValue); } - let u = Polynomial::

::sample(statement.d); - let a: Vec

= statement + let u = Polynomial::::sample(statement.d); + let a: Vec> = statement .g .iter() .zip(&statement.alpha) - .map(|(g, a)| g.clone() * u.evaluate(a)) + .map(|(g, a)| g * u.evaluate(a)) .collect(); - let hash_input: Vec<&P> = statement.g.iter().chain(&statement.x).chain(&a).collect(); - let e = H::create_hash_from_ge::

(hash_input.as_slice()); + let g: Vec> = statement + .g + .iter() + .map(|g| PointZ::from(g.clone())) + .collect(); + let hash_input: Vec<&PointZ> = g.iter().chain(&statement.x).chain(&a).collect(); + let e = H::create_hash_from_ge_z::(hash_input.as_slice()); let z = &u - &(&witness.w * &e); @@ -135,17 +123,17 @@ where /// The verifier checks that `e = H(g1,...,gm,x1,...,xm,a1,...,am)`, that /// `deg(z) ≤ d`, and that `a_i = g_i^z(αlpha_i) * x_i^e` for all i, and accepts if all of this is /// true, otherwise rejects. - pub fn verify(&self, statement: &LdeiStatement

) -> Result<(), ProofError> + pub fn verify(&self, statement: &LdeiStatement) -> Result<(), ProofError> where H: Hash, { - let hash_input: Vec<&P> = statement + let g: Vec> = statement .g .iter() - .chain(&statement.x) - .chain(&self.a) + .map(|g| PointZ::from(g.clone())) .collect(); - let e = H::create_hash_from_ge::

(hash_input.as_slice()); + let hash_input: Vec<&PointZ> = g.iter().chain(&statement.x).chain(&self.a).collect(); + let e = H::create_hash_from_ge_z::(hash_input.as_slice()); if e != self.e { return Err(ProofError); } @@ -158,7 +146,7 @@ where .iter() .zip(&statement.alpha) .zip(&statement.x) - .map(|((g, a), x)| g.clone() * self.z.evaluate(&a) + x.clone() * e.clone()) + .map(|((g, a), x)| g * self.z.evaluate(&a) + x * &e) .collect(); if self.a == expected_a { @@ -197,26 +185,21 @@ fn ensure_list_is_pairwise_distinct(list: &[S]) -> bool { mod tests { use std::iter; - use crate::arithmetic::BigInt; use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; - use crate::elliptic::curves::traits::ECScalar; + use crate::elliptic::curves::{Curve, Scalar}; use crate::test_for_all_curves; use super::*; test_for_all_curves!(correctly_proofs); - fn correctly_proofs

() - where - P: ECPoint + Clone + PartialEq, - P::Scalar: ECScalar + Clone + PartialEq, - { + fn correctly_proofs() { let d = 5; - let poly = Polynomial::

::sample_exact(5); + let poly = Polynomial::::sample_exact(5); let witness = LdeiWitness { w: poly }; - let alpha: Vec = (1..=10).map(|i| ECScalar::from(&BigInt::from(i))).collect(); - let g: Vec

= iter::repeat_with(ECScalar::new_random) - .map(|x| P::generator() * x) + let alpha: Vec> = (1..=10).map(|i| ScalarZ::from(i)).collect(); + let g: Vec> = iter::repeat_with(Scalar::random) + .map(|x| Point::generator() * x) .take(10) .collect(); diff --git a/src/cryptographic_primitives/proofs/mod.rs b/src/cryptographic_primitives/proofs/mod.rs index a3a8b33c..3dd43811 100644 --- a/src/cryptographic_primitives/proofs/mod.rs +++ b/src/cryptographic_primitives/proofs/mod.rs @@ -9,12 +9,12 @@ use std::error::Error; use std::fmt; pub mod low_degree_exponent_interpolation; -pub mod sigma_correct_homomorphic_elgamal_enc; -pub mod sigma_correct_homomorphic_elgamal_encryption_of_dlog; -pub mod sigma_dlog; -pub mod sigma_ec_ddh; -pub mod sigma_valid_pedersen; -pub mod sigma_valid_pedersen_blind; +// pub mod sigma_correct_homomorphic_elgamal_enc; +// pub mod sigma_correct_homomorphic_elgamal_encryption_of_dlog; +// pub mod sigma_dlog; +// pub mod sigma_ec_ddh; +// pub mod sigma_valid_pedersen; +// pub mod sigma_valid_pedersen_blind; #[derive(Debug, Clone, Copy)] pub struct ProofError; From be6c8d929e42b9b7ff15aa7a1d89c6960aca2347 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 6 Jul 2021 22:18:25 +0300 Subject: [PATCH 27/93] Update sigma_correct_homomorphic_elgamal_enc --- src/cryptographic_primitives/proofs/mod.rs | 2 +- .../sigma_correct_homomorphic_elgamal_enc.rs | 196 +++++++++--------- src/elliptic/curves/wrappers.rs | 26 ++- 3 files changed, 117 insertions(+), 107 deletions(-) diff --git a/src/cryptographic_primitives/proofs/mod.rs b/src/cryptographic_primitives/proofs/mod.rs index 3dd43811..3520de4b 100644 --- a/src/cryptographic_primitives/proofs/mod.rs +++ b/src/cryptographic_primitives/proofs/mod.rs @@ -9,7 +9,7 @@ use std::error::Error; use std::fmt; pub mod low_degree_exponent_interpolation; -// pub mod sigma_correct_homomorphic_elgamal_enc; +pub mod sigma_correct_homomorphic_elgamal_enc; // pub mod sigma_correct_homomorphic_elgamal_encryption_of_dlog; // pub mod sigma_dlog; // pub mod sigma_ec_ddh; diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs index 7d2d095f..5fcf1ac6 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs @@ -7,12 +7,11 @@ */ use serde::{Deserialize, Serialize}; -use zeroize::Zeroize; use super::ProofError; use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; use crate::cryptographic_primitives::hashing::traits::Hash; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; /// This is a proof of knowledge that a pair of group elements {D, E} /// form a valid homomorphic ElGamal encryption (”in the exponent”) using public key Y . @@ -21,67 +20,71 @@ use crate::elliptic::curves::traits::*; /// The relation R outputs 1 if D = xH+rY , E = rG (for the case of G=H this is ElGamal) /// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct HomoELGamalProof { - pub T: P, - pub A3: P, - pub z1: P::Scalar, - pub z2: P::Scalar, +pub struct HomoELGamalProof { + pub T: PointZ, + pub A3: PointZ, + pub z1: ScalarZ, + pub z2: ScalarZ, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct HomoElGamalWitness { - pub r: S, - pub x: S, +pub struct HomoElGamalWitness { + pub r: ScalarZ, + pub x: ScalarZ, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct HomoElGamalStatement

{ - pub G: P, - pub H: P, - pub Y: P, - pub D: P, - pub E: P, +pub struct HomoElGamalStatement { + pub G: Point, + pub H: Point, + pub Y: Point, + pub D: PointZ, + pub E: PointZ, } -impl

HomoELGamalProof

-where - P: ECPoint + Clone + Zeroize, - P::Scalar: PartialEq + Clone + Zeroize, -{ +impl HomoELGamalProof { pub fn prove( - w: &HomoElGamalWitness, - delta: &HomoElGamalStatement

, - ) -> HomoELGamalProof

{ - let mut s1: P::Scalar = ECScalar::new_random(); - let mut s2: P::Scalar = ECScalar::new_random(); - let mut A1 = delta.H.clone() * s1.clone(); - let mut A2 = delta.Y.clone() * s2.clone(); - let A3 = delta.G.clone() * s2.clone(); - let T = A1.clone() + A2.clone(); - let e = HSha256::create_hash_from_ge(&[ - &T, &A3, &delta.G, &delta.H, &delta.Y, &delta.D, &delta.E, + w: &HomoElGamalWitness, + delta: &HomoElGamalStatement, + ) -> HomoELGamalProof { + let s1: Scalar = Scalar::random(); + let s2: Scalar = Scalar::random(); + let A1 = &delta.H * &s1; + let A2 = &delta.Y * &s2; + let A3 = &delta.G * &s2; + let T = A1 + A2; + let e = HSha256::create_hash_from_ge_z(&[ + &T, + &A3, + &PointZ::from(delta.G.clone()), + &PointZ::from(delta.H.clone()), + &PointZ::from(delta.Y.clone()), + &PointZ::from(delta.D.clone()), + &PointZ::from(delta.E.clone()), ]); // dealing with zero field element - let z1 = if w.x != P::Scalar::zero() { - s1.clone() + w.x.clone() * e.clone() + let z1 = if !w.x.is_zero() { + &s1 + &w.x * &e } else { - s1.clone() + ScalarZ::from(s1) }; - let z2 = s2.clone() + w.r.clone() * e; - s1.zeroize(); - s2.zeroize(); - A1.zeroize(); - A2.zeroize(); + let z2 = s2 + &w.r * e; HomoELGamalProof { T, A3, z1, z2 } } - pub fn verify(&self, delta: &HomoElGamalStatement

) -> Result<(), ProofError> { - let e = HSha256::create_hash_from_ge(&[ - &self.T, &self.A3, &delta.G, &delta.H, &delta.Y, &delta.D, &delta.E, + pub fn verify(&self, delta: &HomoElGamalStatement) -> Result<(), ProofError> { + let e = HSha256::create_hash_from_ge_z(&[ + &self.T, + &self.A3, + &PointZ::from(delta.G.clone()), + &PointZ::from(delta.H.clone()), + &PointZ::from(delta.Y.clone()), + &PointZ::from(delta.D.clone()), + &PointZ::from(delta.E.clone()), ]); - let z1H_plus_z2Y = delta.H.clone() * self.z1.clone() + delta.Y.clone() * self.z2.clone(); - let T_plus_eD = self.T.clone() + delta.D.clone() * e.clone(); - let z2G = delta.G.clone() * self.z2.clone(); - let A3_plus_eE = self.A3.clone() + delta.E.clone() * e; + let z1H_plus_z2Y = &delta.H * &self.z1 + &delta.Y * &self.z2; + let T_plus_eD = &self.T + &delta.D * &e; + let z2G = &delta.G * &self.z2; + let A3_plus_eE = &self.A3 + &delta.E * &e; if z1H_plus_z2Y == T_plus_eD && z2G == A3_plus_eE { Ok(()) } else { @@ -96,45 +99,43 @@ mod tests { use crate::test_for_all_curves; test_for_all_curves!(test_correct_general_homo_elgamal); - fn test_correct_general_homo_elgamal

() - where - P: ECPoint + Clone + Zeroize, - P::Scalar: PartialEq + Clone + Zeroize, - { - let witness = HomoElGamalWitness:: { - r: ECScalar::new_random(), - x: ECScalar::new_random(), + fn test_correct_general_homo_elgamal() { + let witness = HomoElGamalWitness:: { + r: ScalarZ::random(), + x: ScalarZ::random(), + }; + let G = Point::::generator(); + let h = Scalar::random(); + let H = G * h; + let y = Scalar::random(); + let Y = G * y; + let D = &H * &witness.x + &Y * &witness.r; + let E = G * &witness.r; + let delta = HomoElGamalStatement { + G: G.to_point_owned(), + H, + Y, + D, + E, }; - let G: P = ECPoint::generator(); - let h: P::Scalar = ECScalar::new_random(); - let H = G.clone() * h; - let y: P::Scalar = ECScalar::new_random(); - let Y = G.clone() * y; - let D = H.clone() * witness.x.clone() + Y.clone() * witness.r.clone(); - let E = G.clone() * witness.r.clone(); - let delta = HomoElGamalStatement { G, H, Y, D, E }; let proof = HomoELGamalProof::prove(&witness, &delta); assert!(proof.verify(&delta).is_ok()); } test_for_all_curves!(test_correct_homo_elgamal); - fn test_correct_homo_elgamal() - where - P: ECPoint + Clone + Zeroize, - P::Scalar: PartialEq + Clone + Zeroize, - { + fn test_correct_homo_elgamal() { let witness = HomoElGamalWitness { - r: P::Scalar::new_random(), - x: P::Scalar::new_random(), + r: ScalarZ::random(), + x: ScalarZ::random(), }; - let G: P = ECPoint::generator(); - let y: P::Scalar = ECScalar::new_random(); - let Y = G.clone() * y; - let D = G.clone() * witness.x.clone() + Y.clone() * witness.r.clone(); - let E = G.clone() * witness.r.clone(); + let G = Point::::generator(); + let y = Scalar::random(); + let Y = G * y; + let D = G * &witness.x + &Y * &witness.r; + let E = G * &witness.r; let delta = HomoElGamalStatement { - G: G.clone(), - H: G, + G: G.to_point_owned(), + H: G.to_point_owned(), Y, D, E, @@ -143,29 +144,28 @@ mod tests { assert!(proof.verify(&delta).is_ok()); } - test_for_all_curves!( - #[should_panic] - test_wrong_homo_elgamal - ); - fn test_wrong_homo_elgamal() - where - P: ECPoint + Clone + Zeroize, - P::Scalar: PartialEq + Clone + Zeroize, - { + test_for_all_curves!(test_wrong_homo_elgamal); + fn test_wrong_homo_elgamal() { // test for E = (r+1)G - let witness = HomoElGamalWitness:: { - r: ECScalar::new_random(), - x: ECScalar::new_random(), + let witness = HomoElGamalWitness:: { + r: ScalarZ::random(), + x: ScalarZ::random(), + }; + let G = Point::::generator(); + let h = Scalar::random(); + let H = G * h; + let y = Scalar::random(); + let Y = G * y; + let D = &H * &witness.x + &Y * &witness.r; + let E = G * &witness.r + G; + let delta = HomoElGamalStatement { + G: G.to_point_owned(), + H, + Y, + D, + E, }; - let G: P = ECPoint::generator(); - let h: P::Scalar = ECScalar::new_random(); - let H = G.clone() * h; - let y: P::Scalar = ECScalar::new_random(); - let Y = G.clone() * y; - let D = H.clone() * witness.x.clone() + Y.clone() * witness.r.clone(); - let E = G.clone() * witness.r.clone() + G.clone(); - let delta = HomoElGamalStatement { G, H, Y, D, E }; let proof = HomoELGamalProof::prove(&witness, &delta); - assert!(proof.verify(&delta).is_ok()); + assert!(!proof.verify(&delta).is_ok()); } } diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index ec7bd22c..c5b0ecb5 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -40,7 +40,9 @@ use crate::arithmetic::{BigInt, Converter}; /// ``` #[derive(Serialize, Deserialize)] #[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] -pub struct PointZ(E::Point); +pub struct PointZ { + raw_point: E::Point, +} impl PointZ { /// Checks if `self` is not zero and converts it into [`Point`](Point). Returns `None` if @@ -110,34 +112,36 @@ impl PointZ { self.as_raw().serialize(compressed) } - fn from_raw(point: E::Point) -> Self { - Self(point) + fn from_raw(raw_point: E::Point) -> Self { + Self { raw_point } } fn as_raw(&self) -> &E::Point { - &self.0 + &self.raw_point } fn into_raw(self) -> E::Point { - self.0 + self.raw_point } } impl PartialEq for PointZ { fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) + self.raw_point.eq(&other.raw_point) } } impl Clone for PointZ { fn clone(&self) -> Self { - PointZ(self.0.clone()) + PointZ { + raw_point: self.as_raw().clone(), + } } } impl fmt::Debug for PointZ { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) + self.raw_point.fmt(f) } } @@ -324,6 +328,12 @@ impl Point { } } +impl PartialEq for Point { + fn eq(&self, other: &Self) -> bool { + self.as_raw().eq(&other.as_raw()) + } +} + impl Clone for Point { fn clone(&self) -> Self { // Safety: `self` is guaranteed to be non-zero From 4ecc5289e60e0eb887cc4a15122e11c77b191815 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 7 Jul 2021 15:13:30 +0300 Subject: [PATCH 28/93] Update sigma_correct_homomorphic_elgamal_encryption_of_dlog --- src/cryptographic_primitives/proofs/mod.rs | 2 +- ..._homomorphic_elgamal_encryption_of_dlog.rs | 168 +++++++++--------- 2 files changed, 88 insertions(+), 82 deletions(-) diff --git a/src/cryptographic_primitives/proofs/mod.rs b/src/cryptographic_primitives/proofs/mod.rs index 3520de4b..0742d47e 100644 --- a/src/cryptographic_primitives/proofs/mod.rs +++ b/src/cryptographic_primitives/proofs/mod.rs @@ -10,7 +10,7 @@ use std::fmt; pub mod low_degree_exponent_interpolation; pub mod sigma_correct_homomorphic_elgamal_enc; -// pub mod sigma_correct_homomorphic_elgamal_encryption_of_dlog; +pub mod sigma_correct_homomorphic_elgamal_encryption_of_dlog; // pub mod sigma_dlog; // pub mod sigma_ec_ddh; // pub mod sigma_valid_pedersen; diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs index d75a02a4..33420dfd 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs @@ -7,12 +7,11 @@ */ use serde::{Deserialize, Serialize}; -use zeroize::Zeroize; use super::ProofError; use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; use crate::cryptographic_primitives::hashing::traits::Hash; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; /// This is a proof of knowledge that a pair of group elements {D, E} /// form a valid homomorphic ElGamal encryption (”in the exponent”) using public key Y . @@ -21,62 +20,69 @@ use crate::elliptic::curves::traits::*; /// The relation R outputs 1 if D = xG+rY , E = rG, Q = xG /// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct HomoELGamalDlogProof { - pub A1: P, - pub A2: P, - pub A3: P, - pub z1: P::Scalar, - pub z2: P::Scalar, +pub struct HomoELGamalDlogProof { + pub A1: PointZ, + pub A2: PointZ, + pub A3: PointZ, + pub z1: ScalarZ, + pub z2: ScalarZ, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct HomoElGamalDlogWitness { - pub r: S, - pub x: S, +pub struct HomoElGamalDlogWitness { + pub r: Scalar, + pub x: Scalar, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct HomoElGamalDlogStatement { - pub G: P, - pub Y: P, - pub Q: P, - pub D: P, - pub E: P, +pub struct HomoElGamalDlogStatement { + pub G: Point, + pub Y: Point, + pub Q: Point, + pub D: PointZ, + pub E: Point, } -impl

HomoELGamalDlogProof

-where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, -{ +impl HomoELGamalDlogProof { pub fn prove( - w: &HomoElGamalDlogWitness, - delta: &HomoElGamalDlogStatement

, - ) -> HomoELGamalDlogProof

{ - let mut s1: P::Scalar = ECScalar::new_random(); - let mut s2: P::Scalar = ECScalar::new_random(); - let A1 = delta.G.clone() * s1.clone(); - let A2 = delta.Y.clone() * s2.clone(); - let A3 = delta.G.clone() * s2.clone(); - let e = - HSha256::create_hash_from_ge(&[&A1, &A2, &A3, &delta.G, &delta.Y, &delta.D, &delta.E]); - let z1 = s1.clone() + e.clone() * w.x.clone(); - let z2 = s2.clone() + e * w.r.clone(); - s1.zeroize(); - s2.zeroize(); + w: &HomoElGamalDlogWitness, + delta: &HomoElGamalDlogStatement, + ) -> HomoELGamalDlogProof { + let s1 = Scalar::::random(); + let s2 = Scalar::::random(); + let A1 = &delta.G * &s1; + let A2 = &delta.Y * &s2; + let A3 = &delta.G * &s2; + let e = HSha256::create_hash_from_ge_z(&[ + &A1, + &A2, + &A3, + &PointZ::from(delta.G.clone()), + &PointZ::from(delta.Y.clone()), + &delta.D, + &PointZ::from(delta.E.clone()), + ]); + let z1 = &s1 + &e * &w.x; + let z2 = &s2 + e * &w.r; HomoELGamalDlogProof { A1, A2, A3, z1, z2 } } - pub fn verify(&self, delta: &HomoElGamalDlogStatement

) -> Result<(), ProofError> { - let e = HSha256::create_hash_from_ge(&[ - &self.A1, &self.A2, &self.A3, &delta.G, &delta.Y, &delta.D, &delta.E, + pub fn verify(&self, delta: &HomoElGamalDlogStatement) -> Result<(), ProofError> { + let e = HSha256::create_hash_from_ge_z(&[ + &self.A1, + &self.A2, + &self.A3, + &PointZ::from(delta.G.clone()), + &PointZ::from(delta.Y.clone()), + &delta.D, + &PointZ::from(delta.E.clone()), ]); - let z1G = delta.G.clone() * self.z1.clone(); - let z2Y = delta.Y.clone() * self.z2.clone(); - let z2G = delta.G.clone() * self.z2.clone(); - let A1_plus_eQ = self.A1.clone() + delta.Q.clone() * e.clone(); - let A3_plus_eE = self.A3.clone() + delta.E.clone() * e.clone(); - let D_minus_Q = delta.D.sub_point(&delta.Q.get_element()); + let z1G = &delta.G * &self.z1; + let z2Y = &delta.Y * &self.z2; + let z2G = &delta.G * &self.z2; + let A1_plus_eQ = &self.A1 + &delta.Q * &e; + let A3_plus_eE = &self.A3 + &delta.E * &e; + let D_minus_Q = &delta.D - &delta.Q; let A2_plus_eDmQ = self.A2.clone() + D_minus_Q * e; if z1G == A1_plus_eQ && z2G == A3_plus_eE && z2Y == A2_plus_eDmQ { Ok(()) @@ -88,53 +94,53 @@ where #[cfg(test)] mod tests { - use crate::cryptographic_primitives::proofs::sigma_correct_homomorphic_elgamal_encryption_of_dlog::*; use crate::test_for_all_curves; + use super::*; + test_for_all_curves!(test_correct_homo_elgamal); - fn test_correct_homo_elgamal

() - where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, - { - let witness = HomoElGamalDlogWitness:: { - r: ECScalar::new_random(), - x: ECScalar::new_random(), + fn test_correct_homo_elgamal() { + let witness = HomoElGamalDlogWitness:: { + r: Scalar::random(), + x: Scalar::random(), + }; + let G = Point::::generator(); + let Y = G * Scalar::random(); + let D = G * &witness.x + &Y * &witness.r; + let E = G * &witness.r; + let Q = G * &witness.x; + let delta = HomoElGamalDlogStatement { + G: G.to_point_owned(), + Y, + Q, + D, + E, }; - let G: P = ECPoint::generator(); - let y: P::Scalar = ECScalar::new_random(); - let Y = G.clone() * y; - let D = G.clone() * witness.x.clone() + Y.clone() * witness.r.clone(); - let E = G.clone() * witness.r.clone(); - let Q = G.clone() * witness.x.clone(); - let delta = HomoElGamalDlogStatement { G, Y, Q, D, E }; let proof = HomoELGamalDlogProof::prove(&witness, &delta); assert!(proof.verify(&delta).is_ok()); } // TODO: add more fail scenarios - test_for_all_curves!( - #[should_panic] - test_wrong_homo_elgamal - ); - fn test_wrong_homo_elgamal

() - where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, - { + test_for_all_curves!(test_wrong_homo_elgamal); + fn test_wrong_homo_elgamal() { // test for Q = (x+1)G - let witness = HomoElGamalDlogWitness:: { - r: ECScalar::new_random(), - x: ECScalar::new_random(), + let witness = HomoElGamalDlogWitness:: { + r: Scalar::random(), + x: Scalar::random(), + }; + let G = Point::::generator(); + let Y = G * Scalar::random(); + let D = G * &witness.x + &Y * &witness.r; + let E = (G * &witness.r + G).ensure_nonzero().unwrap(); + let Q = (G * &witness.x + G).ensure_nonzero().unwrap(); + let delta = HomoElGamalDlogStatement { + G: G.to_point_owned(), + Y, + Q, + D, + E, }; - let G: P = ECPoint::generator(); - let y: P::Scalar = ECScalar::new_random(); - let Y = G.clone() * y; - let D = G.clone() * witness.x.clone() + Y.clone() * witness.r.clone(); - let E = G.clone() * witness.r.clone() + G.clone(); - let Q = G.clone() * witness.x.clone() + G.clone(); - let delta = HomoElGamalDlogStatement { G, Y, Q, D, E }; let proof = HomoELGamalDlogProof::prove(&witness, &delta); - assert!(proof.verify(&delta).is_ok()); + assert!(!proof.verify(&delta).is_ok()); } } From 0c91c918e958b31a361724b1b1f4ceaf9d3c04b0 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 7 Jul 2021 19:08:34 +0300 Subject: [PATCH 29/93] Wrappers: rename methods, implement PartialEq --- .../hashing/blake2b512.rs | 4 +- .../hashing/hash_sha256.rs | 4 +- .../hashing/hash_sha512.rs | 4 +- .../hashing/merkle_tree.rs | 4 +- .../sigma_correct_homomorphic_elgamal_enc.rs | 8 +- ..._homomorphic_elgamal_encryption_of_dlog.rs | 4 +- src/elliptic/curves/wrappers.rs | 88 ++++++++++++++++--- 7 files changed, 88 insertions(+), 28 deletions(-) diff --git a/src/cryptographic_primitives/hashing/blake2b512.rs b/src/cryptographic_primitives/hashing/blake2b512.rs index 6092857c..aa2d888c 100644 --- a/src/cryptographic_primitives/hashing/blake2b512.rs +++ b/src/cryptographic_primitives/hashing/blake2b512.rs @@ -66,8 +66,8 @@ mod tests { crate::test_for_all_curves!(create_hash_from_ge_test); fn create_hash_from_ge_test() { - let base_point2 = Point::base_point2().to_point_owned(); - let generator = Point::generator().to_point_owned(); + let base_point2 = Point::base_point2().to_point(); + let generator = Point::generator().to_point(); let result1 = Blake::create_hash_from_ge::(&[&base_point2, &generator], b"Zcash_RedJubjubH"); assert!(result1.to_bigint().bit_length() > 240); diff --git a/src/cryptographic_primitives/hashing/hash_sha256.rs b/src/cryptographic_primitives/hashing/hash_sha256.rs index 89574411..f01757cb 100644 --- a/src/cryptographic_primitives/hashing/hash_sha256.rs +++ b/src/cryptographic_primitives/hashing/hash_sha256.rs @@ -126,8 +126,8 @@ mod tests { crate::test_for_all_curves!(create_sha256_from_ge_test); fn create_sha256_from_ge_test() { - let generator = Point::generator().to_point_owned(); - let base_point2 = Point::base_point2().to_point_owned(); + let generator = Point::generator().to_point(); + let base_point2 = Point::base_point2().to_point(); let result1 = HSha256::create_hash_from_ge::(&[&base_point2, &generator]); assert!(result1.to_bigint().bit_length() > 240); let result2 = HSha256::create_hash_from_ge(&[&generator, &base_point2]); diff --git a/src/cryptographic_primitives/hashing/hash_sha512.rs b/src/cryptographic_primitives/hashing/hash_sha512.rs index d39fcf07..70530ef2 100644 --- a/src/cryptographic_primitives/hashing/hash_sha512.rs +++ b/src/cryptographic_primitives/hashing/hash_sha512.rs @@ -114,8 +114,8 @@ mod tests { crate::test_for_all_curves!(create_sha512_from_ge_test); fn create_sha512_from_ge_test() { - let generator = Point::generator().to_point_owned(); - let base_point2 = Point::base_point2().to_point_owned(); + let generator = Point::generator().to_point(); + let base_point2 = Point::base_point2().to_point(); let result1 = HSha512::create_hash_from_ge::(&[&base_point2, &generator]); assert!(result1.to_bigint().bit_length() > 240); let result2 = HSha512::create_hash_from_ge(&[&generator, &base_point2]); diff --git a/src/cryptographic_primitives/hashing/merkle_tree.rs b/src/cryptographic_primitives/hashing/merkle_tree.rs index f8cd940e..1e00ee72 100644 --- a/src/cryptographic_primitives/hashing/merkle_tree.rs +++ b/src/cryptographic_primitives/hashing/merkle_tree.rs @@ -79,7 +79,7 @@ mod tests { test_for_all_curves!(test_mt_functionality_four_leaves); fn test_mt_functionality_four_leaves() { - let ge1: PointZ = Point::generator().to_point_owned().into(); + let ge1: PointZ = Point::generator().to_point().into(); let ge2: PointZ = ge1.clone(); let ge3: PointZ = &ge1 + &ge2; let ge4: PointZ = &ge1 + &ge3; @@ -94,7 +94,7 @@ mod tests { test_for_all_curves!(test_mt_functionality_three_leaves); fn test_mt_functionality_three_leaves() { - let ge1: PointZ = Point::generator().to_point_owned().into(); + let ge1: PointZ = Point::generator().to_point().into(); let ge2: PointZ = ge1.clone(); let ge3: PointZ = &ge1 + &ge2; diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs index 5fcf1ac6..55a2e888 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs @@ -112,7 +112,7 @@ mod tests { let D = &H * &witness.x + &Y * &witness.r; let E = G * &witness.r; let delta = HomoElGamalStatement { - G: G.to_point_owned(), + G: G.to_point(), H, Y, D, @@ -134,8 +134,8 @@ mod tests { let D = G * &witness.x + &Y * &witness.r; let E = G * &witness.r; let delta = HomoElGamalStatement { - G: G.to_point_owned(), - H: G.to_point_owned(), + G: G.to_point(), + H: G.to_point(), Y, D, E, @@ -159,7 +159,7 @@ mod tests { let D = &H * &witness.x + &Y * &witness.r; let E = G * &witness.r + G; let delta = HomoElGamalStatement { - G: G.to_point_owned(), + G: G.to_point(), H, Y, D, diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs index 33420dfd..977b84a9 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs @@ -110,7 +110,7 @@ mod tests { let E = G * &witness.r; let Q = G * &witness.x; let delta = HomoElGamalDlogStatement { - G: G.to_point_owned(), + G: G.to_point(), Y, Q, D, @@ -134,7 +134,7 @@ mod tests { let E = (G * &witness.r + G).ensure_nonzero().unwrap(); let Q = (G * &witness.x + G).ensure_nonzero().unwrap(); let delta = HomoElGamalDlogStatement { - G: G.to_point_owned(), + G: G.to_point(), Y, Q, D, diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index c5b0ecb5..e3a0aae3 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -131,6 +131,24 @@ impl PartialEq for PointZ { } } +impl PartialEq> for PointZ { + fn eq(&self, other: &Point) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl<'p, E: Curve> PartialEq> for PointZ { + fn eq(&self, other: &PointRef<'p, E>) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl PartialEq> for PointZ { + fn eq(&self, other: &Generator) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + impl Clone for PointZ { fn clone(&self) -> Self { PointZ { @@ -260,50 +278,50 @@ impl Point { /// /// Method never fails as Point is guaranteed to have coordinates pub fn coords(&self) -> PointCoords { - self.as_point_ref().coords() + self.as_point().coords() } /// Returns `x` coordinate of point /// /// Method never fails as Point is guaranteed to have coordinates pub fn x_coord(&self) -> BigInt { - self.as_point_ref().x_coord() + self.as_point().x_coord() } /// Returns `y` coordinate of point /// /// Method never fails as Point is guaranteed to have coordinates pub fn y_coord(&self) -> BigInt { - self.as_point_ref().y_coord() + self.as_point().y_coord() } /// Adds two points, returns the result, or `None` if resulting point is zero pub fn add_checked(&self, point: PointRef) -> Result { - self.as_point_ref().add_checked(point) + self.as_point().add_checked(point) } /// Substrates two points, returns the result, or `None` if resulting point is zero pub fn sub_checked(&self, point: PointRef) -> Result { - self.as_point_ref().sub_checked(point) + self.as_point().sub_checked(point) } /// Multiplies a point at scalar, returns the result, or `None` if resulting point is zero pub fn mul_checked_z(&self, scalar: &ScalarZ) -> Result { - self.as_point_ref().mul_checked_z(scalar) + self.as_point().mul_checked_z(scalar) } /// Multiplies a point at nonzero scalar, returns the result, or `None` if resulting point is zero pub fn mul_checked(&self, scalar: &Scalar) -> Result { - self.as_point_ref().mul_checked(scalar) + self.as_point().mul_checked(scalar) } /// Serializes point into (un)compressed form pub fn to_bytes(&self, compressed: bool) -> Vec { - self.as_point_ref().to_bytes(compressed) + self.as_point().to_bytes(compressed) } /// Creates [PointRef] that holds a reference on `self` - pub fn as_point_ref(&self) -> PointRef { + pub fn as_point(&self) -> PointRef { PointRef::from(self) } @@ -334,9 +352,27 @@ impl PartialEq for Point { } } +impl PartialEq> for Point { + fn eq(&self, other: &PointZ) -> bool { + self.as_raw().eq(&other.as_raw()) + } +} + +impl<'p, E: Curve> PartialEq> for Point { + fn eq(&self, other: &PointRef<'p, E>) -> bool { + self.as_raw().eq(&other.as_raw()) + } +} + +impl PartialEq> for Point { + fn eq(&self, other: &Generator) -> bool { + self.as_raw().eq(&other.as_raw()) + } +} + impl Clone for Point { fn clone(&self) -> Self { - // Safety: `self` is guaranteed to be non-zero + // Safety: `self` is guaranteed to be non-zero unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } } } @@ -389,7 +425,7 @@ impl TryFrom> for Point { /// let g: Generator = Point::generator(); /// let p1: Point = g * &s; /// // Point multiplication: -/// let g: Point = g.to_point_owned(); +/// let g: Point = g.to_point(); /// let p2: PointZ = g * &s; /// // Result will be the same, but generator multiplication is usually faster. /// // Plus, generator multiplication produces `Point` instead of `PointZ` @@ -411,13 +447,13 @@ impl Generator { } /// Clones generator point, returns `Point` - pub fn to_point_owned(self) -> Point { + pub fn to_point(self) -> Point { // Safety: curve generator must be non-zero point, otherwise nothing will work at all unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } } /// Converts generator into `PointRef` - pub fn as_point_ref(self) -> PointRef<'static, E> { + pub fn as_point(self) -> PointRef<'static, E> { // Safety: curve generator must be non-zero point, otherwise nothing will work at all unsafe { PointRef::from_raw_unchecked(self.as_raw()) } } @@ -512,7 +548,7 @@ where } /// Clones the referenced point - pub fn to_point_owned(&self) -> Point { + pub fn to_point(&self) -> Point { // Safety: `self` is guaranteed to be non-zero unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } } @@ -556,6 +592,30 @@ impl<'p, E: Curve> From<&'p Point> for PointRef<'p, E> { } } +impl<'p, E: Curve> PartialEq for PointRef<'p, E> { + fn eq(&self, other: &Self) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { + fn eq(&self, other: &Point) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { + fn eq(&self, other: &PointZ) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { + fn eq(&self, other: &Generator) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + /// Indicates that conversion or computation failed due to occurred zero point #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct ZeroPointError(()); From 93317ec1d5b4ba401297d2f5d576d03ed3b7b39a Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 7 Jul 2021 17:00:44 +0300 Subject: [PATCH 30/93] Update sigma_dlog --- src/cryptographic_primitives/proofs/mod.rs | 2 +- .../proofs/sigma_dlog.rs | 80 ++++++++----------- 2 files changed, 36 insertions(+), 46 deletions(-) diff --git a/src/cryptographic_primitives/proofs/mod.rs b/src/cryptographic_primitives/proofs/mod.rs index 0742d47e..5fb8209e 100644 --- a/src/cryptographic_primitives/proofs/mod.rs +++ b/src/cryptographic_primitives/proofs/mod.rs @@ -11,7 +11,7 @@ use std::fmt; pub mod low_degree_exponent_interpolation; pub mod sigma_correct_homomorphic_elgamal_enc; pub mod sigma_correct_homomorphic_elgamal_encryption_of_dlog; -// pub mod sigma_dlog; +pub mod sigma_dlog; // pub mod sigma_ec_ddh; // pub mod sigma_valid_pedersen; // pub mod sigma_valid_pedersen_blind; diff --git a/src/cryptographic_primitives/proofs/sigma_dlog.rs b/src/cryptographic_primitives/proofs/sigma_dlog.rs index 06a45b74..dc429073 100644 --- a/src/cryptographic_primitives/proofs/sigma_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_dlog.rs @@ -6,13 +6,14 @@ */ use serde::{Deserialize, Serialize}; -use zeroize::Zeroize; use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; use crate::cryptographic_primitives::hashing::traits::Hash; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::{Curve, Point, Scalar, ScalarZ}; use super::ProofError; +use crate::arithmetic::Converter; +use crate::BigInt; /// This is implementation of Schnorr's identification protocol for elliptic curve groups or a /// sigma protocol for Proof of knowledge of the discrete log of an Elliptic-curve point: @@ -25,33 +26,30 @@ use super::ProofError; /// In Advances in Cryptology - CRYPTO ’86, Santa Barbara, California, USA, 1986, Proceedings, /// pages 186–194, 1986. #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct DLogProof { - pub pk: P, - pub pk_t_rand_commitment: P, - pub challenge_response: P::Scalar, +pub struct DLogProof { + pub pk: Point, + pub pk_t_rand_commitment: Point, + pub challenge_response: ScalarZ, } -impl

DLogProof

-where - P: ECPoint + Clone, - P::Scalar: Zeroize, -{ - pub fn prove(sk: &P::Scalar) -> DLogProof

{ - let base_point: P = ECPoint::generator(); - let generator_x = base_point.bytes_compressed_to_big_int(); - let mut sk_t_rand_commitment: P::Scalar = ECScalar::new_random(); - let pk_t_rand_commitment = base_point.scalar_mul(&sk_t_rand_commitment.get_element()); - let ec_point: P = ECPoint::generator(); - let pk = ec_point.scalar_mul(&sk.get_element()); +impl DLogProof { + pub fn prove(sk: &Scalar) -> DLogProof { + let generator = Point::::generator(); + + let sk_t_rand_commitment = Scalar::random(); + let pk_t_rand_commitment = generator * &sk_t_rand_commitment; + + let pk = Point::generator() * sk; + let challenge = HSha256::create_hash(&[ - &pk_t_rand_commitment.bytes_compressed_to_big_int(), - &generator_x, - &pk.bytes_compressed_to_big_int(), + &BigInt::from_bytes(&pk_t_rand_commitment.to_bytes(true)), + &BigInt::from_bytes(&generator.as_point().to_bytes(true)), + &BigInt::from_bytes(&pk.to_bytes(true)), ]); - let challenge_fe: P::Scalar = ECScalar::from(&challenge); - let challenge_mul_sk = challenge_fe.mul(&sk.get_element()); - let challenge_response = sk_t_rand_commitment.sub(&challenge_mul_sk.get_element()); - sk_t_rand_commitment.zeroize(); + + let challenge_fe: ScalarZ = ScalarZ::from(&challenge); + let challenge_mul_sk = challenge_fe * sk; + let challenge_response = &sk_t_rand_commitment - &challenge_mul_sk; DLogProof { pk, pk_t_rand_commitment, @@ -59,23 +57,19 @@ where } } - pub fn verify(proof: &DLogProof

) -> Result<(), ProofError> { - let ec_point: P = ECPoint::generator(); + pub fn verify(proof: &DLogProof) -> Result<(), ProofError> { + let generator = Point::::generator(); + let challenge = HSha256::create_hash(&[ - &proof.pk_t_rand_commitment.bytes_compressed_to_big_int(), - &ec_point.bytes_compressed_to_big_int(), - &proof.pk.bytes_compressed_to_big_int(), + &BigInt::from_bytes(&proof.pk_t_rand_commitment.to_bytes(true)), + &BigInt::from_bytes(&generator.as_point().to_bytes(true)), + &BigInt::from_bytes(&proof.pk.to_bytes(true)), ]); - let sk_challenge: P::Scalar = ECScalar::from(&challenge); - let pk = proof.pk.clone(); - let pk_challenge = pk.scalar_mul(&sk_challenge.get_element()); - - let base_point: P = ECPoint::generator(); - - let mut pk_verifier = base_point.scalar_mul(&proof.challenge_response.get_element()); + let sk_challenge = ScalarZ::::from(&challenge); + let pk_challenge = &proof.pk * &sk_challenge; - pk_verifier = pk_verifier.add_point(&pk_challenge.get_element()); + let pk_verifier = generator * &proof.challenge_response + pk_challenge; if pk_verifier == proof.pk_t_rand_commitment { Ok(()) @@ -90,13 +84,9 @@ mod tests { use super::*; crate::test_for_all_curves!(test_dlog_proof); - fn test_dlog_proof

() - where - P: ECPoint + Clone, - P::Scalar: Zeroize, - { - let witness: P::Scalar = ECScalar::new_random(); - let dlog_proof = DLogProof::

::prove(&witness); + fn test_dlog_proof() { + let witness = Scalar::random(); + let dlog_proof = DLogProof::::prove(&witness); assert!(DLogProof::verify(&dlog_proof).is_ok()); } } From a63cea86abf9e9b5310ad506679be4cf15d61ce8 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 7 Jul 2021 19:09:00 +0300 Subject: [PATCH 31/93] Update sigma_ec_ddh --- src/cryptographic_primitives/proofs/mod.rs | 2 +- .../proofs/sigma_ec_ddh.rs | 130 +++++++++--------- 2 files changed, 68 insertions(+), 64 deletions(-) diff --git a/src/cryptographic_primitives/proofs/mod.rs b/src/cryptographic_primitives/proofs/mod.rs index 5fb8209e..4bd42fe1 100644 --- a/src/cryptographic_primitives/proofs/mod.rs +++ b/src/cryptographic_primitives/proofs/mod.rs @@ -12,7 +12,7 @@ pub mod low_degree_exponent_interpolation; pub mod sigma_correct_homomorphic_elgamal_enc; pub mod sigma_correct_homomorphic_elgamal_encryption_of_dlog; pub mod sigma_dlog; -// pub mod sigma_ec_ddh; +pub mod sigma_ec_ddh; // pub mod sigma_valid_pedersen; // pub mod sigma_valid_pedersen_blind; diff --git a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs index 4219d89c..3bfbf8ec 100644 --- a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs +++ b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs @@ -6,12 +6,11 @@ */ use serde::{Deserialize, Serialize}; -use zeroize::Zeroize; use super::ProofError; use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; use crate::cryptographic_primitives::hashing::traits::Hash; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; /// This protocol is the elliptic curve form of the protocol from : /// D. Chaum, T. P. Pedersen. Transferred cash grows in size. In Advances in Cryptology, EUROCRYPT , volume 658 of Lecture Notes in Computer Science, pages 390 - 407, 1993. @@ -26,49 +25,55 @@ use crate::elliptic::curves::traits::*; /// /// verifier checks that zG1 = A1 + eH1, zG2 = A2 + eH2 #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct ECDDHProof { - pub a1: P, - pub a2: P, - pub z: P::Scalar, +pub struct ECDDHProof { + pub a1: PointZ, + pub a2: PointZ, + pub z: ScalarZ, } #[derive(Clone, PartialEq, Debug)] -pub struct ECDDHStatement { - pub g1: P, - pub h1: P, - pub g2: P, - pub h2: P, +pub struct ECDDHStatement { + pub g1: Point, + pub h1: Point, + pub g2: Point, + pub h2: Point, } #[derive(Clone, PartialEq, Debug)] -pub struct ECDDHWitness { - pub x: S, +pub struct ECDDHWitness { + pub x: Scalar, } -impl

ECDDHProof

-where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, -{ - pub fn prove(w: &ECDDHWitness, delta: &ECDDHStatement

) -> ECDDHProof

{ - let mut s: P::Scalar = ECScalar::new_random(); - let a1 = delta.g1.clone() * s.clone(); - let a2 = delta.g2.clone() * s.clone(); - let e = - HSha256::create_hash_from_ge(&[&delta.g1, &delta.h1, &delta.g2, &delta.h2, &a1, &a2]); - let z = s.clone() + e * w.x.clone(); - s.zeroize(); +impl ECDDHProof { + pub fn prove(w: &ECDDHWitness, delta: &ECDDHStatement) -> ECDDHProof { + let s = Scalar::random(); + let a1 = &delta.g1 * &s; + let a2 = &delta.g2 * &s; + let e = HSha256::create_hash_from_ge_z(&[ + &PointZ::from(delta.g1.clone()), + &PointZ::from(delta.h1.clone()), + &PointZ::from(delta.g2.clone()), + &PointZ::from(delta.h2.clone()), + &a1, + &a2, + ]); + let z = &s + e * &w.x; ECDDHProof { a1, a2, z } } - pub fn verify(&self, delta: &ECDDHStatement

) -> Result<(), ProofError> { - let e = HSha256::create_hash_from_ge(&[ - &delta.g1, &delta.h1, &delta.g2, &delta.h2, &self.a1, &self.a2, + pub fn verify(&self, delta: &ECDDHStatement) -> Result<(), ProofError> { + let e = HSha256::create_hash_from_ge_z(&[ + &PointZ::from(delta.g1.clone()), + &PointZ::from(delta.h1.clone()), + &PointZ::from(delta.g2.clone()), + &PointZ::from(delta.h2.clone()), + &self.a1, + &self.a2, ]); - let z_g1 = delta.g1.clone() * self.z.clone(); - let z_g2 = delta.g2.clone() * self.z.clone(); - let a1_plus_e_h1 = self.a1.clone() + delta.h1.clone() * e.clone(); - let a2_plus_e_h2 = self.a2.clone() + delta.h2.clone() * e; + let z_g1 = &delta.g1 * &self.z; + let z_g2 = &delta.g2 * &self.z; + let a1_plus_e_h1 = &self.a1 + &delta.h1 * &e; + let a2_plus_e_h2 = &self.a2 + &delta.h2 * e; if z_g1 == a1_plus_e_h1 && z_g2 == a2_plus_e_h2 { Ok(()) } else { @@ -79,45 +84,44 @@ where #[cfg(test)] mod tests { - use crate::cryptographic_primitives::proofs::sigma_ec_ddh::*; - use crate::elliptic::curves::traits::{ECPoint, ECScalar}; use crate::test_for_all_curves; + use super::*; + test_for_all_curves!(test_ecddh_proof); - fn test_ecddh_proof

() - where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, - { - let x: P::Scalar = ECScalar::new_random(); - let g1: P = ECPoint::generator(); - let g2: P = ECPoint::base_point2(); - let h1 = g1.clone() * x.clone(); - let h2 = g2.clone() * x.clone(); - let delta = ECDDHStatement { g1, g2, h1, h2 }; + fn test_ecddh_proof() { + let x = Scalar::::random(); + let g1 = Point::generator(); + let g2 = Point::base_point2(); + let h1 = g1 * &x; + let h2 = (g2 * &x).ensure_nonzero().unwrap(); + let delta = ECDDHStatement { + g1: g1.to_point(), + g2: g2.to_point(), + h1, + h2, + }; let w = ECDDHWitness { x }; let proof = ECDDHProof::prove(&w, &delta); assert!(proof.verify(&delta).is_ok()); } - test_for_all_curves!( - #[should_panic] - test_wrong_ecddh_proof - ); - fn test_wrong_ecddh_proof

() - where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, - { - let x: P::Scalar = ECScalar::new_random(); - let g1: P = ECPoint::generator(); - let g2: P = ECPoint::base_point2(); - let x2: P::Scalar = ECScalar::new_random(); - let h1 = g1.clone() * x.clone(); - let h2 = g2.clone() * x2; - let delta = ECDDHStatement { g1, g2, h1, h2 }; + test_for_all_curves!(test_wrong_ecddh_proof); + fn test_wrong_ecddh_proof() { + let x = Scalar::::random(); + let g1 = Point::generator(); + let g2 = Point::base_point2(); + let x2 = Scalar::::random(); + let h1 = g1 * &x; + let h2 = (g2 * &x2).ensure_nonzero().unwrap(); + let delta = ECDDHStatement { + g1: g1.to_point(), + g2: g2.to_point(), + h1, + h2, + }; let w = ECDDHWitness { x }; let proof = ECDDHProof::prove(&w, &delta); - assert!(proof.verify(&delta).is_ok()); + assert!(!proof.verify(&delta).is_ok()); } } From c03f8e23b5a2a6cff4dd3800919041946b8a543e Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 8 Jul 2021 12:42:37 +0300 Subject: [PATCH 32/93] Rename curve_order to group_order --- src/elliptic/curves/secp256_k1.rs | 20 ++++++++++---------- src/elliptic/curves/traits.rs | 3 ++- src/elliptic/curves/wrappers.rs | 8 ++++---- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index a89f756f..49a8f53c 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -178,8 +178,8 @@ impl ECScalar for Secp256k1Scalar { return Self::zero(); } - let curve_order = Self::curve_order(); - let n_reduced = n.modulus(curve_order); + let group_order = Self::group_order(); + let n_reduced = n.modulus(group_order); let bytes = BigInt::to_bytes(&n_reduced); let bytes = if bytes.len() < SECRET_KEY_SIZE { @@ -206,7 +206,7 @@ impl ECScalar for Secp256k1Scalar { fn add(&self, other: &Self) -> Secp256k1Scalar { // TODO: use add_assign? // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.add_assign - let n = BigInt::mod_add(&self.to_bigint(), &other.to_bigint(), Self::curve_order()); + let n = BigInt::mod_add(&self.to_bigint(), &other.to_bigint(), Self::group_order()); Secp256k1Scalar { purpose: "add", fe: Self::from_bigint(&n).fe, @@ -216,7 +216,7 @@ impl ECScalar for Secp256k1Scalar { fn mul(&self, other: &Self) -> Secp256k1Scalar { // TODO: use mul_assign? // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.mul_assign - let n = BigInt::mod_mul(&self.to_bigint(), &other.to_bigint(), Self::curve_order()); + let n = BigInt::mod_mul(&self.to_bigint(), &other.to_bigint(), Self::group_order()); Secp256k1Scalar { purpose: "mul", fe: Self::from_bigint(&n).fe, @@ -227,7 +227,7 @@ impl ECScalar for Secp256k1Scalar { // TODO: use negate+add_assign? // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.negate_assign // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.add_assign - let n = BigInt::mod_sub(&self.to_bigint(), &other.to_bigint(), Self::curve_order()); + let n = BigInt::mod_sub(&self.to_bigint(), &other.to_bigint(), Self::group_order()); Secp256k1Scalar { purpose: "sub", fe: Self::from_bigint(&n).fe, @@ -235,7 +235,7 @@ impl ECScalar for Secp256k1Scalar { } fn neg(&self) -> Self { - let n = BigInt::mod_sub(&BigInt::zero(), &self.to_bigint(), Self::curve_order()); + let n = BigInt::mod_sub(&BigInt::zero(), &self.to_bigint(), Self::group_order()); Secp256k1Scalar { purpose: "neg", fe: Self::from_bigint(&n).fe, @@ -244,14 +244,14 @@ impl ECScalar for Secp256k1Scalar { fn invert(&self) -> Option { let n = self.to_bigint(); - let n_inv = BigInt::mod_inv(&n, Self::curve_order()); + let n_inv = BigInt::mod_inv(&n, Self::group_order()); n_inv.map(|i| Secp256k1Scalar { purpose: "invert", fe: Self::from_bigint(&i).fe, }) } - fn curve_order() -> &'static BigInt { + fn group_order() -> &'static BigInt { &CURVE_ORDER } @@ -621,7 +621,7 @@ mod test { #[test] fn scalar_modulo_curve_order() { - let n = FE::curve_order(); + let n = FE::group_order(); let s = FE::from_bigint(n); assert!(s.is_zero()); @@ -673,7 +673,7 @@ mod test { #[test] fn generator_mul_curve_order_is_zero() { let g = GE::generator(); - let n = FE::curve_order() - 1; + let n = FE::group_order() - 1; let s = FE::from_bigint(&n); assert!(g.scalar_mul(&s).add_point(&g).is_zero()); } diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index e029cedf..e97f60fa 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -80,7 +80,8 @@ pub trait ECScalar: Clone + PartialEq + fmt::Debug + 'static { *self = self.neg() } - fn curve_order() -> &'static BigInt; + /// Returns an order of generator point + fn group_order() -> &'static BigInt; /// Returns a reference to underlying scalar value fn underlying_ref(&self) -> &Self::Underlying; diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index e3a0aae3..3ddf43a3 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -728,9 +728,9 @@ impl ScalarZ { Self::from_raw(E::Scalar::from_bigint(n)) } - /// Returns a curve order - pub fn curve_order() -> &'static BigInt { - E::Scalar::curve_order() + /// Returns an order of generator point + pub fn group_order() -> &'static BigInt { + E::Scalar::group_order() } /// Returns inversion `self^-1 mod curve_order`, or None if `self` is zero @@ -892,7 +892,7 @@ impl Scalar { /// Returns a curve order pub fn curve_order() -> &'static BigInt { - E::Scalar::curve_order() + E::Scalar::group_order() } /// Converts a scalar to [BigInt] From ac52e3fe0b6da5a5d7c9e354a6d65cf42749ac4c Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 12:44:44 +0300 Subject: [PATCH 33/93] Restrict the points to be of group order --- .../sigma_correct_homomorphic_elgamal_enc.rs | 14 +- ..._homomorphic_elgamal_encryption_of_dlog.rs | 18 +- .../proofs/sigma_ec_ddh.rs | 29 +- src/elliptic/curves/traits.rs | 28 +- src/elliptic/curves/wrappers.rs | 490 +++++++++++------- 5 files changed, 339 insertions(+), 240 deletions(-) diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs index 55a2e888..96cc4de7 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs @@ -22,7 +22,7 @@ use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct HomoELGamalProof { pub T: PointZ, - pub A3: PointZ, + pub A3: Point, pub z1: ScalarZ, pub z2: ScalarZ, } @@ -55,12 +55,12 @@ impl HomoELGamalProof { let T = A1 + A2; let e = HSha256::create_hash_from_ge_z(&[ &T, - &A3, + &PointZ::from(A3.clone()), &PointZ::from(delta.G.clone()), &PointZ::from(delta.H.clone()), &PointZ::from(delta.Y.clone()), - &PointZ::from(delta.D.clone()), - &PointZ::from(delta.E.clone()), + &delta.D, + &delta.E, ]); // dealing with zero field element let z1 = if !w.x.is_zero() { @@ -74,12 +74,12 @@ impl HomoELGamalProof { pub fn verify(&self, delta: &HomoElGamalStatement) -> Result<(), ProofError> { let e = HSha256::create_hash_from_ge_z(&[ &self.T, - &self.A3, + &PointZ::from(self.A3.clone()), &PointZ::from(delta.G.clone()), &PointZ::from(delta.H.clone()), &PointZ::from(delta.Y.clone()), - &PointZ::from(delta.D.clone()), - &PointZ::from(delta.E.clone()), + &delta.D, + &delta.E, ]); let z1H_plus_z2Y = &delta.H * &self.z1 + &delta.Y * &self.z2; let T_plus_eD = &self.T + &delta.D * &e; diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs index 977b84a9..47f21e1e 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs @@ -21,9 +21,9 @@ use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; /// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct HomoELGamalDlogProof { - pub A1: PointZ, - pub A2: PointZ, - pub A3: PointZ, + pub A1: Point, + pub A2: Point, + pub A3: Point, pub z1: ScalarZ, pub z2: ScalarZ, } @@ -54,9 +54,9 @@ impl HomoELGamalDlogProof { let A2 = &delta.Y * &s2; let A3 = &delta.G * &s2; let e = HSha256::create_hash_from_ge_z(&[ - &A1, - &A2, - &A3, + &PointZ::from(A1.clone()), + &PointZ::from(A2.clone()), + &PointZ::from(A3.clone()), &PointZ::from(delta.G.clone()), &PointZ::from(delta.Y.clone()), &delta.D, @@ -69,9 +69,9 @@ impl HomoELGamalDlogProof { pub fn verify(&self, delta: &HomoElGamalDlogStatement) -> Result<(), ProofError> { let e = HSha256::create_hash_from_ge_z(&[ - &self.A1, - &self.A2, - &self.A3, + &PointZ::from(self.A1.clone()), + &PointZ::from(self.A2.clone()), + &PointZ::from(self.A3.clone()), &PointZ::from(delta.G.clone()), &PointZ::from(delta.Y.clone()), &delta.D, diff --git a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs index 3bfbf8ec..d430f76c 100644 --- a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs +++ b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; use super::ProofError; use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; use crate::cryptographic_primitives::hashing::traits::Hash; -use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar, ScalarZ}; /// This protocol is the elliptic curve form of the protocol from : /// D. Chaum, T. P. Pedersen. Transferred cash grows in size. In Advances in Cryptology, EUROCRYPT , volume 658 of Lecture Notes in Computer Science, pages 390 - 407, 1993. @@ -26,8 +26,8 @@ use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; /// verifier checks that zG1 = A1 + eH1, zG2 = A2 + eH2 #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct ECDDHProof { - pub a1: PointZ, - pub a2: PointZ, + pub a1: Point, + pub a2: Point, pub z: ScalarZ, } @@ -49,26 +49,15 @@ impl ECDDHProof { let s = Scalar::random(); let a1 = &delta.g1 * &s; let a2 = &delta.g2 * &s; - let e = HSha256::create_hash_from_ge_z(&[ - &PointZ::from(delta.g1.clone()), - &PointZ::from(delta.h1.clone()), - &PointZ::from(delta.g2.clone()), - &PointZ::from(delta.h2.clone()), - &a1, - &a2, - ]); + let e = + HSha256::create_hash_from_ge(&[&delta.g1, &delta.h1, &delta.g2, &delta.h2, &a1, &a2]); let z = &s + e * &w.x; ECDDHProof { a1, a2, z } } pub fn verify(&self, delta: &ECDDHStatement) -> Result<(), ProofError> { - let e = HSha256::create_hash_from_ge_z(&[ - &PointZ::from(delta.g1.clone()), - &PointZ::from(delta.h1.clone()), - &PointZ::from(delta.g2.clone()), - &PointZ::from(delta.h2.clone()), - &self.a1, - &self.a2, + let e = HSha256::create_hash_from_ge(&[ + &delta.g1, &delta.h1, &delta.g2, &delta.h2, &self.a1, &self.a2, ]); let z_g1 = &delta.g1 * &self.z; let z_g2 = &delta.g2 * &self.z; @@ -94,7 +83,7 @@ mod tests { let g1 = Point::generator(); let g2 = Point::base_point2(); let h1 = g1 * &x; - let h2 = (g2 * &x).ensure_nonzero().unwrap(); + let h2 = g2 * &x; let delta = ECDDHStatement { g1: g1.to_point(), g2: g2.to_point(), @@ -113,7 +102,7 @@ mod tests { let g2 = Point::base_point2(); let x2 = Scalar::::random(); let h1 = g1 * &x; - let h2 = (g2 * &x2).ensure_nonzero().unwrap(); + let h2 = g2 * &x2; let delta = ECDDHStatement { g1: g1.to_point(), g2: g2.to_point(), diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index e97f60fa..914cc905 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -23,7 +23,7 @@ pub trait Curve { const CURVE_NAME: &'static str; } -/// Scalar value modulus [curve order](Self::curve_order) +/// Scalar value modulus [group order](Self::group_order) /// /// ## Note /// This is a low-level trait, you should not use it directly. See wrappers [Point], [PointZ], @@ -157,17 +157,33 @@ pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug + 'static { /// Whether point in compressed or uncompressed form will be deducted from its size fn deserialize(bytes: &[u8]) -> Result; + /// Checks that order of this point equals to [group order](ECScalar::group_order) + /// + /// Generally, point might be composition of different subgroups points: `P = sG + kT` (`G` — + /// curve generator of order `q`=[group_order](ECScalar::group_order), `T` — generator of smaller + /// order). This function ensures that the point is of order `q`, ie. of form: `P = sG`. + /// + /// For curves with co-factor ≠ 1, following check must be carried out: + /// + /// ```text + /// P ≠ 0 ∧ qP ≠ 0 + /// ``` + /// + /// For curves with co-factor = 1, the check above can be reduced to: `P ≠ 0`. + fn check_point_order_equals_group_order(&self) -> bool { + let mut self_at_q = self.scalar_mul(&Self::Scalar::from_bigint( + &(Self::Scalar::group_order() - 1), + )); + self_at_q.add_point_assign(self); + !self.is_zero() && self_at_q.is_zero() + } + /// Multiplies the point at scalar value fn scalar_mul(&self, scalar: &Self::Scalar) -> Self; /// Multiplies curve generator at given scalar /// /// Basically, it's the same as `ECPoint::generator().scalar_mul(&s)`, but can be more efficient /// because most curve libs have constant time high performance generator multiplication. - /// - /// ## Correctness - /// - /// Note that scalar is modulo [curve order](ECScalar::curve_order), so multiplying generator - /// at non-zero scalar **must** always produce non-zero point. fn generator_mul(scalar: &Self::Scalar) -> Self { Self::generator().scalar_mul(scalar) } diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs index 3ddf43a3..dda7eb82 100644 --- a/src/elliptic/curves/wrappers.rs +++ b/src/elliptic/curves/wrappers.rs @@ -9,7 +9,7 @@ use thiserror::Error; use super::traits::*; use crate::arithmetic::{BigInt, Converter}; -/// Elliptic point that **might be zero** +/// Either an elliptic point of a [group order](Scalar::group_order), or a zero point /// /// ## Security /// @@ -19,10 +19,14 @@ use crate::arithmetic::{BigInt, Converter}; /// /// ## Guarantees /// -/// * Belongs to curve +/// * On curve /// /// Any instance of `PointZ` is guaranteed to belong to curve `E`, i.e. its coordinates must /// satisfy curve equations +/// * Point order equals to [group order](Scalar::group_order) (unless it's zero point) +/// +/// I.e. denoting `q = group_order`, following predicate is always true: +/// `P = O ∨ qP = O ∧ forall 0 < s < q. sP ≠ O` /// /// ## Arithmetics /// @@ -53,7 +57,7 @@ impl PointZ { /// Constructs zero point /// - /// Zero point is usually denoted as O. It's curve neutral element, i.e. `forall A. A + O = A`. + /// Zero point (or curve neutral element) is usually denoted as `O`. Its property: `forall A. A + O = A`. /// /// Weierstrass and Montgomery curves employ special "point at infinity" that represent a neutral /// element, such points don't have coordinates (i.e. [from_coords], [x_coord], [y_coord] return @@ -63,11 +67,12 @@ impl PointZ { /// [x_coord]: Self::x_coord /// [y_coord]: Self::y_coord pub fn zero() -> Self { - Self::from_raw(E::Point::zero()) + // Safety: `self` can be constructed to hold a zero point + unsafe { Self::from_raw_unchecked(E::Point::zero()) } } /// Checks whether point is zero - pub fn iz_zero(&self) -> bool { + pub fn is_zero(&self) -> bool { self.as_raw().is_zero() } @@ -94,25 +99,38 @@ impl PointZ { } /// Constructs a point from its coordinates, returns error if coordinates don't satisfy - /// curve equation - pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { - E::Point::from_coords(x, y).map(Self::from_raw) + /// curve equation or if point has invalid order + pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { + let raw_point = E::Point::from_coords(x, y) + .map_err(|_: NotOnCurve| PointZFromCoordsError::NotOnCurve)?; + Self::from_raw(raw_point).map_err(PointZFromCoordsError::InvalidPoint) } - /// Tries to parse a point from its (un)compressed form + /// Tries to parse a point in (un)compressed form /// - /// Whether it's a compressed or uncompressed form will be deduced from its length - pub fn from_bytes(bytes: &[u8]) -> Result { - let p = E::Point::deserialize(bytes)?; - Ok(Self::from_raw(p)) + /// Whether it's in compressed or uncompressed form will be deduced from its length + pub fn from_bytes(bytes: &[u8]) -> Result { + let p = E::Point::deserialize(bytes) + .map_err(|_: DeserializationError| PointZDeserializationError::DeserializationError)?; + Self::from_raw(p).map_err(PointZDeserializationError::InvalidPoint) } - /// Serializes point into (un)compressed form + /// Serializes a point in (un)compressed form + /// + /// Returns `None` if it's point at infinity pub fn to_bytes(&self, compressed: bool) -> Option> { self.as_raw().serialize(compressed) } - fn from_raw(raw_point: E::Point) -> Self { + fn from_raw(raw_point: E::Point) -> Result { + if raw_point.is_zero() || raw_point.check_point_order_equals_group_order() { + Ok(Self { raw_point }) + } else { + Err(MismatchedPointOrder(())) + } + } + + unsafe fn from_raw_unchecked(raw_point: E::Point) -> Self { Self { raw_point } } @@ -151,9 +169,8 @@ impl PartialEq> for PointZ { impl Clone for PointZ { fn clone(&self) -> Self { - PointZ { - raw_point: self.as_raw().clone(), - } + // Safety: self is guaranteed to have correct order + unsafe { PointZ::from_raw_unchecked(self.as_raw().clone()) } } } @@ -165,41 +182,54 @@ impl fmt::Debug for PointZ { impl From> for PointZ { fn from(p: Point) -> Self { - PointZ::from_raw(p.into_raw()) + // Safety: `Point` is guaranteed to have correct order + unsafe { PointZ::from_raw_unchecked(p.into_raw()) } } } -/// Elliptic point that _guaranteed_ to be non zero -/// -/// ## Security -/// Non-zero points are preferred to be used in cryptographic algorithms. Lack of checking whether -/// computation on elliptic points results into zero point might lead to vulnerabilities. Using -/// `Point` ensures you and reviewers that check on point not being zero was made. +#[derive(Debug, Error, Clone, PartialEq)] +#[error("invalid point (point order ≠ group order)")] +pub struct MismatchedPointOrder(()); + +#[derive(Debug, Error)] +pub enum PointZDeserializationError { + #[error("failed to deserialize the point")] + DeserializationError, + #[error("invalid point ({0})")] + InvalidPoint(MismatchedPointOrder), +} + +#[derive(Debug, Error)] +pub enum PointZFromCoordsError { + #[error("{}", NotOnCurve)] + NotOnCurve, + #[error("invalid point ({0})")] + InvalidPoint(MismatchedPointOrder), +} + +/// Elliptic point of [group order](Scalar::group_order) /// /// ## Guarantees /// -/// * Belongs to curve +/// * On curve /// /// Any instance of `Point` is guaranteed to belong to curve `E`, i.e. its coordinates must /// satisfy curve equations -/// * Not a neutral element -/// -/// Any instance of `Point` is restricted not to be zero (neutral element), i.e. for any -/// `a: PointZ ∧ b: Point → a + b ≢ a`. +/// * Point order equals to [group order](Scalar::group_order) /// -/// Weierstrass and Montgomery curves represent zero point -/// using special "point at infinity", whereas Edwards curves zero point is a regular point that -/// has coordinates. `Point` cannot be instantiated with neither of these points. +/// I.e. denoting `q = group_order`, following predicate is always true: +/// `qP = O ∧ forall 0 < s < q. sP ≠ O` /// -/// Note also that `Point` is guaranteed to have coordinates (only point at infinity doesn't). +/// Note that this also means that `Point` cannot be zero (zero point has `order=1`), +/// ie. `forall a b. a: PointZ ∧ b: Point → a + b ≢ a`. It also implies that `Point` is +/// guaranteed to have coordinates (only point at infinity doesn't). /// /// ## Arithmetics /// /// You can add, subtract two points, or multiply point at scalar. /// -/// Any arithmetic operation on non-zero point might result into zero point, so addition, subtraction, -/// and multiplication operations output [PointZ]. Use [ensure_nonzero](PointZ::ensure_nonzero) method -/// to ensure that computation doesn't produce zero-point: +/// Addition or subtraction of two points might result into zero point, so these operators output +/// [`PointZ`](PointZ) that allowed to be zero. /// /// ```rust /// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; @@ -212,8 +242,8 @@ impl From> for PointZ { /// let nonzero_result: Option> = result.ensure_nonzero(); /// ``` /// -/// Exception is [curve generator](Self::generator) that can be multiplied at non-zero scalar, and -/// resulting point is guaranteed to be non-zero: +/// Multiplying point at non-zero scalar is guaranteed to be non-zero (as point order is known +/// to be equal to group order, and scalar is known to be less then group order): /// /// ```rust /// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; @@ -222,16 +252,6 @@ impl From> for PointZ { /// let result: Point = s * g; // Generator multiplied at non-zero scalar is /// // always a non-zero point /// ``` -/// -/// When evaluating complex expressions, you typically need to ensure that none of intermediate -/// results are zero-points: -/// -/// ```rust -/// # use curv::elliptic::curves::{Curve, Point, Scalar}; -/// fn expression(a: Point, b: Point, c: Scalar) -> Option> { -/// (a + (b * c).ensure_nonzero()?).ensure_nonzero() -/// } -/// ``` #[derive(Serialize, Deserialize)] #[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] pub struct Point { @@ -242,7 +262,7 @@ impl Point { /// Curve generator /// /// Returns a static reference on actual value because in most cases referenced value is fine. - /// Use [`.to_point_owned()`](PointRef::to_point_owned) if you need to take it by value. + /// Use [`.to_point()`](Generator::to_point) if you need to take it by value. pub fn generator() -> Generator { Generator::default() } @@ -252,10 +272,10 @@ impl Point { /// We provide an alternative generator value and prove that it was picked randomly. /// /// Returns a static reference on actual value because in most cases referenced value is fine. - /// Use [`.to_point_owned()`](PointRef::to_point_owned) if you need to take it by value. + /// Use [`.to_point()`](PointRef::to_point) if you need to take it by value. pub fn base_point2() -> PointRef<'static, E> { let p = E::Point::base_point2(); - PointRef::from_raw(p).expect("base_point2 must be non-zero") + PointRef::from_raw(p).expect("base_point2 must have correct order") } /// Constructs a point from coordinates, returns error if x,y don't satisfy curve equation or @@ -263,7 +283,7 @@ impl Point { pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { let p = E::Point::from_coords(x, y) .map_err(|NotOnCurve { .. }| PointFromCoordsError::PointNotOnCurve)?; - Self::from_raw(p).map_err(|ZeroPointError(())| PointFromCoordsError::ZeroPoint) + Self::from_raw(p).map_err(PointFromCoordsError::InvalidPoint) } /// Tries to parse a point from its (un)compressed form @@ -271,7 +291,7 @@ impl Point { /// Whether it's a compressed or uncompressed form will be deduced from its length pub fn from_bytes(bytes: &[u8]) -> Result { let p = E::Point::deserialize(bytes).map_err(PointFromBytesError::Deserialize)?; - Self::from_raw(p).map_err(|ZeroPointError(())| PointFromBytesError::ZeroPoint) + Self::from_raw(p).map_err(PointFromBytesError::InvalidPoint) } /// Returns point coordinates (`x` and `y`) @@ -295,26 +315,6 @@ impl Point { self.as_point().y_coord() } - /// Adds two points, returns the result, or `None` if resulting point is zero - pub fn add_checked(&self, point: PointRef) -> Result { - self.as_point().add_checked(point) - } - - /// Substrates two points, returns the result, or `None` if resulting point is zero - pub fn sub_checked(&self, point: PointRef) -> Result { - self.as_point().sub_checked(point) - } - - /// Multiplies a point at scalar, returns the result, or `None` if resulting point is zero - pub fn mul_checked_z(&self, scalar: &ScalarZ) -> Result { - self.as_point().mul_checked_z(scalar) - } - - /// Multiplies a point at nonzero scalar, returns the result, or `None` if resulting point is zero - pub fn mul_checked(&self, scalar: &Scalar) -> Result { - self.as_point().mul_checked(scalar) - } - /// Serializes point into (un)compressed form pub fn to_bytes(&self, compressed: bool) -> Vec { self.as_point().to_bytes(compressed) @@ -325,11 +325,13 @@ impl Point { PointRef::from(self) } - fn from_raw(raw_point: E::Point) -> Result { + fn from_raw(raw_point: E::Point) -> Result { if raw_point.is_zero() { - Err(ZeroPointError(())) + Err(InvalidPoint::ZeroPoint) + } else if !raw_point.check_point_order_equals_group_order() { + Err(InvalidPoint::MismatchedPointOrder) } else { - Ok(Self { raw_point }) + Ok(Point { raw_point }) } } @@ -386,7 +388,11 @@ impl fmt::Debug for Point { impl TryFrom> for Point { type Error = ZeroPointError; fn try_from(point: PointZ) -> Result { - Self::from_raw(point.into_raw()) + match Self::from_raw(point.into_raw()) { + Ok(p) => Ok(p), + Err(InvalidPoint::ZeroPoint) => Err(ZeroPointError(())), + Err(InvalidPoint::MismatchedPointOrder) => panic!("Point must have correct order"), + } } } @@ -396,14 +402,10 @@ impl TryFrom> for Point { /// as [`PointRef`](PointRef). /// /// You can convert the generator into `Point` and `PointRef` using -/// [`to_point_owned`](Self::to_point_owned) and [`as_point_ref`](Self::as_point_ref) +/// [`to_point`](Self::to_point) and [`as_point`](Self::as_point) /// methods respectively. /// -/// ## Guarantees -/// -/// Generator multiplied at non-zero scalar always produce non-zero point, thus output type of -/// the multiplication is [`Point`](Point). This is the only difference compared to `Point` and -/// `PointRef`. +/// ## Example /// /// ```rust /// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; @@ -426,10 +428,9 @@ impl TryFrom> for Point { /// let p1: Point = g * &s; /// // Point multiplication: /// let g: Point = g.to_point(); -/// let p2: PointZ = g * &s; -/// // Result will be the same, but generator multiplication is usually faster. -/// // Plus, generator multiplication produces `Point` instead of `PointZ` -/// assert_eq!(PointZ::from(p1), p2); +/// let p2: Point = g * &s; +/// // Result will be the same, but generator multiplication is usually faster +/// assert_eq!(p1, p2); /// ``` pub struct Generator { _ph: PhantomData<&'static E::Point>, @@ -467,7 +468,7 @@ impl Clone for Generator { impl Copy for Generator {} -/// Reference on elliptic point, _guaranteed_ to be non-zero +/// Reference on elliptic point of [group order](Scalar::group_order) /// /// Holds internally a reference on [`Point`](Point), refer to its documentation to learn /// more about Point/PointRef guarantees, security notes, and arithmetics. @@ -516,30 +517,6 @@ where .expect("Point guaranteed to have coordinates") } - /// Adds two points, returns the result, or `None` if resulting point is at infinity - pub fn add_checked(&self, point: Self) -> Result, ZeroPointError> { - let new_point = self.as_raw().add_point(point.as_raw()); - Point::from_raw(new_point) - } - - /// Substrates two points, returns the result, or `None` if resulting point is at infinity - pub fn sub_checked(&self, point: Self) -> Result, ZeroPointError> { - let new_point = self.as_raw().sub_point(point.as_raw()); - Point::from_raw(new_point) - } - - /// Multiplies a point at scalar, returns the result, or `None` if resulting point is at infinity - pub fn mul_checked_z(&self, scalar: &ScalarZ) -> Result, ZeroPointError> { - let new_point = self.as_raw().scalar_mul(scalar.as_raw()); - Point::from_raw(new_point) - } - - /// Multiplies a point at nonzero scalar, returns the result, or `None` if resulting point is at infinity - pub fn mul_checked(&self, scalar: &Scalar) -> Result, ZeroPointError> { - let new_point = self.as_raw().scalar_mul(scalar.as_raw()); - Point::from_raw(new_point) - } - /// Serializes point into (un)compressed form pub fn to_bytes(&self, compressed: bool) -> Vec { self.as_raw() @@ -549,15 +526,17 @@ where /// Clones the referenced point pub fn to_point(&self) -> Point { - // Safety: `self` is guaranteed to be non-zero + // Safety: `self` is guaranteed to have order = group_order unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } } - fn from_raw(raw_point: &'p E::Point) -> Option { + fn from_raw(raw_point: &'p E::Point) -> Result { if raw_point.is_zero() { - None + Err(InvalidPoint::ZeroPoint) + } else if !raw_point.check_point_order_equals_group_order() { + Err(InvalidPoint::MismatchedPointOrder) } else { - Some(Self { raw_point }) + Ok(Self { raw_point }) } } @@ -640,20 +619,28 @@ impl fmt::Display for ZeroScalarError { impl std::error::Error for ZeroScalarError {} +#[derive(Error, Debug)] +pub enum InvalidPoint { + #[error("x,y correspond to zero point")] + ZeroPoint, + #[error("{}", MismatchedPointOrder(()))] + MismatchedPointOrder, +} + /// Constructing Point from its coordinates error #[derive(Debug, Error)] pub enum PointFromCoordsError { - #[error("x,y correspond to zero point")] - ZeroPoint, - #[error("point is not on the curve")] + #[error("invalid point ({0})")] + InvalidPoint(InvalidPoint), + #[error("{}", NotOnCurve)] PointNotOnCurve, } /// Constructing Point from its (un)compressed representation error #[derive(Debug, Error)] pub enum PointFromBytesError { - #[error("deserialized point corresponds to zero point")] - ZeroPoint, + #[error("invalid point ({0})")] + InvalidPoint(InvalidPoint), #[error("{0}")] Deserialize(#[source] DeserializationError), } @@ -668,15 +655,15 @@ pub enum PointFromBytesError { /// /// ## Guarantees /// -/// * Belongs to the curve prime field +/// * Modulus group order /// -/// Denoting [curve order](Self::curve_order) as `n`, any instance `s` of `ScalarZ` is guaranteed +/// Denoting [group order](Self::group_order) as `n`, any instance `s` of `ScalarZ` is guaranteed /// to be non-negative integer modulo `n`: `0 <= s < n` /// /// ## Arithmetics /// /// Supported operations: -/// * Unary: you can [invert](Self::invert) and negate a scalar by modulo of prime field +/// * Unary: you can [invert](Self::invert) and negate a scalar /// * Binary: you can add, subtract, and multiply two points /// /// ### Example @@ -829,7 +816,7 @@ impl From for ScalarZ { /// /// * Belongs to the curve prime field /// -/// Denoting curve order as `n`, any instance `s` of `Scalar` is guaranteed to be less than `q`: +/// Denoting group order as `n`, any instance `s` of `Scalar` is guaranteed to be less than `n`: /// `s < n` /// * Not a zero /// @@ -843,25 +830,25 @@ impl From for ScalarZ { /// * Unary: you can [invert](Self::invert) and negate a scalar by modulo of prime field /// * Binary: you can add, subtract, and multiply two points /// -/// Addition, subtraction, or multiplication of two (even non-zero) scalars might result into zero +/// Addition or subtraction of two (even non-zero) scalars might result into zero /// scalar, so these operations output [ScalarZ]. Use [ensure_nonzero](ScalarZ::ensure_nonzero) method -/// to ensure that computation doesn't produce zero scalar; +/// to ensure that computation doesn't produce zero scalar: /// /// ```rust /// # use curv::elliptic::curves::{ScalarZ, Scalar, Secp256k1}; /// let a = Scalar::::random(); /// let b = Scalar::::random(); -/// let result: ScalarZ = a * b; +/// let result: ScalarZ = a + b; /// let non_zero_result: Option> = result.ensure_nonzero(); /// ``` /// -/// When evaluating complex expressions, you typically need to ensure that none of intermediate -/// results are zero scalars: +/// Multiplication of two nonzero scalars is always nonzero scalar (as scalar is by prime modulo): +/// /// ```rust -/// # use curv::elliptic::curves::{Scalar, Secp256k1}; -/// fn expression(a: Scalar, b: Scalar, c: Scalar) -> Option> { -/// (a + (b * c).ensure_nonzero()?).ensure_nonzero() -/// } +/// # use curv::elliptic::curves::{ScalarZ, Scalar, Secp256k1}; +/// let a = Scalar::::random(); +/// let b = Scalar::::random(); +/// let result: Scalar = a * b; /// ``` #[derive(Serialize, Deserialize)] #[serde(try_from = "ScalarFormat", into = "ScalarFormat", bound = "")] @@ -891,7 +878,7 @@ impl Scalar { } /// Returns a curve order - pub fn curve_order() -> &'static BigInt { + pub fn group_order() -> &'static BigInt { E::Scalar::group_order() } @@ -905,24 +892,6 @@ impl Scalar { Self::from_raw(E::Scalar::from_bigint(n)) } - /// Adds two scalars, returns the result by modulo `q`, or `None` if resulting scalar is zero - pub fn add_checked(&self, scalar: &Scalar) -> Result { - let scalar = self.as_raw().add(scalar.as_raw()); - Self::from_raw(scalar) - } - - /// Subtracts two scalars, returns the result by modulo `q`, or `None` if resulting scalar is zero - pub fn sub_checked(&self, scalar: &Scalar) -> Result { - let scalar = self.as_raw().sub(scalar.as_raw()); - Self::from_raw(scalar) - } - - /// Multiplies two scalars, returns the result by modulo `q`, or `None` if resulting scalar is zero - pub fn mul_checked(&self, scalar: &Scalar) -> Result { - let scalar = self.as_raw().mul(scalar.as_raw()); - Self::from_raw(scalar) - } - fn from_raw(raw_scalar: E::Scalar) -> Result { if raw_scalar.is_zero() { Err(ZeroScalarError(())) @@ -1135,11 +1104,24 @@ macro_rules! matrix { }; } +#[cfg(not(release))] +fn addition_of_two_points(result: E::Point) -> PointZ { + // In non-release environment we check that every addition results into correct point (either + // zero or of the expected order) + PointZ::from_raw(result) + .expect("addition of two points must be either a zero or of the same order") +} +#[cfg(release)] +fn addition_of_two_points(result: E::Point) -> PointZ { + // In release we skip checks + PointZ::from_raw_unchecked(result) +} + matrix! { trait = Add, trait_fn = add, output = PointZ, - output_new = PointZ::from_raw, + output_new = addition_of_two_points, point_fn = add_point, point_assign_fn = add_point_assign, pairs = { @@ -1169,11 +1151,24 @@ matrix! { } } +#[cfg(not(release))] +fn subtraction_of_two_point(result: E::Point) -> PointZ { + // In non-release environment we check that every subtraction results into correct point (either + // zero or of the expected order) + PointZ::from_raw(result) + .expect("subtraction of two points must be either a zero or of the same order") +} +#[cfg(release)] +fn subtraction_of_two_point(result: E::Point) -> PointZ { + // In release we skip checks + PointZ::from_raw_unchecked(result) +} + matrix! { trait = Sub, trait_fn = sub, output = PointZ, - output_new = PointZ::from_raw, + output_new = subtraction_of_two_point, point_fn = sub_point, point_assign_fn = sub_point_assign, pairs = { @@ -1203,25 +1198,72 @@ matrix! { } } +#[cfg(not(release))] +fn multiplication_of_nonzero_point_at_nonzero_scalar(result: E::Point) -> Point { + Point::from_raw(result) + .expect("multiplication of point at non-zero scalar must always produce a non-zero point of the same order") +} +#[cfg(release)] +fn multiplication_of_point_at_nonzero_scalar(result: E::Point) -> Point { + Point::from_raw_unchecked(result) +} + matrix! { trait = Mul, trait_fn = mul, - output = PointZ, - output_new = PointZ::from_raw, + output = Point, + output_new = multiplication_of_nonzero_point_at_nonzero_scalar, point_fn = scalar_mul, point_assign_fn = scalar_mul_assign, pairs = { - (_o<> Scalar, Point), (_o<> Scalar, PointZ), - (_r<> Scalar, &Point), (_r<> Scalar, &PointZ), + (_o<> Scalar, Point), + (_r<> Scalar, &Point), (_r<'p> Scalar, PointRef<'p, E>), + (_o<> &Scalar, Point), + (_r<> &Scalar, &Point), + (_r<'p> &Scalar, PointRef<'p, E>), + + // --- and vice-versa --- + + (o_<> Point, Scalar), + (o_<> Point, &Scalar), + + (r_<> &Point, Scalar), + (r_<> &Point, &Scalar), + + (r_<'p> PointRef<'p, E>, Scalar), + (r_<'p> PointRef<'p, E>, &Scalar), + } +} + +#[cfg(not(release))] +fn multiplication_of_point_at_scalar(result: E::Point) -> PointZ { + PointZ::from_raw(result) + .expect("multiplication of point at scalar must always produce either a point of the same order or a zero point") +} +#[cfg(release)] +fn multiplication_of_point_at_scalar(result: E::Point) -> PointZ { + PointZ::from_raw_unchecked(result) +} + +matrix! { + trait = Mul, + trait_fn = mul, + output = PointZ, + output_new = multiplication_of_point_at_scalar, + point_fn = scalar_mul, + point_assign_fn = scalar_mul_assign, + pairs = { + (_o<> Scalar, PointZ), + (_r<> Scalar, &PointZ), + (_o<> ScalarZ, Point), (_o<> ScalarZ, PointZ), (_r<> ScalarZ, &Point), (_r<> ScalarZ, &PointZ), (_r<'p> ScalarZ, PointRef<'p, E>), - (_o<> &Scalar, Point), (_o<> &Scalar, PointZ), - (_r<> &Scalar, &Point), (_r<> &Scalar, &PointZ), - (_r<'p> &Scalar, PointRef<'p, E>), + (_o<> &Scalar, PointZ), + (_r<> &Scalar, &PointZ), (_o<> &ScalarZ, Point), (_o<> &ScalarZ, PointZ), (_r<> &ScalarZ, &Point), (_r<> &ScalarZ, &PointZ), @@ -1229,20 +1271,20 @@ matrix! { // --- and vice-versa --- - (o_<> Point, Scalar), (o_<> Point, ScalarZ), - (o_<> Point, &Scalar), (o_<> Point, &ScalarZ), + (o_<> Point, ScalarZ), + (o_<> Point, &ScalarZ), (o_<> PointZ, Scalar), (o_<> PointZ, ScalarZ), (o_<> PointZ, &Scalar), (o_<> PointZ, &ScalarZ), - (r_<> &Point, Scalar), (r_<> &Point, ScalarZ), - (r_<> &Point, &Scalar), (r_<> &Point, &ScalarZ), + (r_<> &Point, ScalarZ), + (r_<> &Point, &ScalarZ), (r_<> &PointZ, Scalar), (r_<> &PointZ, ScalarZ), (r_<> &PointZ, &Scalar), (r_<> &PointZ, &ScalarZ), - (r_<'p> PointRef<'p, E>, Scalar), (r_<'p> PointRef<'p, E>, ScalarZ), - (r_<'p> PointRef<'p, E>, &Scalar), (r_<'p> PointRef<'p, E>, &ScalarZ), + (r_<'p> PointRef<'p, E>, ScalarZ), + (r_<'p> PointRef<'p, E>, &ScalarZ), } } @@ -1292,22 +1334,42 @@ matrix! { point_fn = mul, point_assign_fn = mul_assign, pairs = { - (o_<> Scalar, Scalar), (o_<> Scalar, ScalarZ), - (o_<> Scalar, &Scalar), (o_<> Scalar, &ScalarZ), + (o_<> Scalar, ScalarZ), + (o_<> Scalar, &ScalarZ), (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), - (_o<> &Scalar, Scalar), (_o<> &Scalar, ScalarZ), - (r_<> &Scalar, &Scalar), (r_<> &Scalar, &ScalarZ), + (_o<> &Scalar, ScalarZ), + (r_<> &Scalar, &ScalarZ), (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), } } +fn multiplication_of_two_nonzero_scalars(result: E::Scalar) -> Scalar { + Scalar::from_raw(result) + .expect("multiplication of two nonzero scalar by prime modulo must be nonzero") +} + +matrix! { + trait = Mul, + trait_fn = mul, + output = Scalar, + output_new = multiplication_of_two_nonzero_scalars, + point_fn = mul, + point_assign_fn = mul_assign, + pairs = { + (o_<> Scalar, Scalar), + (o_<> Scalar, &Scalar), + (_o<> &Scalar, Scalar), + (r_<> &Scalar, &Scalar), + } +} + impl ops::Mul<&Scalar> for Generator { type Output = Point; fn mul(self, rhs: &Scalar) -> Self::Output { Point::from_raw(E::Point::generator_mul(rhs.as_raw())) - .expect("generator multiplied by non-zero scalar is always non-zero point") + .expect("generator multiplied by non-zero scalar is always a point of group order") } } @@ -1336,6 +1398,7 @@ impl ops::Mul<&ScalarZ> for Generator { type Output = PointZ; fn mul(self, rhs: &ScalarZ) -> Self::Output { PointZ::from_raw(E::Point::generator_mul(rhs.as_raw())) + .expect("sG must be either a point of group order or a zero point") } } @@ -1428,7 +1491,7 @@ impl ops::Neg for PointZ { type Output = PointZ; fn neg(self) -> Self::Output { - PointZ::from_raw(self.as_raw().neg_point()) + PointZ::from_raw(self.as_raw().neg_point()).expect("negated point must have the same order") } } @@ -1436,7 +1499,7 @@ impl ops::Neg for &PointZ { type Output = PointZ; fn neg(self) -> Self::Output { - PointZ::from_raw(self.as_raw().neg_point()) + PointZ::from_raw(self.as_raw().neg_point()).expect("negated point must have the same order") } } @@ -1466,8 +1529,13 @@ impl TryFrom> for PointZ { } match parsed.point { None => Ok(PointZ::zero()), - Some(coords) => PointZ::from_coords(&coords.x, &coords.y) - .map_err(|_: NotOnCurve| ConvertParsedPointError::NotOnCurve), + Some(coords) => match PointZ::from_coords(&coords.x, &coords.y) { + Ok(p) => Ok(p), + Err(PointZFromCoordsError::NotOnCurve) => Err(ConvertParsedPointError::NotOnCurve), + Err(PointZFromCoordsError::InvalidPoint(MismatchedPointOrder(()))) => Err( + ConvertParsedPointError::InvalidPoint(InvalidPoint::MismatchedPointOrder), + ), + }, } } } @@ -1492,13 +1560,17 @@ impl TryFrom> for Point { }); } match parsed.point { - None => Err(ConvertParsedPointError::ZeroPoint), + None => Err(ConvertParsedPointError::InvalidPoint( + InvalidPoint::ZeroPoint, + )), Some(coords) => match Point::from_coords(&coords.x, &coords.y) { Ok(p) => Ok(p), Err(PointFromCoordsError::PointNotOnCurve) => { Err(ConvertParsedPointError::NotOnCurve) } - Err(PointFromCoordsError::ZeroPoint) => Err(ConvertParsedPointError::ZeroPoint), + Err(PointFromCoordsError::InvalidPoint(reason)) => { + Err(ConvertParsedPointError::InvalidPoint(reason)) + } }, } } @@ -1516,8 +1588,8 @@ impl From> for PointFormat { #[derive(Debug, Error)] enum ConvertParsedPointError { - #[error("point must not be zero")] - ZeroPoint, + #[error("invalid point ({0})")] + InvalidPoint(InvalidPoint), #[error("expected point of curve {expected}, but got point of curve {got}")] MismatchedCurve { got: Cow<'static, str>, @@ -1725,36 +1797,37 @@ mod test { fn test_point_multiplication_defined() { fn _curve() { assert_operator_defined_for! { - assert_fn = assert_point_multiplication_defined, - lhs = {Point, PointZ, &Point, &PointZ, PointRef}, - rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + assert_fn = assert_point_nonzero_multiplication_defined, + lhs = {Point, &Point, PointRef}, + rhs = {Scalar, &Scalar}, } assert_operator_defined_for! { assert_fn = assert_point_multiplication_defined, - lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - rhs = {Point, PointZ, &Point, &PointZ, PointRef}, + lhs = {Point, &Point, PointRef}, + rhs = {ScalarZ, &ScalarZ}, } - - // Checking generator's arithmetic assert_operator_defined_for! { assert_fn = assert_point_multiplication_defined, - lhs = {Generator}, - rhs = {ScalarZ, &ScalarZ}, + lhs = {PointZ, &PointZ}, + rhs = {Scalar, &Scalar, ScalarZ, &ScalarZ}, } + + // and vice-versa + assert_operator_defined_for! { assert_fn = assert_point_nonzero_multiplication_defined, - lhs = {Generator}, - rhs = {Scalar, &Scalar}, + lhs = {Scalar, &Scalar}, + rhs = {Point, &Point, PointRef}, } assert_operator_defined_for! { assert_fn = assert_point_multiplication_defined, lhs = {ScalarZ, &ScalarZ}, - rhs = {Generator}, + rhs = {Point, &Point, PointRef}, } assert_operator_defined_for! { - assert_fn = assert_point_nonzero_multiplication_defined, - lhs = {Scalar, &Scalar}, - rhs = {Generator}, + assert_fn = assert_point_multiplication_defined, + lhs = {Scalar, &Scalar, ScalarZ, &ScalarZ}, + rhs = {PointZ, &PointZ}, } } } @@ -1814,14 +1887,35 @@ mod test { // no-op } + /// Function asserts that S1 can be multiplied by S2 (ie. S1 * S2) and result is Scalar. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_nonzero_scalars_multiplication_defined() + where + S1: ops::Mul>, + E: Curve, + { + // no-op + } + #[test] fn test_scalars_multiplication_defined() { fn _curve() { assert_operator_defined_for! { assert_fn = assert_scalars_multiplication_defined, - lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + lhs = {ScalarZ, &ScalarZ}, rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, } + assert_operator_defined_for! { + assert_fn = assert_scalars_multiplication_defined, + lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + rhs = {ScalarZ, &ScalarZ}, + } + assert_operator_defined_for! { + assert_fn = assert_nonzero_scalars_multiplication_defined, + lhs = {Scalar, &Scalar}, + rhs = {Scalar, &Scalar}, + } } } } From c419d837f9481119fed390586843ced252257699 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 13:34:44 +0300 Subject: [PATCH 34/93] Split a large wrappers module into several files --- src/elliptic/curves/mod.rs | 15 +- src/elliptic/curves/wrappers.rs | 1921 -------------------- src/elliptic/curves/wrappers/arithmetic.rs | 758 ++++++++ src/elliptic/curves/wrappers/error.rs | 75 + src/elliptic/curves/wrappers/format.rs | 202 ++ src/elliptic/curves/wrappers/generator.rs | 77 + src/elliptic/curves/wrappers/mod.rs | 14 + src/elliptic/curves/wrappers/point.rs | 202 ++ src/elliptic/curves/wrappers/point_ref.rs | 133 ++ src/elliptic/curves/wrappers/point_z.rs | 191 ++ src/elliptic/curves/wrappers/scalar.rs | 185 ++ src/elliptic/curves/wrappers/scalar_z.rs | 167 ++ 12 files changed, 2018 insertions(+), 1922 deletions(-) delete mode 100644 src/elliptic/curves/wrappers.rs create mode 100644 src/elliptic/curves/wrappers/arithmetic.rs create mode 100644 src/elliptic/curves/wrappers/error.rs create mode 100644 src/elliptic/curves/wrappers/format.rs create mode 100644 src/elliptic/curves/wrappers/generator.rs create mode 100644 src/elliptic/curves/wrappers/mod.rs create mode 100644 src/elliptic/curves/wrappers/point.rs create mode 100644 src/elliptic/curves/wrappers/point_ref.rs create mode 100644 src/elliptic/curves/wrappers/point_z.rs create mode 100644 src/elliptic/curves/wrappers/scalar.rs create mode 100644 src/elliptic/curves/wrappers/scalar_z.rs diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index 2b3d2375..baad6482 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -8,4 +8,17 @@ mod traits; mod wrappers; pub use self::secp256_k1::Secp256k1; -pub use self::{traits::*, wrappers::*}; +pub use self::{ + traits::{Curve, ECPoint, ECScalar}, + wrappers::{Generator, Point, PointRef, PointZ, Scalar, ScalarZ}, +}; + +pub mod error { + pub use super::{ + traits::{DeserializationError, NotOnCurve}, + wrappers::error::*, + }; +} + +#[doc(no_inline)] +pub use self::error::*; diff --git a/src/elliptic/curves/wrappers.rs b/src/elliptic/curves/wrappers.rs deleted file mode 100644 index dda7eb82..00000000 --- a/src/elliptic/curves/wrappers.rs +++ /dev/null @@ -1,1921 +0,0 @@ -use std::borrow::Cow; -use std::convert::TryFrom; -use std::marker::PhantomData; -use std::{fmt, iter, ops}; - -use serde::{Deserialize, Serialize}; -use thiserror::Error; - -use super::traits::*; -use crate::arithmetic::{BigInt, Converter}; - -/// Either an elliptic point of a [group order](Scalar::group_order), or a zero point -/// -/// ## Security -/// -/// Mistakenly used zero point might break security of cryptographic algorithm. It's preferred to -/// use [`Point`](Point) that's guaranteed to be non-zero. Use [ensure_nonzero](PointZ::ensure_nonzero) -/// to convert `PointZ` into `Point`. -/// -/// ## Guarantees -/// -/// * On curve -/// -/// Any instance of `PointZ` is guaranteed to belong to curve `E`, i.e. its coordinates must -/// satisfy curve equations -/// * Point order equals to [group order](Scalar::group_order) (unless it's zero point) -/// -/// I.e. denoting `q = group_order`, following predicate is always true: -/// `P = O ∨ qP = O ∧ forall 0 < s < q. sP ≠ O` -/// -/// ## Arithmetics -/// -/// You can add, subtract two points, or multiply point at scalar: -/// -/// ```rust -/// # use curv::elliptic::curves::{PointZ, Scalar, Secp256k1}; -/// fn expression( -/// a: PointZ, -/// b: PointZ, -/// c: Scalar, -/// ) -> PointZ { -/// a + b * c -/// } -/// ``` -#[derive(Serialize, Deserialize)] -#[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] -pub struct PointZ { - raw_point: E::Point, -} - -impl PointZ { - /// Checks if `self` is not zero and converts it into [`Point`](Point). Returns `None` if - /// it's zero. - pub fn ensure_nonzero(self) -> Option> { - Point::try_from(self).ok() - } - - /// Constructs zero point - /// - /// Zero point (or curve neutral element) is usually denoted as `O`. Its property: `forall A. A + O = A`. - /// - /// Weierstrass and Montgomery curves employ special "point at infinity" that represent a neutral - /// element, such points don't have coordinates (i.e. [from_coords], [x_coord], [y_coord] return - /// `None`). Edwards curves' neutral element has coordinates. - /// - /// [from_coords]: Self::from_coords - /// [x_coord]: Self::x_coord - /// [y_coord]: Self::y_coord - pub fn zero() -> Self { - // Safety: `self` can be constructed to hold a zero point - unsafe { Self::from_raw_unchecked(E::Point::zero()) } - } - - /// Checks whether point is zero - pub fn is_zero(&self) -> bool { - self.as_raw().is_zero() - } - - /// Returns point coordinates - /// - /// Point might not have coordinates (specifically, "point at infinity" doesn't), in this case - /// `None` is returned - pub fn coords(&self) -> Option { - self.as_raw().coords() - } - - /// Returns point x coordinate - /// - /// See [coords](Self::coords) method that retrieves both x and y at once. - pub fn x_coord(&self) -> Option { - self.as_raw().x_coord() - } - - /// Returns point y coordinate - /// - /// See [coords](Self::coords) method that retrieves both x and y at once. - pub fn y_coord(&self) -> Option { - self.as_raw().y_coord() - } - - /// Constructs a point from its coordinates, returns error if coordinates don't satisfy - /// curve equation or if point has invalid order - pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { - let raw_point = E::Point::from_coords(x, y) - .map_err(|_: NotOnCurve| PointZFromCoordsError::NotOnCurve)?; - Self::from_raw(raw_point).map_err(PointZFromCoordsError::InvalidPoint) - } - - /// Tries to parse a point in (un)compressed form - /// - /// Whether it's in compressed or uncompressed form will be deduced from its length - pub fn from_bytes(bytes: &[u8]) -> Result { - let p = E::Point::deserialize(bytes) - .map_err(|_: DeserializationError| PointZDeserializationError::DeserializationError)?; - Self::from_raw(p).map_err(PointZDeserializationError::InvalidPoint) - } - - /// Serializes a point in (un)compressed form - /// - /// Returns `None` if it's point at infinity - pub fn to_bytes(&self, compressed: bool) -> Option> { - self.as_raw().serialize(compressed) - } - - fn from_raw(raw_point: E::Point) -> Result { - if raw_point.is_zero() || raw_point.check_point_order_equals_group_order() { - Ok(Self { raw_point }) - } else { - Err(MismatchedPointOrder(())) - } - } - - unsafe fn from_raw_unchecked(raw_point: E::Point) -> Self { - Self { raw_point } - } - - fn as_raw(&self) -> &E::Point { - &self.raw_point - } - - fn into_raw(self) -> E::Point { - self.raw_point - } -} - -impl PartialEq for PointZ { - fn eq(&self, other: &Self) -> bool { - self.raw_point.eq(&other.raw_point) - } -} - -impl PartialEq> for PointZ { - fn eq(&self, other: &Point) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl<'p, E: Curve> PartialEq> for PointZ { - fn eq(&self, other: &PointRef<'p, E>) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl PartialEq> for PointZ { - fn eq(&self, other: &Generator) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl Clone for PointZ { - fn clone(&self) -> Self { - // Safety: self is guaranteed to have correct order - unsafe { PointZ::from_raw_unchecked(self.as_raw().clone()) } - } -} - -impl fmt::Debug for PointZ { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.raw_point.fmt(f) - } -} - -impl From> for PointZ { - fn from(p: Point) -> Self { - // Safety: `Point` is guaranteed to have correct order - unsafe { PointZ::from_raw_unchecked(p.into_raw()) } - } -} - -#[derive(Debug, Error, Clone, PartialEq)] -#[error("invalid point (point order ≠ group order)")] -pub struct MismatchedPointOrder(()); - -#[derive(Debug, Error)] -pub enum PointZDeserializationError { - #[error("failed to deserialize the point")] - DeserializationError, - #[error("invalid point ({0})")] - InvalidPoint(MismatchedPointOrder), -} - -#[derive(Debug, Error)] -pub enum PointZFromCoordsError { - #[error("{}", NotOnCurve)] - NotOnCurve, - #[error("invalid point ({0})")] - InvalidPoint(MismatchedPointOrder), -} - -/// Elliptic point of [group order](Scalar::group_order) -/// -/// ## Guarantees -/// -/// * On curve -/// -/// Any instance of `Point` is guaranteed to belong to curve `E`, i.e. its coordinates must -/// satisfy curve equations -/// * Point order equals to [group order](Scalar::group_order) -/// -/// I.e. denoting `q = group_order`, following predicate is always true: -/// `qP = O ∧ forall 0 < s < q. sP ≠ O` -/// -/// Note that this also means that `Point` cannot be zero (zero point has `order=1`), -/// ie. `forall a b. a: PointZ ∧ b: Point → a + b ≢ a`. It also implies that `Point` is -/// guaranteed to have coordinates (only point at infinity doesn't). -/// -/// ## Arithmetics -/// -/// You can add, subtract two points, or multiply point at scalar. -/// -/// Addition or subtraction of two points might result into zero point, so these operators output -/// [`PointZ`](PointZ) that allowed to be zero. -/// -/// ```rust -/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; -/// let p1: Point = -/// Point::generator() * Scalar::random(); // Non-zero point -/// let p2: Point = -/// Point::generator() * Scalar::random(); // Non-zero point -/// let result: PointZ = p1 + p2; // Addition of two (even non-zero) -/// // points might produce zero point -/// let nonzero_result: Option> = result.ensure_nonzero(); -/// ``` -/// -/// Multiplying point at non-zero scalar is guaranteed to be non-zero (as point order is known -/// to be equal to group order, and scalar is known to be less then group order): -/// -/// ```rust -/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; -/// let s = Scalar::::random(); // Non-zero scalar -/// let g = Point::::generator(); // Curve generator -/// let result: Point = s * g; // Generator multiplied at non-zero scalar is -/// // always a non-zero point -/// ``` -#[derive(Serialize, Deserialize)] -#[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] -pub struct Point { - raw_point: E::Point, -} - -impl Point { - /// Curve generator - /// - /// Returns a static reference on actual value because in most cases referenced value is fine. - /// Use [`.to_point()`](Generator::to_point) if you need to take it by value. - pub fn generator() -> Generator { - Generator::default() - } - - /// Curve second generator - /// - /// We provide an alternative generator value and prove that it was picked randomly. - /// - /// Returns a static reference on actual value because in most cases referenced value is fine. - /// Use [`.to_point()`](PointRef::to_point) if you need to take it by value. - pub fn base_point2() -> PointRef<'static, E> { - let p = E::Point::base_point2(); - PointRef::from_raw(p).expect("base_point2 must have correct order") - } - - /// Constructs a point from coordinates, returns error if x,y don't satisfy curve equation or - /// correspond to zero point - pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { - let p = E::Point::from_coords(x, y) - .map_err(|NotOnCurve { .. }| PointFromCoordsError::PointNotOnCurve)?; - Self::from_raw(p).map_err(PointFromCoordsError::InvalidPoint) - } - - /// Tries to parse a point from its (un)compressed form - /// - /// Whether it's a compressed or uncompressed form will be deduced from its length - pub fn from_bytes(bytes: &[u8]) -> Result { - let p = E::Point::deserialize(bytes).map_err(PointFromBytesError::Deserialize)?; - Self::from_raw(p).map_err(PointFromBytesError::InvalidPoint) - } - - /// Returns point coordinates (`x` and `y`) - /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn coords(&self) -> PointCoords { - self.as_point().coords() - } - - /// Returns `x` coordinate of point - /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn x_coord(&self) -> BigInt { - self.as_point().x_coord() - } - - /// Returns `y` coordinate of point - /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn y_coord(&self) -> BigInt { - self.as_point().y_coord() - } - - /// Serializes point into (un)compressed form - pub fn to_bytes(&self, compressed: bool) -> Vec { - self.as_point().to_bytes(compressed) - } - - /// Creates [PointRef] that holds a reference on `self` - pub fn as_point(&self) -> PointRef { - PointRef::from(self) - } - - fn from_raw(raw_point: E::Point) -> Result { - if raw_point.is_zero() { - Err(InvalidPoint::ZeroPoint) - } else if !raw_point.check_point_order_equals_group_order() { - Err(InvalidPoint::MismatchedPointOrder) - } else { - Ok(Point { raw_point }) - } - } - - unsafe fn from_raw_unchecked(point: E::Point) -> Self { - Point { raw_point: point } - } - - fn as_raw(&self) -> &E::Point { - &self.raw_point - } - - fn into_raw(self) -> E::Point { - self.raw_point - } -} - -impl PartialEq for Point { - fn eq(&self, other: &Self) -> bool { - self.as_raw().eq(&other.as_raw()) - } -} - -impl PartialEq> for Point { - fn eq(&self, other: &PointZ) -> bool { - self.as_raw().eq(&other.as_raw()) - } -} - -impl<'p, E: Curve> PartialEq> for Point { - fn eq(&self, other: &PointRef<'p, E>) -> bool { - self.as_raw().eq(&other.as_raw()) - } -} - -impl PartialEq> for Point { - fn eq(&self, other: &Generator) -> bool { - self.as_raw().eq(&other.as_raw()) - } -} - -impl Clone for Point { - fn clone(&self) -> Self { - // Safety: `self` is guaranteed to be non-zero - unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } - } -} - -impl fmt::Debug for Point { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.as_raw().fmt(f) - } -} - -impl TryFrom> for Point { - type Error = ZeroPointError; - fn try_from(point: PointZ) -> Result { - match Self::from_raw(point.into_raw()) { - Ok(p) => Ok(p), - Err(InvalidPoint::ZeroPoint) => Err(ZeroPointError(())), - Err(InvalidPoint::MismatchedPointOrder) => panic!("Point must have correct order"), - } - } -} - -/// Elliptic curve generator -/// -/// Holds internally a static reference on curve generator. Can be used in arithmetic interchangeably -/// as [`PointRef`](PointRef). -/// -/// You can convert the generator into `Point` and `PointRef` using -/// [`to_point`](Self::to_point) and [`as_point`](Self::as_point) -/// methods respectively. -/// -/// ## Example -/// -/// ```rust -/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; -/// let s = Scalar::::random(); // Non-zero scalar -/// let g = Point::::generator(); // Curve generator -/// let result: Point = s * g; // Generator multiplied at non-zero scalar is -/// // always a non-zero point -/// ``` -/// -/// ## Performance -/// -/// Generator multiplication is often more efficient than regular point multiplication, so avoid -/// converting generator into the `Point` as long as it's possible: -/// -/// ```rust -/// # use curv::elliptic::curves::{Point, Scalar, Secp256k1, Generator, PointZ}; -/// let s: Scalar = Scalar::random(); -/// // Generator multiplication: -/// let g: Generator = Point::generator(); -/// let p1: Point = g * &s; -/// // Point multiplication: -/// let g: Point = g.to_point(); -/// let p2: Point = g * &s; -/// // Result will be the same, but generator multiplication is usually faster -/// assert_eq!(p1, p2); -/// ``` -pub struct Generator { - _ph: PhantomData<&'static E::Point>, -} - -impl Default for Generator { - fn default() -> Self { - Self { _ph: PhantomData } - } -} - -impl Generator { - fn as_raw(self) -> &'static E::Point { - E::Point::generator() - } - - /// Clones generator point, returns `Point` - pub fn to_point(self) -> Point { - // Safety: curve generator must be non-zero point, otherwise nothing will work at all - unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } - } - - /// Converts generator into `PointRef` - pub fn as_point(self) -> PointRef<'static, E> { - // Safety: curve generator must be non-zero point, otherwise nothing will work at all - unsafe { PointRef::from_raw_unchecked(self.as_raw()) } - } -} - -impl Clone for Generator { - fn clone(&self) -> Self { - Self { _ph: PhantomData } - } -} - -impl Copy for Generator {} - -/// Reference on elliptic point of [group order](Scalar::group_order) -/// -/// Holds internally a reference on [`Point`](Point), refer to its documentation to learn -/// more about Point/PointRef guarantees, security notes, and arithmetics. -pub struct PointRef<'p, E: Curve> { - raw_point: &'p E::Point, -} - -impl PointRef<'static, E> { - pub fn generator() -> Self { - Self::from_raw(E::Point::generator()).expect("generator must be non-zero") - } - - pub fn base_point2() -> Self { - Self::from_raw(E::Point::base_point2()).expect("base_point2 must be non-zero") - } -} - -impl<'p, E> PointRef<'p, E> -where - E: Curve, -{ - /// Returns point coordinates (`x` and `y`) - /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn coords(&self) -> PointCoords { - self.as_raw() - .coords() - .expect("Point guaranteed to have coordinates") - } - - /// Returns `x` coordinate of point - /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn x_coord(&self) -> BigInt { - self.as_raw() - .x_coord() - .expect("Point guaranteed to have coordinates") - } - - /// Returns `y` coordinate of point - /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn y_coord(&self) -> BigInt { - self.as_raw() - .y_coord() - .expect("Point guaranteed to have coordinates") - } - - /// Serializes point into (un)compressed form - pub fn to_bytes(&self, compressed: bool) -> Vec { - self.as_raw() - .serialize(compressed) - .expect("non-zero point must always be serializable") - } - - /// Clones the referenced point - pub fn to_point(&self) -> Point { - // Safety: `self` is guaranteed to have order = group_order - unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } - } - - fn from_raw(raw_point: &'p E::Point) -> Result { - if raw_point.is_zero() { - Err(InvalidPoint::ZeroPoint) - } else if !raw_point.check_point_order_equals_group_order() { - Err(InvalidPoint::MismatchedPointOrder) - } else { - Ok(Self { raw_point }) - } - } - - unsafe fn from_raw_unchecked(raw_point: &'p E::Point) -> Self { - PointRef { raw_point } - } - - fn as_raw(self) -> &'p E::Point { - self.raw_point - } -} - -impl<'p, E: Curve> Clone for PointRef<'p, E> { - fn clone(&self) -> Self { - // Safety: `self` is guaranteed to be non-zero - unsafe { Self::from_raw_unchecked(self.as_raw()) } - } -} - -impl<'p, E: Curve> Copy for PointRef<'p, E> {} - -impl<'p, E: Curve> fmt::Debug for PointRef<'p, E> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.as_raw().fmt(f) - } -} - -impl<'p, E: Curve> From<&'p Point> for PointRef<'p, E> { - fn from(point: &'p Point) -> Self { - // Safety: `point` is guaranteed to be non-zero - unsafe { PointRef::from_raw_unchecked(point.as_raw()) } - } -} - -impl<'p, E: Curve> PartialEq for PointRef<'p, E> { - fn eq(&self, other: &Self) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { - fn eq(&self, other: &Point) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { - fn eq(&self, other: &PointZ) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { - fn eq(&self, other: &Generator) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -/// Indicates that conversion or computation failed due to occurred zero point -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct ZeroPointError(()); - -impl fmt::Display for ZeroPointError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "nonzero check failed: point is zero") - } -} - -impl std::error::Error for ZeroPointError {} - -/// Indicates that conversion or computation failed due to occurred zero scalar -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct ZeroScalarError(()); - -impl fmt::Display for ZeroScalarError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "nonzero check failed: scalar is zero") - } -} - -impl std::error::Error for ZeroScalarError {} - -#[derive(Error, Debug)] -pub enum InvalidPoint { - #[error("x,y correspond to zero point")] - ZeroPoint, - #[error("{}", MismatchedPointOrder(()))] - MismatchedPointOrder, -} - -/// Constructing Point from its coordinates error -#[derive(Debug, Error)] -pub enum PointFromCoordsError { - #[error("invalid point ({0})")] - InvalidPoint(InvalidPoint), - #[error("{}", NotOnCurve)] - PointNotOnCurve, -} - -/// Constructing Point from its (un)compressed representation error -#[derive(Debug, Error)] -pub enum PointFromBytesError { - #[error("invalid point ({0})")] - InvalidPoint(InvalidPoint), - #[error("{0}")] - Deserialize(#[source] DeserializationError), -} - -/// Scalar value in a prime field that **might be zero** -/// -/// ## Security -/// -/// Mistakenly used zero scalar might break security of cryptographic algorithm. It's preferred to -/// use `Scalar`[Scalar] that's guaranteed to be non-zero. Use [ensure_nonzero](ScalarZ::ensure_nonzero) -/// to convert `ScalarZ` into `Scalar`. -/// -/// ## Guarantees -/// -/// * Modulus group order -/// -/// Denoting [group order](Self::group_order) as `n`, any instance `s` of `ScalarZ` is guaranteed -/// to be non-negative integer modulo `n`: `0 <= s < n` -/// -/// ## Arithmetics -/// -/// Supported operations: -/// * Unary: you can [invert](Self::invert) and negate a scalar -/// * Binary: you can add, subtract, and multiply two points -/// -/// ### Example -/// -/// ```rust -/// # use curv::elliptic::curves::{ScalarZ, Secp256k1}; -/// fn expression( -/// a: ScalarZ, -/// b: ScalarZ, -/// c: ScalarZ -/// ) -> ScalarZ { -/// a + b * c -/// } -/// ``` -#[derive(Serialize, Deserialize)] -#[serde(try_from = "ScalarFormat", into = "ScalarFormat", bound = "")] -pub struct ScalarZ { - raw_scalar: E::Scalar, -} - -impl ScalarZ { - /// Converts a scalar into [`Scalar`](ScalarZ) if it's non-zero, returns None otherwise - pub fn ensure_nonzero(self) -> Option> { - Scalar::from_raw(self.into_raw()).ok() - } - - /// Samples a random scalar - pub fn random() -> Self { - Self::from_raw(E::Scalar::random()) - } - - /// Constructs zero scalar - pub fn zero() -> Self { - Self::from_raw(E::Scalar::zero()) - } - - /// Checks if a scalar is zero - pub fn is_zero(&self) -> bool { - self.as_raw().is_zero() - } - - /// Converts a scalar to [BigInt] - pub fn to_bigint(&self) -> BigInt { - self.as_raw().to_bigint() - } - - /// Constructs a scalar `n % curve_order` from give `n` - pub fn from_bigint(n: &BigInt) -> Self { - Self::from_raw(E::Scalar::from_bigint(n)) - } - - /// Returns an order of generator point - pub fn group_order() -> &'static BigInt { - E::Scalar::group_order() - } - - /// Returns inversion `self^-1 mod curve_order`, or None if `self` is zero - pub fn invert(&self) -> Option { - self.as_raw().invert().map(Self::from_raw) - } - - fn from_raw(raw_scalar: E::Scalar) -> Self { - Self { raw_scalar } - } - - fn as_raw(&self) -> &E::Scalar { - &self.raw_scalar - } - - fn into_raw(self) -> E::Scalar { - self.raw_scalar - } -} - -impl Clone for ScalarZ { - fn clone(&self) -> Self { - Self::from_raw(self.as_raw().clone()) - } -} - -impl fmt::Debug for ScalarZ { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.as_raw().fmt(f) - } -} - -impl PartialEq for ScalarZ { - fn eq(&self, other: &Self) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl PartialEq> for ScalarZ { - fn eq(&self, other: &Scalar) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl From> for ScalarZ { - fn from(scalar: Scalar) -> Self { - ScalarZ::from_raw(scalar.into_raw()) - } -} - -impl From for ScalarZ { - fn from(n: u16) -> Self { - Self::from(&BigInt::from(n)) - } -} - -impl From for ScalarZ { - fn from(n: u32) -> Self { - Self::from(&BigInt::from(n)) - } -} - -impl From for ScalarZ { - fn from(n: u64) -> Self { - Self::from(&BigInt::from(n)) - } -} - -impl From for ScalarZ { - fn from(n: i32) -> Self { - Self::from(&BigInt::from(n)) - } -} - -impl From<&BigInt> for ScalarZ { - fn from(n: &BigInt) -> Self { - ScalarZ::from_raw(E::Scalar::from_bigint(n)) - } -} - -impl From for ScalarZ { - fn from(n: BigInt) -> Self { - Self::from(&n) - } -} - -/// Scalar value in a prime field that _guaranteed_ to be non zero -/// -/// ## Security -/// -/// Non-zero scalars are preferred to be used in cryptographic algorithms. Lack of checking whether -/// computation on field scalars results into zero scalar might lead to vulnerability. Using `Scalar` -/// ensures you and reviewers that check on scalar not being zero was made. -/// -/// ## Guarantees -/// -/// * Belongs to the curve prime field -/// -/// Denoting group order as `n`, any instance `s` of `Scalar` is guaranteed to be less than `n`: -/// `s < n` -/// * Not a zero -/// -/// Any instance `s` of `Scalar` is guaranteed to be more than zero: `s > 0` -/// -/// Combining two rules above, any instance `s` of `Scalar` is guaranteed to be: `0 < s < n`. -/// -/// ## Arithmetic -/// -/// Supported operations: -/// * Unary: you can [invert](Self::invert) and negate a scalar by modulo of prime field -/// * Binary: you can add, subtract, and multiply two points -/// -/// Addition or subtraction of two (even non-zero) scalars might result into zero -/// scalar, so these operations output [ScalarZ]. Use [ensure_nonzero](ScalarZ::ensure_nonzero) method -/// to ensure that computation doesn't produce zero scalar: -/// -/// ```rust -/// # use curv::elliptic::curves::{ScalarZ, Scalar, Secp256k1}; -/// let a = Scalar::::random(); -/// let b = Scalar::::random(); -/// let result: ScalarZ = a + b; -/// let non_zero_result: Option> = result.ensure_nonzero(); -/// ``` -/// -/// Multiplication of two nonzero scalars is always nonzero scalar (as scalar is by prime modulo): -/// -/// ```rust -/// # use curv::elliptic::curves::{ScalarZ, Scalar, Secp256k1}; -/// let a = Scalar::::random(); -/// let b = Scalar::::random(); -/// let result: Scalar = a * b; -/// ``` -#[derive(Serialize, Deserialize)] -#[serde(try_from = "ScalarFormat", into = "ScalarFormat", bound = "")] -pub struct Scalar { - raw_scalar: E::Scalar, -} - -impl Scalar { - /// Samples a random non-zero scalar - pub fn random() -> Self { - loop { - if let Some(scalar) = ScalarZ::from_raw(E::Scalar::random()).ensure_nonzero() { - break scalar; - } - } - } - - /// Returns modular multiplicative inverse of the scalar - /// - /// Inverse of non-zero scalar is always defined in a prime field, and inverted scalar is also - /// guaranteed to be non-zero. - pub fn invert(&self) -> Self { - self.as_raw() - .invert() - .map(|s| Scalar::from_raw(s).expect("inversion must be non-zero")) - .expect("non-zero scalar must have corresponding inversion") - } - - /// Returns a curve order - pub fn group_order() -> &'static BigInt { - E::Scalar::group_order() - } - - /// Converts a scalar to [BigInt] - pub fn to_bigint(&self) -> BigInt { - self.as_raw().to_bigint() - } - - /// Constructs a scalar from [BigInt] or returns error if it's zero - pub fn from_bigint(n: &BigInt) -> Result { - Self::from_raw(E::Scalar::from_bigint(n)) - } - - fn from_raw(raw_scalar: E::Scalar) -> Result { - if raw_scalar.is_zero() { - Err(ZeroScalarError(())) - } else { - Ok(Self { raw_scalar }) - } - } - - unsafe fn from_raw_unchecked(raw_scalar: E::Scalar) -> Self { - Self { raw_scalar } - } - - fn as_raw(&self) -> &E::Scalar { - &self.raw_scalar - } - - fn into_raw(self) -> E::Scalar { - self.raw_scalar - } -} - -impl Clone for Scalar { - fn clone(&self) -> Self { - // Safety: `self` is guaranteed to be non-zero - unsafe { Scalar::from_raw_unchecked(self.as_raw().clone()) } - } -} - -impl fmt::Debug for Scalar { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.as_raw().fmt(f) - } -} - -impl PartialEq for Scalar { - fn eq(&self, other: &Self) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl PartialEq> for Scalar { - fn eq(&self, other: &ScalarZ) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl TryFrom for Scalar { - type Error = ZeroScalarError; - fn try_from(n: u16) -> Result { - Self::from_bigint(&BigInt::from(n)) - } -} - -impl TryFrom for Scalar { - type Error = ZeroScalarError; - fn try_from(n: u32) -> Result { - Self::from_bigint(&BigInt::from(n)) - } -} - -impl TryFrom for Scalar { - type Error = ZeroScalarError; - fn try_from(n: u64) -> Result { - Self::from_bigint(&BigInt::from(n)) - } -} - -impl TryFrom for Scalar { - type Error = ZeroScalarError; - fn try_from(n: i32) -> Result { - Self::from_bigint(&BigInt::from(n)) - } -} - -impl TryFrom<&BigInt> for Scalar { - type Error = ZeroScalarError; - fn try_from(n: &BigInt) -> Result { - Self::from_bigint(n) - } -} - -impl TryFrom for Scalar { - type Error = ZeroScalarError; - fn try_from(n: BigInt) -> Result { - Self::from_bigint(&n) - } -} - -macro_rules! matrix { - ( - trait = $trait:ident, - trait_fn = $trait_fn:ident, - output = $output:ty, - output_new = $output_new:expr, - point_fn = $point_fn:ident, - point_assign_fn = $point_assign_fn:ident, - pairs = {(r_<$($l:lifetime),*> $lhs_ref:ty, $rhs:ty), $($rest:tt)*} - ) => { - impl<$($l,)* E: Curve> ops::$trait<$rhs> for $lhs_ref { - type Output = $output; - fn $trait_fn(self, rhs: $rhs) -> Self::Output { - let p = self.as_raw().$point_fn(rhs.as_raw()); - $output_new(p) - } - } - matrix!{ - trait = $trait, - trait_fn = $trait_fn, - output = $output, - output_new = $output_new, - point_fn = $point_fn, - point_assign_fn = $point_assign_fn, - pairs = {$($rest)*} - } - }; - - ( - trait = $trait:ident, - trait_fn = $trait_fn:ident, - output = $output:ty, - output_new = $output_new:expr, - point_fn = $point_fn:ident, - point_assign_fn = $point_assign_fn:ident, - pairs = {(_r<$($l:lifetime),*> $lhs:ty, $rhs_ref:ty), $($rest:tt)*} - ) => { - impl<$($l,)* E: Curve> ops::$trait<$rhs_ref> for $lhs { - type Output = $output; - fn $trait_fn(self, rhs: $rhs_ref) -> Self::Output { - let p = rhs.as_raw().$point_fn(self.as_raw()); - $output_new(p) - } - } - matrix!{ - trait = $trait, - trait_fn = $trait_fn, - output = $output, - output_new = $output_new, - point_fn = $point_fn, - point_assign_fn = $point_assign_fn, - pairs = {$($rest)*} - } - }; - - ( - trait = $trait:ident, - trait_fn = $trait_fn:ident, - output = $output:ty, - output_new = $output_new:expr, - point_fn = $point_fn:ident, - point_assign_fn = $point_assign_fn:ident, - pairs = {(o_<$($l:lifetime),*> $lhs_owned:ty, $rhs:ty), $($rest:tt)*} - ) => { - impl<$($l,)* E: Curve> ops::$trait<$rhs> for $lhs_owned { - type Output = $output; - fn $trait_fn(self, rhs: $rhs) -> Self::Output { - let mut raw = self.into_raw(); - raw.$point_assign_fn(rhs.as_raw()); - $output_new(raw) - } - } - matrix!{ - trait = $trait, - trait_fn = $trait_fn, - output = $output, - output_new = $output_new, - point_fn = $point_fn, - point_assign_fn = $point_assign_fn, - pairs = {$($rest)*} - } - }; - - ( - trait = $trait:ident, - trait_fn = $trait_fn:ident, - output = $output:ty, - output_new = $output_new:expr, - point_fn = $point_fn:ident, - point_assign_fn = $point_assign_fn:ident, - pairs = {(_o<$($l:lifetime),*> $lhs:ty, $rhs_owned:ty), $($rest:tt)*} - ) => { - impl<$($l,)* E: Curve> ops::$trait<$rhs_owned> for $lhs { - type Output = $output; - fn $trait_fn(self, rhs: $rhs_owned) -> Self::Output { - let mut raw = rhs.into_raw(); - raw.$point_assign_fn(self.as_raw()); - $output_new(raw) - } - } - matrix!{ - trait = $trait, - trait_fn = $trait_fn, - output = $output, - output_new = $output_new, - point_fn = $point_fn, - point_assign_fn = $point_assign_fn, - pairs = {$($rest)*} - } - }; - - ( - trait = $trait:ident, - trait_fn = $trait_fn:ident, - output = $output:ty, - output_new = $output_new:expr, - point_fn = $point_fn:ident, - point_assign_fn = $point_assign_fn:ident, - pairs = {} - ) => { - // happy termination - }; -} - -#[cfg(not(release))] -fn addition_of_two_points(result: E::Point) -> PointZ { - // In non-release environment we check that every addition results into correct point (either - // zero or of the expected order) - PointZ::from_raw(result) - .expect("addition of two points must be either a zero or of the same order") -} -#[cfg(release)] -fn addition_of_two_points(result: E::Point) -> PointZ { - // In release we skip checks - PointZ::from_raw_unchecked(result) -} - -matrix! { - trait = Add, - trait_fn = add, - output = PointZ, - output_new = addition_of_two_points, - point_fn = add_point, - point_assign_fn = add_point_assign, - pairs = { - (o_<> Point, Point), (o_<> Point, PointZ), - (o_<> Point, &Point), (o_<> Point, &PointZ), - (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), - - (o_<> PointZ, Point), (o_<> PointZ, PointZ), - (o_<> PointZ, &Point), (o_<> PointZ, &PointZ), - (o_<'p> PointZ, PointRef<'p, E>), (o_<> PointZ, Generator), - - (_o<> &Point, Point), (_o<> &Point, PointZ), - (r_<> &Point, &Point), (r_<> &Point, &PointZ), - (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), - - (_o<> &PointZ, Point), (_o<> &PointZ, PointZ), - (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), - (r_<'p> &PointZ, PointRef<'p, E>), (r_<> &PointZ, Generator), - - (_o<'p> PointRef<'p, E>, Point), (_o<'p> PointRef<'p, E>, PointZ), - (r_<'p> PointRef<'p, E>, &Point), (r_<'p> PointRef<'p, E>, &PointZ), - (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), - - (_o<> Generator, Point), (_o<> Generator, PointZ), - (r_<> Generator, &Point), (r_<> Generator, &PointZ), - (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), - } -} - -#[cfg(not(release))] -fn subtraction_of_two_point(result: E::Point) -> PointZ { - // In non-release environment we check that every subtraction results into correct point (either - // zero or of the expected order) - PointZ::from_raw(result) - .expect("subtraction of two points must be either a zero or of the same order") -} -#[cfg(release)] -fn subtraction_of_two_point(result: E::Point) -> PointZ { - // In release we skip checks - PointZ::from_raw_unchecked(result) -} - -matrix! { - trait = Sub, - trait_fn = sub, - output = PointZ, - output_new = subtraction_of_two_point, - point_fn = sub_point, - point_assign_fn = sub_point_assign, - pairs = { - (o_<> Point, Point), (o_<> Point, PointZ), - (o_<> Point, &Point), (o_<> Point, &PointZ), - (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), - - (o_<> PointZ, Point), (o_<> PointZ, PointZ), - (o_<> PointZ, &Point), (o_<> PointZ, &PointZ), - (o_<'p> PointZ, PointRef<'p, E>), (o_<> PointZ, Generator), - - (_o<> &Point, Point), (_o<> &Point, PointZ), - (r_<> &Point, &Point), (r_<> &Point, &PointZ), - (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), - - (_o<> &PointZ, Point), (_o<> &PointZ, PointZ), - (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), - (r_<'p> &PointZ, PointRef<'p, E>), (r_<> &PointZ, Generator), - - (_o<'p> PointRef<'p, E>, Point), (_o<'p> PointRef<'p, E>, PointZ), - (r_<'p> PointRef<'p, E>, &Point), (r_<'p> PointRef<'p, E>, &PointZ), - (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), - - (_o<> Generator, Point), (_o<> Generator, PointZ), - (r_<> Generator, &Point), (r_<> Generator, &PointZ), - (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), - } -} - -#[cfg(not(release))] -fn multiplication_of_nonzero_point_at_nonzero_scalar(result: E::Point) -> Point { - Point::from_raw(result) - .expect("multiplication of point at non-zero scalar must always produce a non-zero point of the same order") -} -#[cfg(release)] -fn multiplication_of_point_at_nonzero_scalar(result: E::Point) -> Point { - Point::from_raw_unchecked(result) -} - -matrix! { - trait = Mul, - trait_fn = mul, - output = Point, - output_new = multiplication_of_nonzero_point_at_nonzero_scalar, - point_fn = scalar_mul, - point_assign_fn = scalar_mul_assign, - pairs = { - (_o<> Scalar, Point), - (_r<> Scalar, &Point), - (_r<'p> Scalar, PointRef<'p, E>), - - (_o<> &Scalar, Point), - (_r<> &Scalar, &Point), - (_r<'p> &Scalar, PointRef<'p, E>), - - // --- and vice-versa --- - - (o_<> Point, Scalar), - (o_<> Point, &Scalar), - - (r_<> &Point, Scalar), - (r_<> &Point, &Scalar), - - (r_<'p> PointRef<'p, E>, Scalar), - (r_<'p> PointRef<'p, E>, &Scalar), - } -} - -#[cfg(not(release))] -fn multiplication_of_point_at_scalar(result: E::Point) -> PointZ { - PointZ::from_raw(result) - .expect("multiplication of point at scalar must always produce either a point of the same order or a zero point") -} -#[cfg(release)] -fn multiplication_of_point_at_scalar(result: E::Point) -> PointZ { - PointZ::from_raw_unchecked(result) -} - -matrix! { - trait = Mul, - trait_fn = mul, - output = PointZ, - output_new = multiplication_of_point_at_scalar, - point_fn = scalar_mul, - point_assign_fn = scalar_mul_assign, - pairs = { - (_o<> Scalar, PointZ), - (_r<> Scalar, &PointZ), - - (_o<> ScalarZ, Point), (_o<> ScalarZ, PointZ), - (_r<> ScalarZ, &Point), (_r<> ScalarZ, &PointZ), - (_r<'p> ScalarZ, PointRef<'p, E>), - - (_o<> &Scalar, PointZ), - (_r<> &Scalar, &PointZ), - - (_o<> &ScalarZ, Point), (_o<> &ScalarZ, PointZ), - (_r<> &ScalarZ, &Point), (_r<> &ScalarZ, &PointZ), - (_r<'p> &ScalarZ, PointRef<'p, E>), - - // --- and vice-versa --- - - (o_<> Point, ScalarZ), - (o_<> Point, &ScalarZ), - - (o_<> PointZ, Scalar), (o_<> PointZ, ScalarZ), - (o_<> PointZ, &Scalar), (o_<> PointZ, &ScalarZ), - - (r_<> &Point, ScalarZ), - (r_<> &Point, &ScalarZ), - - (r_<> &PointZ, Scalar), (r_<> &PointZ, ScalarZ), - (r_<> &PointZ, &Scalar), (r_<> &PointZ, &ScalarZ), - - (r_<'p> PointRef<'p, E>, ScalarZ), - (r_<'p> PointRef<'p, E>, &ScalarZ), - } -} - -matrix! { - trait = Add, - trait_fn = add, - output = ScalarZ, - output_new = ScalarZ::from_raw, - point_fn = add, - point_assign_fn = add_assign, - pairs = { - (o_<> Scalar, Scalar), (o_<> Scalar, ScalarZ), - (o_<> Scalar, &Scalar), (o_<> Scalar, &ScalarZ), - (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), - (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), - (_o<> &Scalar, Scalar), (_o<> &Scalar, ScalarZ), - (r_<> &Scalar, &Scalar), (r_<> &Scalar, &ScalarZ), - (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), - (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), - } -} - -matrix! { - trait = Sub, - trait_fn = sub, - output = ScalarZ, - output_new = ScalarZ::from_raw, - point_fn = sub, - point_assign_fn = sub_assign, - pairs = { - (o_<> Scalar, Scalar), (o_<> Scalar, ScalarZ), - (o_<> Scalar, &Scalar), (o_<> Scalar, &ScalarZ), - (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), - (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), - (_o<> &Scalar, Scalar), (_o<> &Scalar, ScalarZ), - (r_<> &Scalar, &Scalar), (r_<> &Scalar, &ScalarZ), - (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), - (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), - } -} - -matrix! { - trait = Mul, - trait_fn = mul, - output = ScalarZ, - output_new = ScalarZ::from_raw, - point_fn = mul, - point_assign_fn = mul_assign, - pairs = { - (o_<> Scalar, ScalarZ), - (o_<> Scalar, &ScalarZ), - (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), - (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), - (_o<> &Scalar, ScalarZ), - (r_<> &Scalar, &ScalarZ), - (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), - (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), - } -} - -fn multiplication_of_two_nonzero_scalars(result: E::Scalar) -> Scalar { - Scalar::from_raw(result) - .expect("multiplication of two nonzero scalar by prime modulo must be nonzero") -} - -matrix! { - trait = Mul, - trait_fn = mul, - output = Scalar, - output_new = multiplication_of_two_nonzero_scalars, - point_fn = mul, - point_assign_fn = mul_assign, - pairs = { - (o_<> Scalar, Scalar), - (o_<> Scalar, &Scalar), - (_o<> &Scalar, Scalar), - (r_<> &Scalar, &Scalar), - } -} - -impl ops::Mul<&Scalar> for Generator { - type Output = Point; - fn mul(self, rhs: &Scalar) -> Self::Output { - Point::from_raw(E::Point::generator_mul(rhs.as_raw())) - .expect("generator multiplied by non-zero scalar is always a point of group order") - } -} - -impl ops::Mul> for Generator { - type Output = Point; - fn mul(self, rhs: Scalar) -> Self::Output { - self.mul(&rhs) - } -} - -impl ops::Mul> for &Scalar { - type Output = Point; - fn mul(self, rhs: Generator) -> Self::Output { - rhs.mul(self) - } -} - -impl ops::Mul> for Scalar { - type Output = Point; - fn mul(self, rhs: Generator) -> Self::Output { - rhs.mul(self) - } -} - -impl ops::Mul<&ScalarZ> for Generator { - type Output = PointZ; - fn mul(self, rhs: &ScalarZ) -> Self::Output { - PointZ::from_raw(E::Point::generator_mul(rhs.as_raw())) - .expect("sG must be either a point of group order or a zero point") - } -} - -impl ops::Mul> for Generator { - type Output = PointZ; - fn mul(self, rhs: ScalarZ) -> Self::Output { - self.mul(&rhs) - } -} - -impl ops::Mul> for &ScalarZ { - type Output = PointZ; - fn mul(self, rhs: Generator) -> Self::Output { - rhs.mul(self) - } -} - -impl ops::Mul> for ScalarZ { - type Output = PointZ; - fn mul(self, rhs: Generator) -> Self::Output { - rhs.mul(self) - } -} - -impl ops::Neg for Scalar { - type Output = Scalar; - - fn neg(self) -> Self::Output { - Scalar::from_raw(self.as_raw().neg()).expect("neg must not produce zero point") - } -} - -impl ops::Neg for &Scalar { - type Output = Scalar; - - fn neg(self) -> Self::Output { - Scalar::from_raw(self.as_raw().neg()).expect("neg must not produce zero point") - } -} - -impl ops::Neg for ScalarZ { - type Output = ScalarZ; - - fn neg(self) -> Self::Output { - ScalarZ::from_raw(self.as_raw().neg()) - } -} - -impl ops::Neg for &ScalarZ { - type Output = ScalarZ; - - fn neg(self) -> Self::Output { - ScalarZ::from_raw(self.as_raw().neg()) - } -} - -impl ops::Neg for Point { - type Output = Point; - - fn neg(self) -> Self::Output { - Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") - } -} - -impl ops::Neg for &Point { - type Output = Point; - - fn neg(self) -> Self::Output { - Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") - } -} - -impl<'p, E: Curve> ops::Neg for PointRef<'p, E> { - type Output = Point; - - fn neg(self) -> Self::Output { - Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") - } -} - -impl ops::Neg for Generator { - type Output = Point; - - fn neg(self) -> Self::Output { - Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") - } -} - -impl ops::Neg for PointZ { - type Output = PointZ; - - fn neg(self) -> Self::Output { - PointZ::from_raw(self.as_raw().neg_point()).expect("negated point must have the same order") - } -} - -impl ops::Neg for &PointZ { - type Output = PointZ; - - fn neg(self) -> Self::Output { - PointZ::from_raw(self.as_raw().neg_point()).expect("negated point must have the same order") - } -} - -#[derive(Serialize, Deserialize)] -#[serde(bound = "")] -struct PointFormat { - curve: Cow<'static, str>, - point: Option, - #[serde(skip, default = "PointFormat::::_ph")] - _ph: PhantomData, -} - -impl PointFormat { - fn _ph() -> PhantomData { - PhantomData - } -} - -impl TryFrom> for PointZ { - type Error = ConvertParsedPointError; - fn try_from(parsed: PointFormat) -> Result { - if parsed.curve != E::CURVE_NAME { - return Err(ConvertParsedPointError::MismatchedCurve { - expected: E::CURVE_NAME, - got: parsed.curve, - }); - } - match parsed.point { - None => Ok(PointZ::zero()), - Some(coords) => match PointZ::from_coords(&coords.x, &coords.y) { - Ok(p) => Ok(p), - Err(PointZFromCoordsError::NotOnCurve) => Err(ConvertParsedPointError::NotOnCurve), - Err(PointZFromCoordsError::InvalidPoint(MismatchedPointOrder(()))) => Err( - ConvertParsedPointError::InvalidPoint(InvalidPoint::MismatchedPointOrder), - ), - }, - } - } -} - -impl From> for PointFormat { - fn from(point: PointZ) -> Self { - Self { - curve: E::CURVE_NAME.into(), - point: point.coords(), - _ph: PhantomData, - } - } -} - -impl TryFrom> for Point { - type Error = ConvertParsedPointError; - fn try_from(parsed: PointFormat) -> Result { - if parsed.curve != E::CURVE_NAME { - return Err(ConvertParsedPointError::MismatchedCurve { - expected: E::CURVE_NAME, - got: parsed.curve, - }); - } - match parsed.point { - None => Err(ConvertParsedPointError::InvalidPoint( - InvalidPoint::ZeroPoint, - )), - Some(coords) => match Point::from_coords(&coords.x, &coords.y) { - Ok(p) => Ok(p), - Err(PointFromCoordsError::PointNotOnCurve) => { - Err(ConvertParsedPointError::NotOnCurve) - } - Err(PointFromCoordsError::InvalidPoint(reason)) => { - Err(ConvertParsedPointError::InvalidPoint(reason)) - } - }, - } - } -} - -impl From> for PointFormat { - fn from(point: Point) -> Self { - Self { - curve: E::CURVE_NAME.into(), - point: Some(point.coords()), - _ph: PhantomData, - } - } -} - -#[derive(Debug, Error)] -enum ConvertParsedPointError { - #[error("invalid point ({0})")] - InvalidPoint(InvalidPoint), - #[error("expected point of curve {expected}, but got point of curve {got}")] - MismatchedCurve { - got: Cow<'static, str>, - expected: &'static str, - }, - #[error("point not on the curve: x,y don't satisfy curve equation")] - NotOnCurve, -} - -#[derive(Serialize, Deserialize)] -#[serde(bound = "")] -struct ScalarFormat { - curve: Cow<'static, str>, - #[serde(with = "hex")] - scalar: ScalarHex, -} - -impl TryFrom> for ScalarZ { - type Error = ConvertParsedScalarError; - - fn try_from(parsed: ScalarFormat) -> Result { - if parsed.curve != E::CURVE_NAME { - return Err(ConvertParsedScalarError::MismatchedCurve { - got: parsed.curve, - expected: E::CURVE_NAME, - }); - } - - Ok(ScalarZ::from_raw(parsed.scalar.0)) - } -} - -impl From> for ScalarFormat { - fn from(s: ScalarZ) -> Self { - ScalarFormat { - curve: E::CURVE_NAME.into(), - scalar: ScalarHex(s.into_raw()), - } - } -} - -impl TryFrom> for Scalar { - type Error = ConvertParsedScalarError; - - fn try_from(parsed: ScalarFormat) -> Result { - if parsed.curve != E::CURVE_NAME { - return Err(ConvertParsedScalarError::MismatchedCurve { - got: parsed.curve, - expected: E::CURVE_NAME, - }); - } - - ScalarZ::from_raw(parsed.scalar.0) - .ensure_nonzero() - .ok_or(ConvertParsedScalarError::ZeroScalar) - } -} - -impl From> for ScalarFormat { - fn from(s: Scalar) -> Self { - ScalarFormat { - curve: E::CURVE_NAME.into(), - scalar: ScalarHex(s.into_raw()), - } - } -} - -#[derive(Debug, Error)] -enum ConvertParsedScalarError { - #[error("scalar must not be zero")] - ZeroScalar, - #[error("expected scalar of curve {expected}, but got scalar of curve {got}")] - MismatchedCurve { - got: Cow<'static, str>, - expected: &'static str, - }, -} - -struct ScalarHex(E::Scalar); - -impl hex::ToHex for &ScalarHex { - fn encode_hex>(&self) -> T { - self.0.to_bigint().to_bytes().encode_hex() - } - - fn encode_hex_upper>(&self) -> T { - self.0.to_bigint().to_bytes().encode_hex_upper() - } -} - -impl hex::FromHex for ScalarHex { - type Error = hex::FromHexError; - - fn from_hex>(hex: T) -> Result { - let bytes = Vec::::from_hex(hex)?; - let big_int = BigInt::from_bytes(&bytes); - Ok(ScalarHex(E::Scalar::from_bigint(&big_int))) - } -} - -#[cfg(test)] -mod test { - use super::*; - - macro_rules! assert_operator_defined_for { - ( - assert_fn = $assert_fn:ident, - lhs = {}, - rhs = {$($rhs:ty),*}, - ) => { - // Corner case - }; - ( - assert_fn = $assert_fn:ident, - lhs = {$lhs:ty $(, $lhs_tail:ty)*}, - rhs = {$($rhs:ty),*}, - ) => { - assert_operator_defined_for! { - assert_fn = $assert_fn, - lhs = $lhs, - rhs = {$($rhs),*}, - } - assert_operator_defined_for! { - assert_fn = $assert_fn, - lhs = {$($lhs_tail),*}, - rhs = {$($rhs),*}, - } - }; - ( - assert_fn = $assert_fn:ident, - lhs = $lhs:ty, - rhs = {$($rhs:ty),*}, - ) => { - $($assert_fn::());* - }; - } - - /// Function asserts that P2 can be added to P1 (ie. P1 + P2) and result is PointZ. - /// If any condition doesn't meet, function won't compile. - #[allow(dead_code)] - fn assert_point_addition_defined() - where - P1: ops::Add>, - E: Curve, - { - // no-op - } - - #[test] - fn test_point_addition_defined() { - fn _curve() { - assert_operator_defined_for! { - assert_fn = assert_point_addition_defined, - lhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, - rhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, - } - } - } - - /// Function asserts that P2 can be subtracted from P1 (ie. P1 - P2) and result is PointZ. - /// If any condition doesn't meet, function won't compile. - #[allow(dead_code)] - fn assert_point_subtraction_defined() - where - P1: ops::Sub>, - E: Curve, - { - // no-op - } - - #[test] - fn test_point_subtraction_defined() { - fn _curve() { - assert_operator_defined_for! { - assert_fn = assert_point_subtraction_defined, - lhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, - rhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, - } - } - } - - /// Function asserts that M can be multiplied by N (ie. M * N) and result is PointZ. - /// If any condition doesn't meet, function won't compile. - #[allow(dead_code)] - fn assert_point_multiplication_defined() - where - M: ops::Mul>, - E: Curve, - { - // no-op - } - - /// Function asserts that M can be multiplied by N (ie. M * N) and result is **non-zero** Point. - /// If any condition doesn't meet, function won't compile. - #[allow(dead_code)] - fn assert_point_nonzero_multiplication_defined() - where - M: ops::Mul>, - E: Curve, - { - // no-op - } - - #[test] - fn test_point_multiplication_defined() { - fn _curve() { - assert_operator_defined_for! { - assert_fn = assert_point_nonzero_multiplication_defined, - lhs = {Point, &Point, PointRef}, - rhs = {Scalar, &Scalar}, - } - assert_operator_defined_for! { - assert_fn = assert_point_multiplication_defined, - lhs = {Point, &Point, PointRef}, - rhs = {ScalarZ, &ScalarZ}, - } - assert_operator_defined_for! { - assert_fn = assert_point_multiplication_defined, - lhs = {PointZ, &PointZ}, - rhs = {Scalar, &Scalar, ScalarZ, &ScalarZ}, - } - - // and vice-versa - - assert_operator_defined_for! { - assert_fn = assert_point_nonzero_multiplication_defined, - lhs = {Scalar, &Scalar}, - rhs = {Point, &Point, PointRef}, - } - assert_operator_defined_for! { - assert_fn = assert_point_multiplication_defined, - lhs = {ScalarZ, &ScalarZ}, - rhs = {Point, &Point, PointRef}, - } - assert_operator_defined_for! { - assert_fn = assert_point_multiplication_defined, - lhs = {Scalar, &Scalar, ScalarZ, &ScalarZ}, - rhs = {PointZ, &PointZ}, - } - } - } - - /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is ScalarZ. - /// If any condition doesn't meet, function won't compile. - #[allow(dead_code)] - fn assert_scalars_addition_defined() - where - S1: ops::Add>, - E: Curve, - { - // no-op - } - - #[test] - fn test_scalars_addition_defined() { - fn _curve() { - assert_operator_defined_for! { - assert_fn = assert_scalars_addition_defined, - lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - } - } - } - - /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is ScalarZ. - /// If any condition doesn't meet, function won't compile. - #[allow(dead_code)] - fn assert_scalars_subtraction_defined() - where - S1: ops::Sub>, - E: Curve, - { - // no-op - } - - #[test] - fn test_scalars_subtraction_defined() { - fn _curve() { - assert_operator_defined_for! { - assert_fn = assert_scalars_subtraction_defined, - lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - } - } - } - - /// Function asserts that S1 can be multiplied by S2 (ie. S1 * S2) and result is ScalarZ. - /// If any condition doesn't meet, function won't compile. - #[allow(dead_code)] - fn assert_scalars_multiplication_defined() - where - S1: ops::Mul>, - E: Curve, - { - // no-op - } - - /// Function asserts that S1 can be multiplied by S2 (ie. S1 * S2) and result is Scalar. - /// If any condition doesn't meet, function won't compile. - #[allow(dead_code)] - fn assert_nonzero_scalars_multiplication_defined() - where - S1: ops::Mul>, - E: Curve, - { - // no-op - } - - #[test] - fn test_scalars_multiplication_defined() { - fn _curve() { - assert_operator_defined_for! { - assert_fn = assert_scalars_multiplication_defined, - lhs = {ScalarZ, &ScalarZ}, - rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - } - assert_operator_defined_for! { - assert_fn = assert_scalars_multiplication_defined, - lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - rhs = {ScalarZ, &ScalarZ}, - } - assert_operator_defined_for! { - assert_fn = assert_nonzero_scalars_multiplication_defined, - lhs = {Scalar, &Scalar}, - rhs = {Scalar, &Scalar}, - } - } - } -} diff --git a/src/elliptic/curves/wrappers/arithmetic.rs b/src/elliptic/curves/wrappers/arithmetic.rs new file mode 100644 index 00000000..32de5f3f --- /dev/null +++ b/src/elliptic/curves/wrappers/arithmetic.rs @@ -0,0 +1,758 @@ +use std::ops; + +use crate::elliptic::curves::traits::*; + +use super::*; + +macro_rules! matrix { + ( + trait = $trait:ident, + trait_fn = $trait_fn:ident, + output = $output:ty, + output_new = $output_new:expr, + point_fn = $point_fn:ident, + point_assign_fn = $point_assign_fn:ident, + pairs = {(r_<$($l:lifetime),*> $lhs_ref:ty, $rhs:ty), $($rest:tt)*} + ) => { + impl<$($l,)* E: Curve> ops::$trait<$rhs> for $lhs_ref { + type Output = $output; + fn $trait_fn(self, rhs: $rhs) -> Self::Output { + let p = self.as_raw().$point_fn(rhs.as_raw()); + $output_new(p) + } + } + matrix!{ + trait = $trait, + trait_fn = $trait_fn, + output = $output, + output_new = $output_new, + point_fn = $point_fn, + point_assign_fn = $point_assign_fn, + pairs = {$($rest)*} + } + }; + + ( + trait = $trait:ident, + trait_fn = $trait_fn:ident, + output = $output:ty, + output_new = $output_new:expr, + point_fn = $point_fn:ident, + point_assign_fn = $point_assign_fn:ident, + pairs = {(_r<$($l:lifetime),*> $lhs:ty, $rhs_ref:ty), $($rest:tt)*} + ) => { + impl<$($l,)* E: Curve> ops::$trait<$rhs_ref> for $lhs { + type Output = $output; + fn $trait_fn(self, rhs: $rhs_ref) -> Self::Output { + let p = rhs.as_raw().$point_fn(self.as_raw()); + $output_new(p) + } + } + matrix!{ + trait = $trait, + trait_fn = $trait_fn, + output = $output, + output_new = $output_new, + point_fn = $point_fn, + point_assign_fn = $point_assign_fn, + pairs = {$($rest)*} + } + }; + + ( + trait = $trait:ident, + trait_fn = $trait_fn:ident, + output = $output:ty, + output_new = $output_new:expr, + point_fn = $point_fn:ident, + point_assign_fn = $point_assign_fn:ident, + pairs = {(o_<$($l:lifetime),*> $lhs_owned:ty, $rhs:ty), $($rest:tt)*} + ) => { + impl<$($l,)* E: Curve> ops::$trait<$rhs> for $lhs_owned { + type Output = $output; + fn $trait_fn(self, rhs: $rhs) -> Self::Output { + let mut raw = self.into_raw(); + raw.$point_assign_fn(rhs.as_raw()); + $output_new(raw) + } + } + matrix!{ + trait = $trait, + trait_fn = $trait_fn, + output = $output, + output_new = $output_new, + point_fn = $point_fn, + point_assign_fn = $point_assign_fn, + pairs = {$($rest)*} + } + }; + + ( + trait = $trait:ident, + trait_fn = $trait_fn:ident, + output = $output:ty, + output_new = $output_new:expr, + point_fn = $point_fn:ident, + point_assign_fn = $point_assign_fn:ident, + pairs = {(_o<$($l:lifetime),*> $lhs:ty, $rhs_owned:ty), $($rest:tt)*} + ) => { + impl<$($l,)* E: Curve> ops::$trait<$rhs_owned> for $lhs { + type Output = $output; + fn $trait_fn(self, rhs: $rhs_owned) -> Self::Output { + let mut raw = rhs.into_raw(); + raw.$point_assign_fn(self.as_raw()); + $output_new(raw) + } + } + matrix!{ + trait = $trait, + trait_fn = $trait_fn, + output = $output, + output_new = $output_new, + point_fn = $point_fn, + point_assign_fn = $point_assign_fn, + pairs = {$($rest)*} + } + }; + + ( + trait = $trait:ident, + trait_fn = $trait_fn:ident, + output = $output:ty, + output_new = $output_new:expr, + point_fn = $point_fn:ident, + point_assign_fn = $point_assign_fn:ident, + pairs = {} + ) => { + // happy termination + }; +} + +#[cfg(not(release))] +fn addition_of_two_points(result: E::Point) -> PointZ { + // In non-release environment we check that every addition results into correct point (either + // zero or of the expected order) + PointZ::from_raw(result) + .expect("addition of two points must be either a zero or of the same order") +} +#[cfg(release)] +fn addition_of_two_points(result: E::Point) -> PointZ { + // In release we skip checks + PointZ::from_raw_unchecked(result) +} + +matrix! { + trait = Add, + trait_fn = add, + output = PointZ, + output_new = addition_of_two_points, + point_fn = add_point, + point_assign_fn = add_point_assign, + pairs = { + (o_<> Point, Point), (o_<> Point, PointZ), + (o_<> Point, &Point), (o_<> Point, &PointZ), + (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), + + (o_<> PointZ, Point), (o_<> PointZ, PointZ), + (o_<> PointZ, &Point), (o_<> PointZ, &PointZ), + (o_<'p> PointZ, PointRef<'p, E>), (o_<> PointZ, Generator), + + (_o<> &Point, Point), (_o<> &Point, PointZ), + (r_<> &Point, &Point), (r_<> &Point, &PointZ), + (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), + + (_o<> &PointZ, Point), (_o<> &PointZ, PointZ), + (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), + (r_<'p> &PointZ, PointRef<'p, E>), (r_<> &PointZ, Generator), + + (_o<'p> PointRef<'p, E>, Point), (_o<'p> PointRef<'p, E>, PointZ), + (r_<'p> PointRef<'p, E>, &Point), (r_<'p> PointRef<'p, E>, &PointZ), + (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), + + (_o<> Generator, Point), (_o<> Generator, PointZ), + (r_<> Generator, &Point), (r_<> Generator, &PointZ), + (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), + } +} + +#[cfg(not(release))] +fn subtraction_of_two_point(result: E::Point) -> PointZ { + // In non-release environment we check that every subtraction results into correct point (either + // zero or of the expected order) + PointZ::from_raw(result) + .expect("subtraction of two points must be either a zero or of the same order") +} +#[cfg(release)] +fn subtraction_of_two_point(result: E::Point) -> PointZ { + // In release we skip checks + PointZ::from_raw_unchecked(result) +} + +matrix! { + trait = Sub, + trait_fn = sub, + output = PointZ, + output_new = subtraction_of_two_point, + point_fn = sub_point, + point_assign_fn = sub_point_assign, + pairs = { + (o_<> Point, Point), (o_<> Point, PointZ), + (o_<> Point, &Point), (o_<> Point, &PointZ), + (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), + + (o_<> PointZ, Point), (o_<> PointZ, PointZ), + (o_<> PointZ, &Point), (o_<> PointZ, &PointZ), + (o_<'p> PointZ, PointRef<'p, E>), (o_<> PointZ, Generator), + + (_o<> &Point, Point), (_o<> &Point, PointZ), + (r_<> &Point, &Point), (r_<> &Point, &PointZ), + (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), + + (_o<> &PointZ, Point), (_o<> &PointZ, PointZ), + (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), + (r_<'p> &PointZ, PointRef<'p, E>), (r_<> &PointZ, Generator), + + (_o<'p> PointRef<'p, E>, Point), (_o<'p> PointRef<'p, E>, PointZ), + (r_<'p> PointRef<'p, E>, &Point), (r_<'p> PointRef<'p, E>, &PointZ), + (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), + + (_o<> Generator, Point), (_o<> Generator, PointZ), + (r_<> Generator, &Point), (r_<> Generator, &PointZ), + (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), + } +} + +#[cfg(not(release))] +fn multiplication_of_nonzero_point_at_nonzero_scalar(result: E::Point) -> Point { + Point::from_raw(result) + .expect("multiplication of point at non-zero scalar must always produce a non-zero point of the same order") +} +#[cfg(release)] +fn multiplication_of_point_at_nonzero_scalar(result: E::Point) -> Point { + Point::from_raw_unchecked(result) +} + +matrix! { + trait = Mul, + trait_fn = mul, + output = Point, + output_new = multiplication_of_nonzero_point_at_nonzero_scalar, + point_fn = scalar_mul, + point_assign_fn = scalar_mul_assign, + pairs = { + (_o<> Scalar, Point), + (_r<> Scalar, &Point), + (_r<'p> Scalar, PointRef<'p, E>), + + (_o<> &Scalar, Point), + (_r<> &Scalar, &Point), + (_r<'p> &Scalar, PointRef<'p, E>), + + // --- and vice-versa --- + + (o_<> Point, Scalar), + (o_<> Point, &Scalar), + + (r_<> &Point, Scalar), + (r_<> &Point, &Scalar), + + (r_<'p> PointRef<'p, E>, Scalar), + (r_<'p> PointRef<'p, E>, &Scalar), + } +} + +#[cfg(not(release))] +fn multiplication_of_point_at_scalar(result: E::Point) -> PointZ { + PointZ::from_raw(result) + .expect("multiplication of point at scalar must always produce either a point of the same order or a zero point") +} +#[cfg(release)] +fn multiplication_of_point_at_scalar(result: E::Point) -> PointZ { + PointZ::from_raw_unchecked(result) +} + +matrix! { + trait = Mul, + trait_fn = mul, + output = PointZ, + output_new = multiplication_of_point_at_scalar, + point_fn = scalar_mul, + point_assign_fn = scalar_mul_assign, + pairs = { + (_o<> Scalar, PointZ), + (_r<> Scalar, &PointZ), + + (_o<> ScalarZ, Point), (_o<> ScalarZ, PointZ), + (_r<> ScalarZ, &Point), (_r<> ScalarZ, &PointZ), + (_r<'p> ScalarZ, PointRef<'p, E>), + + (_o<> &Scalar, PointZ), + (_r<> &Scalar, &PointZ), + + (_o<> &ScalarZ, Point), (_o<> &ScalarZ, PointZ), + (_r<> &ScalarZ, &Point), (_r<> &ScalarZ, &PointZ), + (_r<'p> &ScalarZ, PointRef<'p, E>), + + // --- and vice-versa --- + + (o_<> Point, ScalarZ), + (o_<> Point, &ScalarZ), + + (o_<> PointZ, Scalar), (o_<> PointZ, ScalarZ), + (o_<> PointZ, &Scalar), (o_<> PointZ, &ScalarZ), + + (r_<> &Point, ScalarZ), + (r_<> &Point, &ScalarZ), + + (r_<> &PointZ, Scalar), (r_<> &PointZ, ScalarZ), + (r_<> &PointZ, &Scalar), (r_<> &PointZ, &ScalarZ), + + (r_<'p> PointRef<'p, E>, ScalarZ), + (r_<'p> PointRef<'p, E>, &ScalarZ), + } +} + +matrix! { + trait = Add, + trait_fn = add, + output = ScalarZ, + output_new = ScalarZ::from_raw, + point_fn = add, + point_assign_fn = add_assign, + pairs = { + (o_<> Scalar, Scalar), (o_<> Scalar, ScalarZ), + (o_<> Scalar, &Scalar), (o_<> Scalar, &ScalarZ), + (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), + (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), + (_o<> &Scalar, Scalar), (_o<> &Scalar, ScalarZ), + (r_<> &Scalar, &Scalar), (r_<> &Scalar, &ScalarZ), + (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), + (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), + } +} + +matrix! { + trait = Sub, + trait_fn = sub, + output = ScalarZ, + output_new = ScalarZ::from_raw, + point_fn = sub, + point_assign_fn = sub_assign, + pairs = { + (o_<> Scalar, Scalar), (o_<> Scalar, ScalarZ), + (o_<> Scalar, &Scalar), (o_<> Scalar, &ScalarZ), + (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), + (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), + (_o<> &Scalar, Scalar), (_o<> &Scalar, ScalarZ), + (r_<> &Scalar, &Scalar), (r_<> &Scalar, &ScalarZ), + (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), + (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), + } +} + +matrix! { + trait = Mul, + trait_fn = mul, + output = ScalarZ, + output_new = ScalarZ::from_raw, + point_fn = mul, + point_assign_fn = mul_assign, + pairs = { + (o_<> Scalar, ScalarZ), + (o_<> Scalar, &ScalarZ), + (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), + (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), + (_o<> &Scalar, ScalarZ), + (r_<> &Scalar, &ScalarZ), + (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), + (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), + } +} + +fn multiplication_of_two_nonzero_scalars(result: E::Scalar) -> Scalar { + Scalar::from_raw(result) + .expect("multiplication of two nonzero scalar by prime modulo must be nonzero") +} + +matrix! { + trait = Mul, + trait_fn = mul, + output = Scalar, + output_new = multiplication_of_two_nonzero_scalars, + point_fn = mul, + point_assign_fn = mul_assign, + pairs = { + (o_<> Scalar, Scalar), + (o_<> Scalar, &Scalar), + (_o<> &Scalar, Scalar), + (r_<> &Scalar, &Scalar), + } +} + +impl ops::Mul<&Scalar> for Generator { + type Output = Point; + fn mul(self, rhs: &Scalar) -> Self::Output { + Point::from_raw(E::Point::generator_mul(rhs.as_raw())) + .expect("generator multiplied by non-zero scalar is always a point of group order") + } +} + +impl ops::Mul> for Generator { + type Output = Point; + fn mul(self, rhs: Scalar) -> Self::Output { + self.mul(&rhs) + } +} + +impl ops::Mul> for &Scalar { + type Output = Point; + fn mul(self, rhs: Generator) -> Self::Output { + rhs.mul(self) + } +} + +impl ops::Mul> for Scalar { + type Output = Point; + fn mul(self, rhs: Generator) -> Self::Output { + rhs.mul(self) + } +} + +impl ops::Mul<&ScalarZ> for Generator { + type Output = PointZ; + fn mul(self, rhs: &ScalarZ) -> Self::Output { + PointZ::from_raw(E::Point::generator_mul(rhs.as_raw())) + .expect("sG must be either a point of group order or a zero point") + } +} + +impl ops::Mul> for Generator { + type Output = PointZ; + fn mul(self, rhs: ScalarZ) -> Self::Output { + self.mul(&rhs) + } +} + +impl ops::Mul> for &ScalarZ { + type Output = PointZ; + fn mul(self, rhs: Generator) -> Self::Output { + rhs.mul(self) + } +} + +impl ops::Mul> for ScalarZ { + type Output = PointZ; + fn mul(self, rhs: Generator) -> Self::Output { + rhs.mul(self) + } +} + +impl ops::Neg for Scalar { + type Output = Scalar; + + fn neg(self) -> Self::Output { + Scalar::from_raw(self.as_raw().neg()).expect("neg must not produce zero point") + } +} + +impl ops::Neg for &Scalar { + type Output = Scalar; + + fn neg(self) -> Self::Output { + Scalar::from_raw(self.as_raw().neg()).expect("neg must not produce zero point") + } +} + +impl ops::Neg for ScalarZ { + type Output = ScalarZ; + + fn neg(self) -> Self::Output { + ScalarZ::from_raw(self.as_raw().neg()) + } +} + +impl ops::Neg for &ScalarZ { + type Output = ScalarZ; + + fn neg(self) -> Self::Output { + ScalarZ::from_raw(self.as_raw().neg()) + } +} + +impl ops::Neg for Point { + type Output = Point; + + fn neg(self) -> Self::Output { + Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") + } +} + +impl ops::Neg for &Point { + type Output = Point; + + fn neg(self) -> Self::Output { + Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") + } +} + +impl<'p, E: Curve> ops::Neg for PointRef<'p, E> { + type Output = Point; + + fn neg(self) -> Self::Output { + Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") + } +} + +impl ops::Neg for Generator { + type Output = Point; + + fn neg(self) -> Self::Output { + Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") + } +} + +impl ops::Neg for PointZ { + type Output = PointZ; + + fn neg(self) -> Self::Output { + PointZ::from_raw(self.as_raw().neg_point()).expect("negated point must have the same order") + } +} + +impl ops::Neg for &PointZ { + type Output = PointZ; + + fn neg(self) -> Self::Output { + PointZ::from_raw(self.as_raw().neg_point()).expect("negated point must have the same order") + } +} + +#[cfg(test)] +mod test { + use super::*; + + macro_rules! assert_operator_defined_for { + ( + assert_fn = $assert_fn:ident, + lhs = {}, + rhs = {$($rhs:ty),*}, + ) => { + // Corner case + }; + ( + assert_fn = $assert_fn:ident, + lhs = {$lhs:ty $(, $lhs_tail:ty)*}, + rhs = {$($rhs:ty),*}, + ) => { + assert_operator_defined_for! { + assert_fn = $assert_fn, + lhs = $lhs, + rhs = {$($rhs),*}, + } + assert_operator_defined_for! { + assert_fn = $assert_fn, + lhs = {$($lhs_tail),*}, + rhs = {$($rhs),*}, + } + }; + ( + assert_fn = $assert_fn:ident, + lhs = $lhs:ty, + rhs = {$($rhs:ty),*}, + ) => { + $($assert_fn::());* + }; + } + + /// Function asserts that P2 can be added to P1 (ie. P1 + P2) and result is PointZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_point_addition_defined() + where + P1: ops::Add>, + E: Curve, + { + // no-op + } + + #[test] + fn test_point_addition_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_point_addition_defined, + lhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, + rhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, + } + } + } + + /// Function asserts that P2 can be subtracted from P1 (ie. P1 - P2) and result is PointZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_point_subtraction_defined() + where + P1: ops::Sub>, + E: Curve, + { + // no-op + } + + #[test] + fn test_point_subtraction_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_point_subtraction_defined, + lhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, + rhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, + } + } + } + + /// Function asserts that M can be multiplied by N (ie. M * N) and result is PointZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_point_multiplication_defined() + where + M: ops::Mul>, + E: Curve, + { + // no-op + } + + /// Function asserts that M can be multiplied by N (ie. M * N) and result is **non-zero** Point. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_point_nonzero_multiplication_defined() + where + M: ops::Mul>, + E: Curve, + { + // no-op + } + + #[test] + fn test_point_multiplication_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_point_nonzero_multiplication_defined, + lhs = {Point, &Point, PointRef}, + rhs = {Scalar, &Scalar}, + } + assert_operator_defined_for! { + assert_fn = assert_point_multiplication_defined, + lhs = {Point, &Point, PointRef}, + rhs = {ScalarZ, &ScalarZ}, + } + assert_operator_defined_for! { + assert_fn = assert_point_multiplication_defined, + lhs = {PointZ, &PointZ}, + rhs = {Scalar, &Scalar, ScalarZ, &ScalarZ}, + } + + // and vice-versa + + assert_operator_defined_for! { + assert_fn = assert_point_nonzero_multiplication_defined, + lhs = {Scalar, &Scalar}, + rhs = {Point, &Point, PointRef}, + } + assert_operator_defined_for! { + assert_fn = assert_point_multiplication_defined, + lhs = {ScalarZ, &ScalarZ}, + rhs = {Point, &Point, PointRef}, + } + assert_operator_defined_for! { + assert_fn = assert_point_multiplication_defined, + lhs = {Scalar, &Scalar, ScalarZ, &ScalarZ}, + rhs = {PointZ, &PointZ}, + } + } + } + + /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is ScalarZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_scalars_addition_defined() + where + S1: ops::Add>, + E: Curve, + { + // no-op + } + + #[test] + fn test_scalars_addition_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_scalars_addition_defined, + lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + } + } + } + + /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is ScalarZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_scalars_subtraction_defined() + where + S1: ops::Sub>, + E: Curve, + { + // no-op + } + + #[test] + fn test_scalars_subtraction_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_scalars_subtraction_defined, + lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + } + } + } + + /// Function asserts that S1 can be multiplied by S2 (ie. S1 * S2) and result is ScalarZ. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_scalars_multiplication_defined() + where + S1: ops::Mul>, + E: Curve, + { + // no-op + } + + /// Function asserts that S1 can be multiplied by S2 (ie. S1 * S2) and result is Scalar. + /// If any condition doesn't meet, function won't compile. + #[allow(dead_code)] + fn assert_nonzero_scalars_multiplication_defined() + where + S1: ops::Mul>, + E: Curve, + { + // no-op + } + + #[test] + fn test_scalars_multiplication_defined() { + fn _curve() { + assert_operator_defined_for! { + assert_fn = assert_scalars_multiplication_defined, + lhs = {ScalarZ, &ScalarZ}, + rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + } + assert_operator_defined_for! { + assert_fn = assert_scalars_multiplication_defined, + lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + rhs = {ScalarZ, &ScalarZ}, + } + assert_operator_defined_for! { + assert_fn = assert_nonzero_scalars_multiplication_defined, + lhs = {Scalar, &Scalar}, + rhs = {Scalar, &Scalar}, + } + } + } +} diff --git a/src/elliptic/curves/wrappers/error.rs b/src/elliptic/curves/wrappers/error.rs new file mode 100644 index 00000000..dee34b01 --- /dev/null +++ b/src/elliptic/curves/wrappers/error.rs @@ -0,0 +1,75 @@ +use std::fmt; + +use thiserror::Error; + +use crate::elliptic::curves::traits::*; + +#[derive(Debug, Error, Clone, PartialEq)] +#[error("invalid point (point order ≠ group order)")] +pub struct MismatchedPointOrder(pub(super) ()); + +#[derive(Debug, Error)] +pub enum PointZDeserializationError { + #[error("failed to deserialize the point")] + DeserializationError, + #[error("invalid point ({0})")] + InvalidPoint(MismatchedPointOrder), +} + +#[derive(Debug, Error)] +pub enum PointZFromCoordsError { + #[error("{}", NotOnCurve)] + NotOnCurve, + #[error("invalid point ({0})")] + InvalidPoint(MismatchedPointOrder), +} + +/// Indicates that conversion or computation failed due to occurred zero point +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ZeroPointError(pub(super) ()); + +impl fmt::Display for ZeroPointError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "nonzero check failed: point is zero") + } +} + +impl std::error::Error for ZeroPointError {} + +/// Indicates that conversion or computation failed due to occurred zero scalar +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ZeroScalarError(pub(super) ()); + +impl fmt::Display for ZeroScalarError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "nonzero check failed: scalar is zero") + } +} + +impl std::error::Error for ZeroScalarError {} + +#[derive(Error, Debug)] +pub enum InvalidPoint { + #[error("x,y correspond to zero point")] + ZeroPoint, + #[error("{}", MismatchedPointOrder(()))] + MismatchedPointOrder, +} + +/// Constructing Point from its coordinates error +#[derive(Debug, Error)] +pub enum PointFromCoordsError { + #[error("invalid point ({0})")] + InvalidPoint(InvalidPoint), + #[error("{}", NotOnCurve)] + PointNotOnCurve, +} + +/// Constructing Point from its (un)compressed representation error +#[derive(Debug, Error)] +pub enum PointFromBytesError { + #[error("invalid point ({0})")] + InvalidPoint(InvalidPoint), + #[error("{0}")] + Deserialize(#[source] DeserializationError), +} diff --git a/src/elliptic/curves/wrappers/format.rs b/src/elliptic/curves/wrappers/format.rs new file mode 100644 index 00000000..75acd5c3 --- /dev/null +++ b/src/elliptic/curves/wrappers/format.rs @@ -0,0 +1,202 @@ +use std::borrow::Cow; +use std::convert::TryFrom; +use std::iter; +use std::marker::PhantomData; + +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::arithmetic::*; +use crate::elliptic::curves::traits::*; + +use super::{ + error::{InvalidPoint, MismatchedPointOrder, PointFromCoordsError, PointZFromCoordsError}, + *, +}; + +#[derive(Serialize, Deserialize)] +#[serde(bound = "")] +pub struct PointFormat { + curve: Cow<'static, str>, + point: Option, + #[serde(skip, default = "PointFormat::::_ph")] + _ph: PhantomData, +} + +impl PointFormat { + fn _ph() -> PhantomData { + PhantomData + } +} + +impl TryFrom> for PointZ { + type Error = ConvertParsedPointError; + fn try_from(parsed: PointFormat) -> Result { + if parsed.curve != E::CURVE_NAME { + return Err(ConvertParsedPointError::MismatchedCurve { + expected: E::CURVE_NAME, + got: parsed.curve, + }); + } + match parsed.point { + None => Ok(PointZ::zero()), + Some(coords) => match PointZ::from_coords(&coords.x, &coords.y) { + Ok(p) => Ok(p), + Err(PointZFromCoordsError::NotOnCurve) => Err(ConvertParsedPointError::NotOnCurve), + Err(PointZFromCoordsError::InvalidPoint(MismatchedPointOrder(()))) => Err( + ConvertParsedPointError::InvalidPoint(InvalidPoint::MismatchedPointOrder), + ), + }, + } + } +} + +impl From> for PointFormat { + fn from(point: PointZ) -> Self { + Self { + curve: E::CURVE_NAME.into(), + point: point.coords(), + _ph: PhantomData, + } + } +} + +impl TryFrom> for Point { + type Error = ConvertParsedPointError; + fn try_from(parsed: PointFormat) -> Result { + if parsed.curve != E::CURVE_NAME { + return Err(ConvertParsedPointError::MismatchedCurve { + expected: E::CURVE_NAME, + got: parsed.curve, + }); + } + match parsed.point { + None => Err(ConvertParsedPointError::InvalidPoint( + InvalidPoint::ZeroPoint, + )), + Some(coords) => match Point::from_coords(&coords.x, &coords.y) { + Ok(p) => Ok(p), + Err(PointFromCoordsError::PointNotOnCurve) => { + Err(ConvertParsedPointError::NotOnCurve) + } + Err(PointFromCoordsError::InvalidPoint(reason)) => { + Err(ConvertParsedPointError::InvalidPoint(reason)) + } + }, + } + } +} + +impl From> for PointFormat { + fn from(point: Point) -> Self { + Self { + curve: E::CURVE_NAME.into(), + point: Some(point.coords()), + _ph: PhantomData, + } + } +} + +#[derive(Debug, Error)] +pub enum ConvertParsedPointError { + #[error("invalid point ({0})")] + InvalidPoint(InvalidPoint), + #[error("expected point of curve {expected}, but got point of curve {got}")] + MismatchedCurve { + got: Cow<'static, str>, + expected: &'static str, + }, + #[error("point not on the curve: x,y don't satisfy curve equation")] + NotOnCurve, +} + +#[derive(Serialize, Deserialize)] +#[serde(bound = "")] +pub struct ScalarFormat { + curve: Cow<'static, str>, + #[serde(with = "hex")] + scalar: ScalarHex, +} + +impl TryFrom> for ScalarZ { + type Error = ConvertParsedScalarError; + + fn try_from(parsed: ScalarFormat) -> Result { + if parsed.curve != E::CURVE_NAME { + return Err(ConvertParsedScalarError::MismatchedCurve { + got: parsed.curve, + expected: E::CURVE_NAME, + }); + } + + Ok(ScalarZ::from_raw(parsed.scalar.0)) + } +} + +impl From> for ScalarFormat { + fn from(s: ScalarZ) -> Self { + ScalarFormat { + curve: E::CURVE_NAME.into(), + scalar: ScalarHex(s.into_raw()), + } + } +} + +impl TryFrom> for Scalar { + type Error = ConvertParsedScalarError; + + fn try_from(parsed: ScalarFormat) -> Result { + if parsed.curve != E::CURVE_NAME { + return Err(ConvertParsedScalarError::MismatchedCurve { + got: parsed.curve, + expected: E::CURVE_NAME, + }); + } + + ScalarZ::from_raw(parsed.scalar.0) + .ensure_nonzero() + .ok_or(ConvertParsedScalarError::ZeroScalar) + } +} + +impl From> for ScalarFormat { + fn from(s: Scalar) -> Self { + ScalarFormat { + curve: E::CURVE_NAME.into(), + scalar: ScalarHex(s.into_raw()), + } + } +} + +#[derive(Debug, Error)] +pub enum ConvertParsedScalarError { + #[error("scalar must not be zero")] + ZeroScalar, + #[error("expected scalar of curve {expected}, but got scalar of curve {got}")] + MismatchedCurve { + got: Cow<'static, str>, + expected: &'static str, + }, +} + +struct ScalarHex(E::Scalar); + +impl hex::ToHex for &ScalarHex { + fn encode_hex>(&self) -> T { + self.0.to_bigint().to_bytes().encode_hex() + } + + fn encode_hex_upper>(&self) -> T { + self.0.to_bigint().to_bytes().encode_hex_upper() + } +} + +impl hex::FromHex for ScalarHex { + type Error = hex::FromHexError; + + fn from_hex>(hex: T) -> Result { + let bytes = Vec::::from_hex(hex)?; + let big_int = BigInt::from_bytes(&bytes); + Ok(ScalarHex(E::Scalar::from_bigint(&big_int))) + } +} diff --git a/src/elliptic/curves/wrappers/generator.rs b/src/elliptic/curves/wrappers/generator.rs new file mode 100644 index 00000000..74fd4879 --- /dev/null +++ b/src/elliptic/curves/wrappers/generator.rs @@ -0,0 +1,77 @@ +use std::marker::PhantomData; + +use crate::elliptic::curves::traits::*; + +use super::{Point, PointRef}; + +/// Elliptic curve generator +/// +/// Holds internally a static reference on curve generator. Can be used in arithmetic interchangeably +/// as [`PointRef`](PointRef). +/// +/// You can convert the generator into `Point` and `PointRef` using +/// [`to_point`](Self::to_point) and [`as_point`](Self::as_point) +/// methods respectively. +/// +/// ## Example +/// +/// ```rust +/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; +/// let s = Scalar::::random(); // Non-zero scalar +/// let g = Point::::generator(); // Curve generator +/// let result: Point = s * g; // Generator multiplied at non-zero scalar is +/// // always a non-zero point +/// ``` +/// +/// ## Performance +/// +/// Generator multiplication is often more efficient than regular point multiplication, so avoid +/// converting generator into the `Point` as long as it's possible: +/// +/// ```rust +/// # use curv::elliptic::curves::{Point, Scalar, Secp256k1, Generator, PointZ}; +/// let s: Scalar = Scalar::random(); +/// // Generator multiplication: +/// let g: Generator = Point::generator(); +/// let p1: Point = g * &s; +/// // Point multiplication: +/// let g: Point = g.to_point(); +/// let p2: Point = g * &s; +/// // Result will be the same, but generator multiplication is usually faster +/// assert_eq!(p1, p2); +/// ``` +pub struct Generator { + _ph: PhantomData<&'static E::Point>, +} + +impl Default for Generator { + fn default() -> Self { + Self { _ph: PhantomData } + } +} + +impl Generator { + pub fn as_raw(self) -> &'static E::Point { + E::Point::generator() + } + + /// Clones generator point, returns `Point` + pub fn to_point(self) -> Point { + // Safety: curve generator must be non-zero point, otherwise nothing will work at all + unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } + } + + /// Converts generator into `PointRef` + pub fn as_point(self) -> PointRef<'static, E> { + // Safety: curve generator must be non-zero point, otherwise nothing will work at all + unsafe { PointRef::from_raw_unchecked(self.as_raw()) } + } +} + +impl Clone for Generator { + fn clone(&self) -> Self { + Self { _ph: PhantomData } + } +} + +impl Copy for Generator {} diff --git a/src/elliptic/curves/wrappers/mod.rs b/src/elliptic/curves/wrappers/mod.rs new file mode 100644 index 00000000..27edf898 --- /dev/null +++ b/src/elliptic/curves/wrappers/mod.rs @@ -0,0 +1,14 @@ +mod arithmetic; +pub mod error; +mod format; +mod generator; +mod point; +mod point_ref; +mod point_z; +mod scalar; +mod scalar_z; + +pub use self::{ + generator::Generator, point::Point, point_ref::PointRef, point_z::PointZ, scalar::Scalar, + scalar_z::ScalarZ, +}; diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs new file mode 100644 index 00000000..bf60d7dc --- /dev/null +++ b/src/elliptic/curves/wrappers/point.rs @@ -0,0 +1,202 @@ +use std::convert::TryFrom; +use std::fmt; + +use serde::{Deserialize, Serialize}; + +use crate::elliptic::curves::traits::*; +use crate::BigInt; + +use super::{ + error::{InvalidPoint, PointFromBytesError, PointFromCoordsError, ZeroPointError}, + format::PointFormat, + Generator, PointRef, PointZ, +}; + +/// Elliptic point of [group order](super::Scalar::group_order) +/// +/// ## Guarantees +/// +/// * On curve +/// +/// Any instance of `Point` is guaranteed to belong to curve `E`, i.e. its coordinates must +/// satisfy curve equations +/// * Point order equals to [group order](super::Scalar::group_order) +/// +/// I.e. denoting `q = group_order`, following predicate is always true: +/// `qP = O ∧ forall 0 < s < q. sP ≠ O` +/// +/// Note that this also means that `Point` cannot be zero (zero point has `order=1`), +/// ie. `forall a b. a: PointZ ∧ b: Point → a + b ≢ a`. It also implies that `Point` is +/// guaranteed to have coordinates (only point at infinity doesn't). +/// +/// ## Arithmetics +/// +/// You can add, subtract two points, or multiply point at scalar. +/// +/// Addition or subtraction of two points might result into zero point, so these operators output +/// [`PointZ`](PointZ) that allowed to be zero. +/// +/// ```rust +/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; +/// let p1: Point = +/// Point::generator() * Scalar::random(); // Non-zero point +/// let p2: Point = +/// Point::generator() * Scalar::random(); // Non-zero point +/// let result: PointZ = p1 + p2; // Addition of two (even non-zero) +/// // points might produce zero point +/// let nonzero_result: Option> = result.ensure_nonzero(); +/// ``` +/// +/// Multiplying point at non-zero scalar is guaranteed to be non-zero (as point order is known +/// to be equal to group order, and scalar is known to be less then group order): +/// +/// ```rust +/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; +/// let s = Scalar::::random(); // Non-zero scalar +/// let g = Point::::generator(); // Curve generator +/// let result: Point = s * g; // Generator multiplied at non-zero scalar is +/// // always a non-zero point +/// ``` +#[derive(Serialize, Deserialize)] +#[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] +pub struct Point { + raw_point: E::Point, +} + +impl Point { + /// Curve generator + /// + /// Returns a static reference on actual value because in most cases referenced value is fine. + /// Use [`.to_point()`](Generator::to_point) if you need to take it by value. + pub fn generator() -> Generator { + Generator::default() + } + + /// Curve second generator + /// + /// We provide an alternative generator value and prove that it was picked randomly. + /// + /// Returns a static reference on actual value because in most cases referenced value is fine. + /// Use [`.to_point()`](PointRef::to_point) if you need to take it by value. + pub fn base_point2() -> PointRef<'static, E> { + let p = E::Point::base_point2(); + PointRef::from_raw(p).expect("base_point2 must have correct order") + } + + /// Constructs a point from coordinates, returns error if x,y don't satisfy curve equation or + /// correspond to zero point + pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { + let p = E::Point::from_coords(x, y) + .map_err(|NotOnCurve { .. }| PointFromCoordsError::PointNotOnCurve)?; + Self::from_raw(p).map_err(PointFromCoordsError::InvalidPoint) + } + + /// Tries to parse a point from its (un)compressed form + /// + /// Whether it's a compressed or uncompressed form will be deduced from its length + pub fn from_bytes(bytes: &[u8]) -> Result { + let p = E::Point::deserialize(bytes).map_err(PointFromBytesError::Deserialize)?; + Self::from_raw(p).map_err(PointFromBytesError::InvalidPoint) + } + + /// Returns point coordinates (`x` and `y`) + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn coords(&self) -> PointCoords { + self.as_point().coords() + } + + /// Returns `x` coordinate of point + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn x_coord(&self) -> BigInt { + self.as_point().x_coord() + } + + /// Returns `y` coordinate of point + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn y_coord(&self) -> BigInt { + self.as_point().y_coord() + } + + /// Serializes point into (un)compressed form + pub fn to_bytes(&self, compressed: bool) -> Vec { + self.as_point().to_bytes(compressed) + } + + /// Creates [PointRef] that holds a reference on `self` + pub fn as_point(&self) -> PointRef { + PointRef::from(self) + } + + pub fn from_raw(raw_point: E::Point) -> Result { + if raw_point.is_zero() { + Err(InvalidPoint::ZeroPoint) + } else if !raw_point.check_point_order_equals_group_order() { + Err(InvalidPoint::MismatchedPointOrder) + } else { + Ok(Point { raw_point }) + } + } + + pub unsafe fn from_raw_unchecked(point: E::Point) -> Self { + Point { raw_point: point } + } + + pub fn as_raw(&self) -> &E::Point { + &self.raw_point + } + + pub fn into_raw(self) -> E::Point { + self.raw_point + } +} + +impl PartialEq for Point { + fn eq(&self, other: &Self) -> bool { + self.as_raw().eq(&other.as_raw()) + } +} + +impl PartialEq> for Point { + fn eq(&self, other: &PointZ) -> bool { + self.as_raw().eq(&other.as_raw()) + } +} + +impl<'p, E: Curve> PartialEq> for Point { + fn eq(&self, other: &PointRef<'p, E>) -> bool { + self.as_raw().eq(&other.as_raw()) + } +} + +impl PartialEq> for Point { + fn eq(&self, other: &Generator) -> bool { + self.as_raw().eq(&other.as_raw()) + } +} + +impl Clone for Point { + fn clone(&self) -> Self { + // Safety: `self` is guaranteed to be non-zero + unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } + } +} + +impl fmt::Debug for Point { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.as_raw().fmt(f) + } +} + +impl TryFrom> for Point { + type Error = ZeroPointError; + fn try_from(point: PointZ) -> Result { + match Self::from_raw(point.into_raw()) { + Ok(p) => Ok(p), + Err(InvalidPoint::ZeroPoint) => Err(ZeroPointError(())), + Err(InvalidPoint::MismatchedPointOrder) => panic!("Point must have correct order"), + } + } +} diff --git a/src/elliptic/curves/wrappers/point_ref.rs b/src/elliptic/curves/wrappers/point_ref.rs new file mode 100644 index 00000000..00b61656 --- /dev/null +++ b/src/elliptic/curves/wrappers/point_ref.rs @@ -0,0 +1,133 @@ +use std::fmt; + +use crate::elliptic::curves::traits::*; +use crate::BigInt; + +use super::{error::InvalidPoint, Generator, Point, PointZ}; + +/// Reference on elliptic point of [group order](super::Scalar::group_order) +/// +/// Holds internally a reference on [`Point`](Point), refer to its documentation to learn +/// more about Point/PointRef guarantees, security notes, and arithmetics. +pub struct PointRef<'p, E: Curve> { + raw_point: &'p E::Point, +} + +impl PointRef<'static, E> { + pub fn generator() -> Self { + Self::from_raw(E::Point::generator()).expect("generator must be non-zero") + } + + pub fn base_point2() -> Self { + Self::from_raw(E::Point::base_point2()).expect("base_point2 must be non-zero") + } +} + +impl<'p, E> PointRef<'p, E> +where + E: Curve, +{ + /// Returns point coordinates (`x` and `y`) + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn coords(&self) -> PointCoords { + self.as_raw() + .coords() + .expect("Point guaranteed to have coordinates") + } + + /// Returns `x` coordinate of point + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn x_coord(&self) -> BigInt { + self.as_raw() + .x_coord() + .expect("Point guaranteed to have coordinates") + } + + /// Returns `y` coordinate of point + /// + /// Method never fails as Point is guaranteed to have coordinates + pub fn y_coord(&self) -> BigInt { + self.as_raw() + .y_coord() + .expect("Point guaranteed to have coordinates") + } + + /// Serializes point into (un)compressed form + pub fn to_bytes(&self, compressed: bool) -> Vec { + self.as_raw() + .serialize(compressed) + .expect("non-zero point must always be serializable") + } + + /// Clones the referenced point + pub fn to_point(&self) -> Point { + // Safety: `self` is guaranteed to have order = group_order + unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } + } + + pub fn from_raw(raw_point: &'p E::Point) -> Result { + if raw_point.is_zero() { + Err(InvalidPoint::ZeroPoint) + } else if !raw_point.check_point_order_equals_group_order() { + Err(InvalidPoint::MismatchedPointOrder) + } else { + Ok(Self { raw_point }) + } + } + + pub unsafe fn from_raw_unchecked(raw_point: &'p E::Point) -> Self { + PointRef { raw_point } + } + + pub fn as_raw(self) -> &'p E::Point { + self.raw_point + } +} + +impl<'p, E: Curve> Clone for PointRef<'p, E> { + fn clone(&self) -> Self { + // Safety: `self` is guaranteed to be non-zero + unsafe { Self::from_raw_unchecked(self.as_raw()) } + } +} + +impl<'p, E: Curve> Copy for PointRef<'p, E> {} + +impl<'p, E: Curve> fmt::Debug for PointRef<'p, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.as_raw().fmt(f) + } +} + +impl<'p, E: Curve> From<&'p Point> for PointRef<'p, E> { + fn from(point: &'p Point) -> Self { + // Safety: `point` is guaranteed to be non-zero + unsafe { PointRef::from_raw_unchecked(point.as_raw()) } + } +} + +impl<'p, E: Curve> PartialEq for PointRef<'p, E> { + fn eq(&self, other: &Self) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { + fn eq(&self, other: &Point) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { + fn eq(&self, other: &PointZ) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { + fn eq(&self, other: &Generator) -> bool { + self.as_raw().eq(other.as_raw()) + } +} diff --git a/src/elliptic/curves/wrappers/point_z.rs b/src/elliptic/curves/wrappers/point_z.rs new file mode 100644 index 00000000..14f71751 --- /dev/null +++ b/src/elliptic/curves/wrappers/point_z.rs @@ -0,0 +1,191 @@ +use std::convert::TryFrom; +use std::fmt; + +use serde::{Deserialize, Serialize}; + +use crate::elliptic::curves::traits::*; +use crate::BigInt; + +use super::{ + error::{MismatchedPointOrder, PointZDeserializationError, PointZFromCoordsError}, + format::PointFormat, + Generator, Point, PointRef, +}; + +/// Either an elliptic point of a [group order](super::Scalar::group_order), or a zero point +/// +/// ## Security +/// +/// Mistakenly used zero point might break security of cryptographic algorithm. It's preferred to +/// use [`Point`](Point) that's guaranteed to be non-zero. Use [ensure_nonzero](PointZ::ensure_nonzero) +/// to convert `PointZ` into `Point`. +/// +/// ## Guarantees +/// +/// * On curve +/// +/// Any instance of `PointZ` is guaranteed to belong to curve `E`, i.e. its coordinates must +/// satisfy curve equations +/// * Point order equals to [group order](super::Scalar::group_order) (unless it's zero point) +/// +/// I.e. denoting `q = group_order`, following predicate is always true: +/// `P = O ∨ qP = O ∧ forall 0 < s < q. sP ≠ O` +/// +/// ## Arithmetics +/// +/// You can add, subtract two points, or multiply point at scalar: +/// +/// ```rust +/// # use curv::elliptic::curves::{PointZ, Scalar, Secp256k1}; +/// fn expression( +/// a: PointZ, +/// b: PointZ, +/// c: Scalar, +/// ) -> PointZ { +/// a + b * c +/// } +/// ``` +#[derive(Serialize, Deserialize)] +#[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] +pub struct PointZ { + raw_point: E::Point, +} + +impl PointZ { + /// Checks if `self` is not zero and converts it into [`Point`](Point). Returns `None` if + /// it's zero. + pub fn ensure_nonzero(self) -> Option> { + Point::try_from(self).ok() + } + + /// Constructs zero point + /// + /// Zero point (or curve neutral element) is usually denoted as `O`. Its property: `forall A. A + O = A`. + /// + /// Weierstrass and Montgomery curves employ special "point at infinity" that represent a neutral + /// element, such points don't have coordinates (i.e. [from_coords], [x_coord], [y_coord] return + /// `None`). Edwards curves' neutral element has coordinates. + /// + /// [from_coords]: Self::from_coords + /// [x_coord]: Self::x_coord + /// [y_coord]: Self::y_coord + pub fn zero() -> Self { + // Safety: `self` can be constructed to hold a zero point + unsafe { Self::from_raw_unchecked(E::Point::zero()) } + } + + /// Checks whether point is zero + pub fn is_zero(&self) -> bool { + self.as_raw().is_zero() + } + + /// Returns point coordinates + /// + /// Point might not have coordinates (specifically, "point at infinity" doesn't), in this case + /// `None` is returned + pub fn coords(&self) -> Option { + self.as_raw().coords() + } + + /// Returns point x coordinate + /// + /// See [coords](Self::coords) method that retrieves both x and y at once. + pub fn x_coord(&self) -> Option { + self.as_raw().x_coord() + } + + /// Returns point y coordinate + /// + /// See [coords](Self::coords) method that retrieves both x and y at once. + pub fn y_coord(&self) -> Option { + self.as_raw().y_coord() + } + + /// Constructs a point from its coordinates, returns error if coordinates don't satisfy + /// curve equation or if point has invalid order + pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { + let raw_point = E::Point::from_coords(x, y) + .map_err(|_: NotOnCurve| PointZFromCoordsError::NotOnCurve)?; + Self::from_raw(raw_point).map_err(PointZFromCoordsError::InvalidPoint) + } + + /// Tries to parse a point in (un)compressed form + /// + /// Whether it's in compressed or uncompressed form will be deduced from its length + pub fn from_bytes(bytes: &[u8]) -> Result { + let p = E::Point::deserialize(bytes) + .map_err(|_: DeserializationError| PointZDeserializationError::DeserializationError)?; + Self::from_raw(p).map_err(PointZDeserializationError::InvalidPoint) + } + + /// Serializes a point in (un)compressed form + /// + /// Returns `None` if it's point at infinity + pub fn to_bytes(&self, compressed: bool) -> Option> { + self.as_raw().serialize(compressed) + } + + pub fn from_raw(raw_point: E::Point) -> Result { + if raw_point.is_zero() || raw_point.check_point_order_equals_group_order() { + Ok(Self { raw_point }) + } else { + Err(MismatchedPointOrder(())) + } + } + + pub unsafe fn from_raw_unchecked(raw_point: E::Point) -> Self { + Self { raw_point } + } + + pub fn as_raw(&self) -> &E::Point { + &self.raw_point + } + + pub fn into_raw(self) -> E::Point { + self.raw_point + } +} + +impl PartialEq for PointZ { + fn eq(&self, other: &Self) -> bool { + self.raw_point.eq(&other.raw_point) + } +} + +impl PartialEq> for PointZ { + fn eq(&self, other: &Point) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl<'p, E: Curve> PartialEq> for PointZ { + fn eq(&self, other: &PointRef<'p, E>) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl PartialEq> for PointZ { + fn eq(&self, other: &Generator) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl Clone for PointZ { + fn clone(&self) -> Self { + // Safety: self is guaranteed to have correct order + unsafe { PointZ::from_raw_unchecked(self.as_raw().clone()) } + } +} + +impl fmt::Debug for PointZ { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.raw_point.fmt(f) + } +} + +impl From> for PointZ { + fn from(p: Point) -> Self { + // Safety: `Point` is guaranteed to have correct order + unsafe { PointZ::from_raw_unchecked(p.into_raw()) } + } +} diff --git a/src/elliptic/curves/wrappers/scalar.rs b/src/elliptic/curves/wrappers/scalar.rs new file mode 100644 index 00000000..77b78285 --- /dev/null +++ b/src/elliptic/curves/wrappers/scalar.rs @@ -0,0 +1,185 @@ +use std::convert::TryFrom; +use std::fmt; + +use serde::{Deserialize, Serialize}; + +use crate::elliptic::curves::traits::*; +use crate::BigInt; + +use super::{error::ZeroScalarError, format::ScalarFormat, ScalarZ}; + +/// Scalar value in a prime field that _guaranteed_ to be non zero +/// +/// ## Security +/// +/// Non-zero scalars are preferred to be used in cryptographic algorithms. Lack of checking whether +/// computation on field scalars results into zero scalar might lead to vulnerability. Using `Scalar` +/// ensures you and reviewers that check on scalar not being zero was made. +/// +/// ## Guarantees +/// +/// * Belongs to the curve prime field +/// +/// Denoting group order as `n`, any instance `s` of `Scalar` is guaranteed to be less than `n`: +/// `s < n` +/// * Not a zero +/// +/// Any instance `s` of `Scalar` is guaranteed to be more than zero: `s > 0` +/// +/// Combining two rules above, any instance `s` of `Scalar` is guaranteed to be: `0 < s < n`. +/// +/// ## Arithmetic +/// +/// Supported operations: +/// * Unary: you can [invert](Self::invert) and negate a scalar by modulo of prime field +/// * Binary: you can add, subtract, and multiply two points +/// +/// Addition or subtraction of two (even non-zero) scalars might result into zero +/// scalar, so these operations output [ScalarZ]. Use [ensure_nonzero](ScalarZ::ensure_nonzero) method +/// to ensure that computation doesn't produce zero scalar: +/// +/// ```rust +/// # use curv::elliptic::curves::{ScalarZ, Scalar, Secp256k1}; +/// let a = Scalar::::random(); +/// let b = Scalar::::random(); +/// let result: ScalarZ = a + b; +/// let non_zero_result: Option> = result.ensure_nonzero(); +/// ``` +/// +/// Multiplication of two nonzero scalars is always nonzero scalar (as scalar is by prime modulo): +/// +/// ```rust +/// # use curv::elliptic::curves::{ScalarZ, Scalar, Secp256k1}; +/// let a = Scalar::::random(); +/// let b = Scalar::::random(); +/// let result: Scalar = a * b; +/// ``` +#[derive(Serialize, Deserialize)] +#[serde(try_from = "ScalarFormat", into = "ScalarFormat", bound = "")] +pub struct Scalar { + raw_scalar: E::Scalar, +} + +impl Scalar { + /// Samples a random non-zero scalar + pub fn random() -> Self { + loop { + if let Some(scalar) = ScalarZ::from_raw(E::Scalar::random()).ensure_nonzero() { + break scalar; + } + } + } + + /// Returns modular multiplicative inverse of the scalar + /// + /// Inverse of non-zero scalar is always defined in a prime field, and inverted scalar is also + /// guaranteed to be non-zero. + pub fn invert(&self) -> Self { + self.as_raw() + .invert() + .map(|s| Scalar::from_raw(s).expect("inversion must be non-zero")) + .expect("non-zero scalar must have corresponding inversion") + } + + /// Returns a curve order + pub fn group_order() -> &'static BigInt { + E::Scalar::group_order() + } + + /// Converts a scalar to [BigInt] + pub fn to_bigint(&self) -> BigInt { + self.as_raw().to_bigint() + } + + /// Constructs a scalar from [BigInt] or returns error if it's zero + pub fn from_bigint(n: &BigInt) -> Result { + Self::from_raw(E::Scalar::from_bigint(n)) + } + + pub fn from_raw(raw_scalar: E::Scalar) -> Result { + if raw_scalar.is_zero() { + Err(ZeroScalarError(())) + } else { + Ok(Self { raw_scalar }) + } + } + + pub unsafe fn from_raw_unchecked(raw_scalar: E::Scalar) -> Self { + Self { raw_scalar } + } + + pub fn as_raw(&self) -> &E::Scalar { + &self.raw_scalar + } + + pub fn into_raw(self) -> E::Scalar { + self.raw_scalar + } +} + +impl Clone for Scalar { + fn clone(&self) -> Self { + // Safety: `self` is guaranteed to be non-zero + unsafe { Scalar::from_raw_unchecked(self.as_raw().clone()) } + } +} + +impl fmt::Debug for Scalar { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.as_raw().fmt(f) + } +} + +impl PartialEq for Scalar { + fn eq(&self, other: &Self) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl PartialEq> for Scalar { + fn eq(&self, other: &ScalarZ) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl TryFrom for Scalar { + type Error = ZeroScalarError; + fn try_from(n: u16) -> Result { + Self::from_bigint(&BigInt::from(n)) + } +} + +impl TryFrom for Scalar { + type Error = ZeroScalarError; + fn try_from(n: u32) -> Result { + Self::from_bigint(&BigInt::from(n)) + } +} + +impl TryFrom for Scalar { + type Error = ZeroScalarError; + fn try_from(n: u64) -> Result { + Self::from_bigint(&BigInt::from(n)) + } +} + +impl TryFrom for Scalar { + type Error = ZeroScalarError; + fn try_from(n: i32) -> Result { + Self::from_bigint(&BigInt::from(n)) + } +} + +impl TryFrom<&BigInt> for Scalar { + type Error = ZeroScalarError; + fn try_from(n: &BigInt) -> Result { + Self::from_bigint(n) + } +} + +impl TryFrom for Scalar { + type Error = ZeroScalarError; + fn try_from(n: BigInt) -> Result { + Self::from_bigint(&n) + } +} diff --git a/src/elliptic/curves/wrappers/scalar_z.rs b/src/elliptic/curves/wrappers/scalar_z.rs new file mode 100644 index 00000000..a94ea8f7 --- /dev/null +++ b/src/elliptic/curves/wrappers/scalar_z.rs @@ -0,0 +1,167 @@ +use std::fmt; + +use serde::{Deserialize, Serialize}; + +use crate::elliptic::curves::traits::{Curve, ECScalar}; +use crate::BigInt; + +use super::{format::ScalarFormat, Scalar}; + +/// Scalar value in a prime field that **might be zero** +/// +/// ## Security +/// +/// Mistakenly used zero scalar might break security of cryptographic algorithm. It's preferred to +/// use `Scalar`[Scalar] that's guaranteed to be non-zero. Use [ensure_nonzero](ScalarZ::ensure_nonzero) +/// to convert `ScalarZ` into `Scalar`. +/// +/// ## Guarantees +/// +/// * Modulus group order +/// +/// Denoting [group order](Self::group_order) as `n`, any instance `s` of `ScalarZ` is guaranteed +/// to be non-negative integer modulo `n`: `0 <= s < n` +/// +/// ## Arithmetics +/// +/// Supported operations: +/// * Unary: you can [invert](Self::invert) and negate a scalar +/// * Binary: you can add, subtract, and multiply two points +/// +/// ### Example +/// +/// ```rust +/// # use curv::elliptic::curves::{ScalarZ, Secp256k1}; +/// fn expression( +/// a: ScalarZ, +/// b: ScalarZ, +/// c: ScalarZ +/// ) -> ScalarZ { +/// a + b * c +/// } +/// ``` +#[derive(Serialize, Deserialize)] +#[serde(try_from = "ScalarFormat", into = "ScalarFormat", bound = "")] +pub struct ScalarZ { + raw_scalar: E::Scalar, +} + +impl ScalarZ { + /// Converts a scalar into [`Scalar`](ScalarZ) if it's non-zero, returns None otherwise + pub fn ensure_nonzero(self) -> Option> { + Scalar::from_raw(self.into_raw()).ok() + } + + /// Samples a random scalar + pub fn random() -> Self { + Self::from_raw(E::Scalar::random()) + } + + /// Constructs zero scalar + pub fn zero() -> Self { + Self::from_raw(E::Scalar::zero()) + } + + /// Checks if a scalar is zero + pub fn is_zero(&self) -> bool { + self.as_raw().is_zero() + } + + /// Converts a scalar to [BigInt] + pub fn to_bigint(&self) -> BigInt { + self.as_raw().to_bigint() + } + + /// Constructs a scalar `n % curve_order` from give `n` + pub fn from_bigint(n: &BigInt) -> Self { + Self::from_raw(E::Scalar::from_bigint(n)) + } + + /// Returns an order of generator point + pub fn group_order() -> &'static BigInt { + E::Scalar::group_order() + } + + /// Returns inversion `self^-1 mod curve_order`, or None if `self` is zero + pub fn invert(&self) -> Option { + self.as_raw().invert().map(Self::from_raw) + } + + pub fn from_raw(raw_scalar: E::Scalar) -> Self { + Self { raw_scalar } + } + + pub fn as_raw(&self) -> &E::Scalar { + &self.raw_scalar + } + + pub fn into_raw(self) -> E::Scalar { + self.raw_scalar + } +} + +impl Clone for ScalarZ { + fn clone(&self) -> Self { + Self::from_raw(self.as_raw().clone()) + } +} + +impl fmt::Debug for ScalarZ { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.as_raw().fmt(f) + } +} + +impl PartialEq for ScalarZ { + fn eq(&self, other: &Self) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl PartialEq> for ScalarZ { + fn eq(&self, other: &Scalar) -> bool { + self.as_raw().eq(other.as_raw()) + } +} + +impl From> for ScalarZ { + fn from(scalar: Scalar) -> Self { + ScalarZ::from_raw(scalar.into_raw()) + } +} + +impl From for ScalarZ { + fn from(n: u16) -> Self { + Self::from(&BigInt::from(n)) + } +} + +impl From for ScalarZ { + fn from(n: u32) -> Self { + Self::from(&BigInt::from(n)) + } +} + +impl From for ScalarZ { + fn from(n: u64) -> Self { + Self::from(&BigInt::from(n)) + } +} + +impl From for ScalarZ { + fn from(n: i32) -> Self { + Self::from(&BigInt::from(n)) + } +} + +impl From<&BigInt> for ScalarZ { + fn from(n: &BigInt) -> Self { + ScalarZ::from_raw(E::Scalar::from_bigint(n)) + } +} + +impl From for ScalarZ { + fn from(n: BigInt) -> Self { + Self::from(&n) + } +} From 1bedf0ad3c88093ad804b669c874a8ee4010010d Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 13:55:20 +0300 Subject: [PATCH 35/93] Update sigma_valid_pedersen --- src/cryptographic_primitives/proofs/mod.rs | 2 +- .../proofs/sigma_valid_pedersen.rs | 116 +++++++++--------- 2 files changed, 56 insertions(+), 62 deletions(-) diff --git a/src/cryptographic_primitives/proofs/mod.rs b/src/cryptographic_primitives/proofs/mod.rs index 4bd42fe1..bb33fa29 100644 --- a/src/cryptographic_primitives/proofs/mod.rs +++ b/src/cryptographic_primitives/proofs/mod.rs @@ -13,7 +13,7 @@ pub mod sigma_correct_homomorphic_elgamal_enc; pub mod sigma_correct_homomorphic_elgamal_encryption_of_dlog; pub mod sigma_dlog; pub mod sigma_ec_ddh; -// pub mod sigma_valid_pedersen; +pub mod sigma_valid_pedersen; // pub mod sigma_valid_pedersen_blind; #[derive(Debug, Clone, Copy)] diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs index d72859d6..9b54dca4 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs @@ -6,14 +6,14 @@ */ use serde::{Deserialize, Serialize}; -use zeroize::Zeroize; use super::ProofError; +use crate::arithmetic::*; use crate::cryptographic_primitives::commitments::pedersen_commitment::PedersenCommitment; use crate::cryptographic_primitives::commitments::traits::Commitment; use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; use crate::cryptographic_primitives::hashing::traits::Hash; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; /// protocol for proving that Pedersen commitment c was constructed correctly which is the same as /// proof of knowledge of (m,r) such that c = mG + rH. @@ -25,49 +25,44 @@ use crate::elliptic::curves::traits::*; /// /// verifier checks that z1*G + z2*H = A1 + A2 + ec #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct PedersenProof { - e: P::Scalar, - a1: P, - a2: P, - pub com: P, - z1: P::Scalar, - z2: P::Scalar, +pub struct PedersenProof { + e: ScalarZ, + a1: Point, + a2: Point, + pub com: PointZ, + z1: ScalarZ, + z2: ScalarZ, } -impl

PedersenProof

-where - P: ECPoint + Clone, - P::Scalar: Zeroize, -{ +impl PedersenProof { #[allow(clippy::many_single_char_names)] - pub fn prove(m: &P::Scalar, r: &P::Scalar) -> PedersenProof

{ - let g: P = ECPoint::generator(); - let h: P = ECPoint::base_point2(); - let mut s1: P::Scalar = ECScalar::new_random(); - let mut s2: P::Scalar = ECScalar::new_random(); - let a1 = g.scalar_mul(&s1.get_element()); - let a2 = h.scalar_mul(&s2.get_element()); - let com: P = PedersenCommitment::create_commitment_with_user_defined_randomness( - &m.to_big_int(), - &r.to_big_int(), + pub fn prove(m: &Scalar, r: &Scalar) -> PedersenProof { + let g = Point::::generator(); + let h = Point::::base_point2(); + let s1 = Scalar::random(); + let s2 = Scalar::random(); + let a1 = g * &s1; + let a2 = h * &s2; + let com: PointZ = PedersenCommitment::create_commitment_with_user_defined_randomness( + &m.to_bigint(), + &r.to_bigint(), ); - let g: P = ECPoint::generator(); let challenge = HSha256::create_hash(&[ - &g.bytes_compressed_to_big_int(), - &h.bytes_compressed_to_big_int(), - &com.bytes_compressed_to_big_int(), - &a1.bytes_compressed_to_big_int(), - &a2.bytes_compressed_to_big_int(), + &BigInt::from_bytes(&g.as_point().to_bytes(true)), + &BigInt::from_bytes(&h.to_bytes(true)), + &com.to_bytes(true) + .map(|b| BigInt::from_bytes(&b)) + .unwrap_or_else(|| BigInt::from_bytes(b"infinity point")), + &BigInt::from_bytes(&a1.to_bytes(true)), + &BigInt::from_bytes(&a2.to_bytes(true)), ]); - let e: P::Scalar = ECScalar::from(&challenge); + let e = ScalarZ::from(&challenge); - let em = e.mul(&m.get_element()); - let z1 = s1.add(&em.get_element()); - let er = e.mul(&r.get_element()); - let z2 = s2.add(&er.get_element()); - s1.zeroize(); - s2.zeroize(); + let em = &e * m; + let z1 = &s1 + em; + let er = &e * r; + let z2 = &s2 + er; PedersenProof { e, @@ -79,25 +74,28 @@ where } } - pub fn verify(proof: &PedersenProof

) -> Result<(), ProofError> { - let g: P = ECPoint::generator(); - let h: P = ECPoint::base_point2(); + pub fn verify(proof: &PedersenProof) -> Result<(), ProofError> { + let g = Point::::generator(); + let h = Point::::base_point2(); let challenge = HSha256::create_hash(&[ - &g.bytes_compressed_to_big_int(), - &h.bytes_compressed_to_big_int(), - &proof.com.bytes_compressed_to_big_int(), - &proof.a1.bytes_compressed_to_big_int(), - &proof.a2.bytes_compressed_to_big_int(), + &BigInt::from_bytes(&g.as_point().to_bytes(true)), + &BigInt::from_bytes(&h.to_bytes(true)), + &proof + .com + .to_bytes(true) + .map(|b| BigInt::from_bytes(&b)) + .unwrap_or_else(|| BigInt::from_bytes(b"infinity point")), + &BigInt::from_bytes(&proof.a1.to_bytes(true)), + &BigInt::from_bytes(&proof.a2.to_bytes(true)), ]); - let e: P::Scalar = ECScalar::from(&challenge); + let e = ScalarZ::from(challenge); - let z1g = g.scalar_mul(&proof.z1.get_element()); - let z2h = h.scalar_mul(&proof.z2.get_element()); - let lhs = z1g.add_point(&z2h.get_element()); - let rhs = proof.a1.add_point(&proof.a2.get_element()); - let com_clone = proof.com.clone(); - let ecom = com_clone.scalar_mul(&e.get_element()); - let rhs = rhs.add_point(&ecom.get_element()); + let z1g = g * &proof.z1; + let z2h = h * &proof.z2; + let lhs = &z1g + &z2h; + let rhs = &proof.a1 + &proof.a2; + let ecom = &proof.com * &e; + let rhs = rhs + &ecom; if lhs == rhs { Ok(()) @@ -112,14 +110,10 @@ mod tests { use super::*; crate::test_for_all_curves!(test_pedersen_proof); - fn test_pedersen_proof

() - where - P: ECPoint + Clone, - P::Scalar: Zeroize, - { - let m: P::Scalar = ECScalar::new_random(); - let r: P::Scalar = ECScalar::new_random(); - let pedersen_proof = PedersenProof::

::prove(&m, &r); + fn test_pedersen_proof() { + let m = Scalar::random(); + let r = Scalar::random(); + let pedersen_proof = PedersenProof::::prove(&m, &r); PedersenProof::verify(&pedersen_proof).expect("error pedersen"); } } From f30877cde96325289f385b8530d9926985e5e80a Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 14:08:47 +0300 Subject: [PATCH 36/93] Update sigma_valid_pedersen_blind --- src/cryptographic_primitives/proofs/mod.rs | 2 +- .../proofs/sigma_valid_pedersen_blind.rs | 105 +++++++++--------- 2 files changed, 52 insertions(+), 55 deletions(-) diff --git a/src/cryptographic_primitives/proofs/mod.rs b/src/cryptographic_primitives/proofs/mod.rs index bb33fa29..a3a8b33c 100644 --- a/src/cryptographic_primitives/proofs/mod.rs +++ b/src/cryptographic_primitives/proofs/mod.rs @@ -14,7 +14,7 @@ pub mod sigma_correct_homomorphic_elgamal_encryption_of_dlog; pub mod sigma_dlog; pub mod sigma_ec_ddh; pub mod sigma_valid_pedersen; -// pub mod sigma_valid_pedersen_blind; +pub mod sigma_valid_pedersen_blind; #[derive(Debug, Clone, Copy)] pub struct ProofError; diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs index 10df1cfe..a09d8aef 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs @@ -6,14 +6,15 @@ */ use serde::{Deserialize, Serialize}; -use zeroize::Zeroize; use super::ProofError; +use crate::arithmetic::Converter; use crate::cryptographic_primitives::commitments::pedersen_commitment::PedersenCommitment; use crate::cryptographic_primitives::commitments::traits::Commitment; use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; use crate::cryptographic_primitives::hashing::traits::Hash; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use crate::BigInt; /// protocol for proving that Pedersen commitment c was constructed correctly which is the same as /// proof of knowledge of (r) such that c = mG + rH. @@ -24,42 +25,39 @@ use crate::elliptic::curves::traits::*; /// prover sends pi = {e, m,A,c, z} /// verifier checks that emG + zH = A + ec #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct PedersenBlindingProof { - e: P::Scalar, - pub m: P::Scalar, - a: P, - pub com: P, - z: P::Scalar, +pub struct PedersenBlindingProof { + e: ScalarZ, + pub m: Scalar, + a: Point, + pub com: PointZ, + z: ScalarZ, } -impl

PedersenBlindingProof

-where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, -{ +impl PedersenBlindingProof { #[allow(clippy::many_single_char_names)] //TODO: add self verification to prover proof - pub fn prove(m: &P::Scalar, r: &P::Scalar) -> PedersenBlindingProof

{ - let h: P = ECPoint::base_point2(); - let mut s: P::Scalar = ECScalar::new_random(); - let a = h.scalar_mul(&s.get_element()); - let com: P = PedersenCommitment::create_commitment_with_user_defined_randomness( - &m.to_big_int(), - &r.to_big_int(), + pub fn prove(m: &Scalar, r: &Scalar) -> PedersenBlindingProof { + let h = Point::::base_point2(); + let s = Scalar::::random(); + let a = h * &s; + let com: PointZ = PedersenCommitment::create_commitment_with_user_defined_randomness( + &m.to_bigint(), + &r.to_bigint(), ); - let g: P = ECPoint::generator(); + let g = Point::::generator(); let challenge = HSha256::create_hash(&[ - &g.bytes_compressed_to_big_int(), - &h.bytes_compressed_to_big_int(), - &com.bytes_compressed_to_big_int(), - &a.bytes_compressed_to_big_int(), - &m.to_big_int(), + &BigInt::from_bytes(&g.as_point().to_bytes(true)), + &BigInt::from_bytes(&h.to_bytes(true)), + &com.to_bytes(true) + .map(|b| BigInt::from_bytes(&b)) + .unwrap_or_else(|| BigInt::from_bytes(b"infinity point")), + &BigInt::from_bytes(&a.to_bytes(true)), + &m.to_bigint(), ]); - let e: P::Scalar = ECScalar::from(&challenge); + let e = ScalarZ::from(&challenge); - let er = e.mul(&r.get_element()); - let z = s.add(&er.get_element()); - s.zeroize(); + let er = &e * r; + let z = &s + &er; PedersenBlindingProof { e, m: m.clone(), @@ -69,26 +67,29 @@ where } } - pub fn verify(proof: &PedersenBlindingProof

) -> Result<(), ProofError> { - let g: P = ECPoint::generator(); - let h: P = ECPoint::base_point2(); + pub fn verify(proof: &PedersenBlindingProof) -> Result<(), ProofError> { + let g = Point::::generator(); + let h = Point::::base_point2(); let challenge = HSha256::create_hash(&[ - &g.bytes_compressed_to_big_int(), - &h.bytes_compressed_to_big_int(), - &proof.com.bytes_compressed_to_big_int(), - &proof.a.bytes_compressed_to_big_int(), - &proof.m.to_big_int(), + &BigInt::from_bytes(&g.as_point().to_bytes(true)), + &BigInt::from_bytes(&h.to_bytes(true)), + &proof + .com + .to_bytes(true) + .map(|b| BigInt::from_bytes(&b)) + .unwrap_or_else(|| BigInt::from_bytes(b"infinity point")), + &BigInt::from_bytes(&proof.a.to_bytes(true)), + &proof.m.to_bigint(), ]); - let e: P::Scalar = ECScalar::from(&challenge); + let e = ScalarZ::from(&challenge); - let zh = h.scalar_mul(&proof.z.get_element()); - let mg = g.scalar_mul(&proof.m.get_element()); - let emg = mg.scalar_mul(&e.get_element()); - let lhs = zh.add_point(&emg.get_element()); - let com_clone = proof.com.clone(); - let ecom = com_clone.scalar_mul(&e.get_element()); - let rhs = ecom.add_point(&proof.a.get_element()); + let zh = h * &proof.z; + let mg = g * &proof.m; + let emg = mg * &e; + let lhs = zh + emg; + let ecom = &proof.com * &e; + let rhs = ecom + &proof.a; if lhs == rhs { Ok(()) @@ -103,14 +104,10 @@ mod tests { use super::*; crate::test_for_all_curves!(test_pedersen_blind_proof); - fn test_pedersen_blind_proof

() - where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, - { - let m: P::Scalar = ECScalar::new_random(); - let r: P::Scalar = ECScalar::new_random(); - let pedersen_proof = PedersenBlindingProof::

::prove(&m, &r); + fn test_pedersen_blind_proof() { + let m = Scalar::random(); + let r = Scalar::random(); + let pedersen_proof = PedersenBlindingProof::::prove(&m, &r); let _verified = PedersenBlindingProof::verify(&pedersen_proof).expect("error pedersen blind"); } From c3de0a8732ad4fac3205220ce4af129898c3bfa3 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 15:23:54 +0300 Subject: [PATCH 37/93] Fix derived Serialize/Deserialize traits --- .../proofs/sigma_correct_homomorphic_elgamal_enc.rs | 3 +++ .../sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs | 3 +++ src/cryptographic_primitives/proofs/sigma_dlog.rs | 1 + src/cryptographic_primitives/proofs/sigma_ec_ddh.rs | 1 + src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs | 1 + .../proofs/sigma_valid_pedersen_blind.rs | 1 + src/cryptographic_primitives/secret_sharing/feldman_vss.rs | 1 + src/elliptic/curves/secp256_k1.rs | 3 ++- src/elliptic/curves/traits.rs | 2 +- 9 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs index 96cc4de7..a1bc53b7 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs @@ -20,6 +20,7 @@ use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; /// The relation R outputs 1 if D = xH+rY , E = rG (for the case of G=H this is ElGamal) /// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct HomoELGamalProof { pub T: PointZ, pub A3: Point, @@ -28,12 +29,14 @@ pub struct HomoELGamalProof { } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct HomoElGamalWitness { pub r: ScalarZ, pub x: ScalarZ, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct HomoElGamalStatement { pub G: Point, pub H: Point, diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs index 47f21e1e..ce425852 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs @@ -20,6 +20,7 @@ use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; /// The relation R outputs 1 if D = xG+rY , E = rG, Q = xG /// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct HomoELGamalDlogProof { pub A1: Point, pub A2: Point, @@ -29,12 +30,14 @@ pub struct HomoELGamalDlogProof { } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct HomoElGamalDlogWitness { pub r: Scalar, pub x: Scalar, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct HomoElGamalDlogStatement { pub G: Point, pub Y: Point, diff --git a/src/cryptographic_primitives/proofs/sigma_dlog.rs b/src/cryptographic_primitives/proofs/sigma_dlog.rs index dc429073..7e61102b 100644 --- a/src/cryptographic_primitives/proofs/sigma_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_dlog.rs @@ -26,6 +26,7 @@ use crate::BigInt; /// In Advances in Cryptology - CRYPTO ’86, Santa Barbara, California, USA, 1986, Proceedings, /// pages 186–194, 1986. #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct DLogProof { pub pk: Point, pub pk_t_rand_commitment: Point, diff --git a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs index d430f76c..8add23cc 100644 --- a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs +++ b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs @@ -25,6 +25,7 @@ use crate::elliptic::curves::{Curve, Point, Scalar, ScalarZ}; /// /// verifier checks that zG1 = A1 + eH1, zG2 = A2 + eH2 #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct ECDDHProof { pub a1: Point, pub a2: Point, diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs index 9b54dca4..68ec875d 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs @@ -25,6 +25,7 @@ use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; /// /// verifier checks that z1*G + z2*H = A1 + A2 + ec #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct PedersenProof { e: ScalarZ, a1: Point, diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs index a09d8aef..55c62860 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs @@ -25,6 +25,7 @@ use crate::BigInt; /// prover sends pi = {e, m,A,c, z} /// verifier checks that emG + zH = A + ec #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct PedersenBlindingProof { e: ScalarZ, pub m: Scalar, diff --git a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs index fd5f6e38..74e3e8d2 100644 --- a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs +++ b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs @@ -26,6 +26,7 @@ pub struct ShamirSecretSharing { /// implementation details: The code is using FE and GE. Each party is given an index from 1,..,n and a secret share of type FE. /// The index of the party is also the point on the polynomial where we treat this number as u32 but converting it to FE internally. #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct VerifiableSS { pub parameters: ShamirSecretSharing, pub commitments: Vec>, diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 49a8f53c..cdb11076 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -25,6 +25,7 @@ use secp256k1::constants::{ self, GENERATOR_X, GENERATOR_Y, SECRET_KEY_SIZE, UNCOMPRESSED_PUBLIC_KEY_SIZE, }; use secp256k1::{PublicKey, SecretKey}; +use serde::{Deserialize, Serialize}; use zeroize::{Zeroize, Zeroizing}; use crate::arithmetic::*; @@ -124,7 +125,7 @@ impl Zeroize for PK { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Secp256k1 {} impl Curve for Secp256k1 { diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 914cc905..92403b70 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -15,7 +15,7 @@ use crate::BigInt; /// Elliptic curve implementation /// /// Refers to according implementation of [ECPoint] and [ECScalar]. -pub trait Curve { +pub trait Curve: PartialEq + Clone + fmt::Debug { type Point: ECPoint; type Scalar: ECScalar; From 7cb906f2864c4d78299fbd4e80b7d779493b3c18 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 15:24:12 +0300 Subject: [PATCH 38/93] Update coin_flip_optimal_rounds --- src/cryptographic_primitives/mod.rs | 2 +- .../twoparty/coin_flip_optimal_rounds.rs | 100 +++++++----------- src/cryptographic_primitives/twoparty/mod.rs | 32 +++--- 3 files changed, 55 insertions(+), 79 deletions(-) diff --git a/src/cryptographic_primitives/mod.rs b/src/cryptographic_primitives/mod.rs index 075f5b90..2a868030 100644 --- a/src/cryptographic_primitives/mod.rs +++ b/src/cryptographic_primitives/mod.rs @@ -9,4 +9,4 @@ pub mod commitments; pub mod hashing; pub mod proofs; pub mod secret_sharing; -// pub mod twoparty; +pub mod twoparty; diff --git a/src/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs b/src/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs index b80c031d..795919a4 100644 --- a/src/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs +++ b/src/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs @@ -7,95 +7,75 @@ use std::fmt::Debug; -use derivative::Derivative; use serde::{Deserialize, Serialize}; -use zeroize::Zeroize; use crate::cryptographic_primitives::proofs::sigma_valid_pedersen::PedersenProof; use crate::cryptographic_primitives::proofs::sigma_valid_pedersen_blind::PedersenBlindingProof; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::{Curve, PointZ, Scalar, ScalarZ}; /// based on How To Simulate It – A Tutorial on the Simulation /// Proof Technique. protocol 7.3: Multiple coin tossing. which provide simulatble constant round /// coin toss -#[derive(Derivative, Serialize, Deserialize)] -#[derivative(Clone(bound = "PedersenProof

: Clone"))] -#[derivative(Debug(bound = "PedersenProof

: Debug"))] -#[derivative(PartialEq(bound = "PedersenProof

: PartialEq"))] -#[serde(bound(serialize = "PedersenProof

: Serialize"))] -#[serde(bound(deserialize = "PedersenProof

: Deserialize<'de>"))] -pub struct Party1FirstMessage { - pub proof: PedersenProof

, +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct Party1FirstMessage { + pub proof: PedersenProof, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct Party2FirstMessage { - pub seed: P::Scalar, +#[serde(bound = "")] +pub struct Party2FirstMessage { + pub seed: Scalar, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct Party1SecondMessage { - pub proof: PedersenBlindingProof

, - pub seed: P::Scalar, +#[serde(bound = "")] +pub struct Party1SecondMessage { + pub proof: PedersenBlindingProof, + pub seed: Scalar, } -impl

Party1FirstMessage

-where - P: ECPoint + Clone, - P::Scalar: Zeroize, -{ - pub fn commit() -> (Party1FirstMessage

, P::Scalar, P::Scalar) { - let seed: P::Scalar = ECScalar::new_random(); - let blinding: P::Scalar = ECScalar::new_random(); +impl Party1FirstMessage { + pub fn commit() -> (Party1FirstMessage, Scalar, Scalar) { + let seed = Scalar::random(); + let blinding = Scalar::random(); let proof = PedersenProof::prove(&seed, &blinding); (Party1FirstMessage { proof }, seed, blinding) } } -impl

Party2FirstMessage

-where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, -{ - pub fn share(proof: &PedersenProof

) -> Party2FirstMessage

{ +impl Party2FirstMessage { + pub fn share(proof: &PedersenProof) -> Party2FirstMessage { PedersenProof::verify(&proof).expect("{(m,r),c} proof failed"); - let seed: P::Scalar = ECScalar::new_random(); + let seed = Scalar::random(); Party2FirstMessage { seed } } } -impl

Party1SecondMessage

-where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, -{ +impl Party1SecondMessage { pub fn reveal( - party2seed: &P::Scalar, - party1seed: &P::Scalar, - party1blinding: &P::Scalar, - ) -> (Party1SecondMessage

, P::Scalar) { - let proof = PedersenBlindingProof::

::prove(&party1seed, &party1blinding); - let coin_flip_result = &party1seed.to_big_int() ^ &party2seed.to_big_int(); + party2seed: &Scalar, + party1seed: &Scalar, + party1blinding: &Scalar, + ) -> (Party1SecondMessage, ScalarZ) { + let proof = PedersenBlindingProof::::prove(&party1seed, &party1blinding); + let coin_flip_result = &party1seed.to_bigint() ^ &party2seed.to_bigint(); ( Party1SecondMessage { proof, seed: party1seed.clone(), }, - ECScalar::from(&coin_flip_result), + ScalarZ::from(&coin_flip_result), ) } } // party2 finalize -pub fn finalize

( - proof: &PedersenBlindingProof

, - party2seed: &P::Scalar, - party1comm: &P, -) -> P::Scalar -where - P: ECPoint + Clone + Debug, - P::Scalar: Zeroize + Clone, -{ - PedersenBlindingProof::

::verify(&proof).expect("{r,(m,c)} proof failed"); +pub fn finalize( + proof: &PedersenBlindingProof, + party2seed: &Scalar, + party1comm: &PointZ, +) -> ScalarZ { + PedersenBlindingProof::::verify(&proof).expect("{r,(m,c)} proof failed"); assert_eq!(&proof.com, party1comm); - let coin_flip_result = &proof.m.to_big_int() ^ &party2seed.to_big_int(); - ECScalar::from(&coin_flip_result) + let coin_flip_result = &proof.m.to_bigint() ^ &party2seed.to_bigint(); + ScalarZ::from(&coin_flip_result) } #[cfg(test)] @@ -103,15 +83,11 @@ mod tests { use super::*; crate::test_for_all_curves!(test_coin_toss); - pub fn test_coin_toss

() - where - P: ECPoint + Clone + Debug, - P::Scalar: PartialEq + Clone + Debug + Zeroize, - { - let (party1_first_message, m1, r1) = Party1FirstMessage::

::commit(); + pub fn test_coin_toss() { + let (party1_first_message, m1, r1) = Party1FirstMessage::::commit(); let party2_first_message = Party2FirstMessage::share(&party1_first_message.proof); let (party1_second_message, random1) = - Party1SecondMessage::

::reveal(&party2_first_message.seed, &m1, &r1); + Party1SecondMessage::::reveal(&party2_first_message.seed, &m1, &r1); let random2 = finalize( &party1_second_message.proof, &party2_first_message.seed, diff --git a/src/cryptographic_primitives/twoparty/mod.rs b/src/cryptographic_primitives/twoparty/mod.rs index d4cb0d8b..c0dce920 100644 --- a/src/cryptographic_primitives/twoparty/mod.rs +++ b/src/cryptographic_primitives/twoparty/mod.rs @@ -11,20 +11,20 @@ /// Proof Technique∗" (https://eprint.iacr.org/2016/046.pdf) pub mod coin_flip_optimal_rounds; -///This is an implementation of a Diffie Hellman Key Exchange. -/// Party1 private key is "x", -/// Party2 private key is "y", -/// The shared secret is Q = xyG -pub mod dh_key_exchange; +// ///This is an implementation of a Diffie Hellman Key Exchange. +// /// Party1 private key is "x", +// /// Party2 private key is "y", +// /// The shared secret is Q = xyG +// pub mod dh_key_exchange; -///This is an implementation of a Diffie Hellman Key Exchange. -/// Party1 private key is "x", -/// Party2 private key is "y", -///protocol: -/// party1 sends a commitmemt to P1 = xG a commitment to a proof of knowledge of x -/// party2 sends P2 and a proof of knowledge of y -/// party1 verifies party2 proof decommit to P1 and to the PoK -/// party2 verifies party1 proof -/// the shared secret is Q = xyG -/// reference can be found in protocol 3.1 step 1 - 3(b) in the paper https://eprint.iacr.org/2017/552.pdf -pub mod dh_key_exchange_variant_with_pok_comm; +// ///This is an implementation of a Diffie Hellman Key Exchange. +// /// Party1 private key is "x", +// /// Party2 private key is "y", +// ///protocol: +// /// party1 sends a commitmemt to P1 = xG a commitment to a proof of knowledge of x +// /// party2 sends P2 and a proof of knowledge of y +// /// party1 verifies party2 proof decommit to P1 and to the PoK +// /// party2 verifies party1 proof +// /// the shared secret is Q = xyG +// /// reference can be found in protocol 3.1 step 1 - 3(b) in the paper https://eprint.iacr.org/2017/552.pdf +// pub mod dh_key_exchange_variant_with_pok_comm; From 6f5a51186b3e7adcef9a96281573be948285f619 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 15:34:29 +0300 Subject: [PATCH 39/93] Update dh_key_exchange --- .../twoparty/dh_key_exchange.rs | 103 +++++++----------- src/cryptographic_primitives/twoparty/mod.rs | 10 +- 2 files changed, 47 insertions(+), 66 deletions(-) diff --git a/src/cryptographic_primitives/twoparty/dh_key_exchange.rs b/src/cryptographic_primitives/twoparty/dh_key_exchange.rs index ed9a4a13..7baa02c5 100644 --- a/src/cryptographic_primitives/twoparty/dh_key_exchange.rs +++ b/src/cryptographic_primitives/twoparty/dh_key_exchange.rs @@ -12,37 +12,36 @@ use serde::{Deserialize, Serialize}; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::{Curve, Point, Scalar}; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct EcKeyPair { - pub public_share: P, - secret_share: P::Scalar, +#[serde(bound = "")] +pub struct EcKeyPair { + pub public_share: Point, + secret_share: Scalar, } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Party1FirstMessage { - pub public_share: P, +#[serde(bound = "")] +pub struct Party1FirstMessage { + pub public_share: Point, } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Party2FirstMessage { - pub public_share: P, +#[serde(bound = "")] +pub struct Party2FirstMessage { + pub public_share: Point, } #[derive(Debug, Serialize, Deserialize)] pub struct Party2SecondMessage {} -impl

Party1FirstMessage

-where - P: ECPoint + Clone, - P::Scalar: Clone, -{ - pub fn first() -> (Party1FirstMessage

, EcKeyPair

) { - let base: P = ECPoint::generator(); +impl Party1FirstMessage { + pub fn first() -> (Party1FirstMessage, EcKeyPair) { + let base = Point::::generator(); - let secret_share: P::Scalar = ECScalar::new_random(); + let secret_share = Scalar::random(); - let public_share = base * secret_share.clone(); + let public_share = base * &secret_share; let ec_key_pair = EcKeyPair { public_share: public_share.clone(), @@ -52,10 +51,9 @@ where } pub fn first_with_fixed_secret_share( - secret_share: P::Scalar, - ) -> (Party1FirstMessage

, EcKeyPair

) { - let base: P = ECPoint::generator(); - let public_share = base * secret_share.clone(); + secret_share: Scalar, + ) -> (Party1FirstMessage, EcKeyPair) { + let public_share = Point::generator() * secret_share.clone(); let ec_key_pair = EcKeyPair { public_share: public_share.clone(), @@ -65,15 +63,11 @@ where } } -impl

Party2FirstMessage

-where - P: ECPoint + Clone, - P::Scalar: Clone, -{ - pub fn first() -> (Party2FirstMessage

, EcKeyPair

) { - let base: P = ECPoint::generator(); - let secret_share: P::Scalar = ECScalar::new_random(); - let public_share = base * secret_share.clone(); +impl Party2FirstMessage { + pub fn first() -> (Party2FirstMessage, EcKeyPair) { + let base = Point::::generator(); + let secret_share = Scalar::random(); + let public_share = base * &secret_share; let ec_key_pair = EcKeyPair { public_share: public_share.clone(), secret_share, @@ -82,10 +76,9 @@ where } pub fn first_with_fixed_secret_share( - secret_share: P::Scalar, - ) -> (Party2FirstMessage

, EcKeyPair

) { - let base: P = ECPoint::generator(); - let public_share = base * secret_share.clone(); + secret_share: Scalar, + ) -> (Party2FirstMessage, EcKeyPair) { + let public_share = Point::generator() * &secret_share; let ec_key_pair = EcKeyPair { public_share: public_share.clone(), secret_share, @@ -94,32 +87,25 @@ where } } -pub fn compute_pubkey

(local_share: &EcKeyPair

, other_share_public_share: &P) -> P -where - P: ECPoint + Clone, - P::Scalar: Clone, -{ - other_share_public_share.clone() * local_share.secret_share.clone() +pub fn compute_pubkey( + local_share: &EcKeyPair, + other_share_public_share: &Point, +) -> Point { + other_share_public_share * &local_share.secret_share } #[cfg(test)] mod tests { - use std::fmt::Debug; - - use crate::arithmetic::traits::*; use crate::cryptographic_primitives::twoparty::dh_key_exchange::*; - use crate::elliptic::curves::traits::ECScalar; + use crate::elliptic::curves::Curve; use crate::test_for_all_curves; use crate::BigInt; + use std::convert::TryFrom; test_for_all_curves!(test_dh_key_exchange_random_shares); - fn test_dh_key_exchange_random_shares

() - where - P: ECPoint + Clone + Debug, - P::Scalar: Clone, - { - let (kg_party_one_first_message, kg_ec_key_pair_party1) = Party1FirstMessage::

::first(); - let (kg_party_two_first_message, kg_ec_key_pair_party2) = Party2FirstMessage::

::first(); + fn test_dh_key_exchange_random_shares() { + let (kg_party_one_first_message, kg_ec_key_pair_party1) = Party1FirstMessage::::first(); + let (kg_party_two_first_message, kg_ec_key_pair_party2) = Party2FirstMessage::::first(); assert_eq!( compute_pubkey( @@ -134,15 +120,11 @@ mod tests { } test_for_all_curves!(test_dh_key_exchange_fixed_shares); - fn test_dh_key_exchange_fixed_shares

() - where - P: ECPoint + Clone + Debug, - P::Scalar: Clone, - { - let secret_party_1: P::Scalar = ECScalar::from(&BigInt::one()); + fn test_dh_key_exchange_fixed_shares() { + let secret_party_1 = Scalar::try_from(&BigInt::from(1)).unwrap(); let (kg_party_one_first_message, kg_ec_key_pair_party1) = - Party1FirstMessage::

::first_with_fixed_secret_share(secret_party_1); - let secret_party_2: P::Scalar = ECScalar::from(&BigInt::from(2)); + Party1FirstMessage::::first_with_fixed_secret_share(secret_party_1); + let secret_party_2 = Scalar::try_from(&BigInt::from(2)).unwrap(); let (kg_party_two_first_message, kg_ec_key_pair_party2) = Party2FirstMessage::first_with_fixed_secret_share(secret_party_2.clone()); @@ -157,13 +139,12 @@ mod tests { &kg_party_two_first_message.public_share ) ); - let g: P = ECPoint::generator(); assert_eq!( compute_pubkey( &kg_ec_key_pair_party2, &kg_party_one_first_message.public_share ), - g * secret_party_2 + Point::generator() * secret_party_2 ); } } diff --git a/src/cryptographic_primitives/twoparty/mod.rs b/src/cryptographic_primitives/twoparty/mod.rs index c0dce920..a9e083aa 100644 --- a/src/cryptographic_primitives/twoparty/mod.rs +++ b/src/cryptographic_primitives/twoparty/mod.rs @@ -11,11 +11,11 @@ /// Proof Technique∗" (https://eprint.iacr.org/2016/046.pdf) pub mod coin_flip_optimal_rounds; -// ///This is an implementation of a Diffie Hellman Key Exchange. -// /// Party1 private key is "x", -// /// Party2 private key is "y", -// /// The shared secret is Q = xyG -// pub mod dh_key_exchange; +///This is an implementation of a Diffie Hellman Key Exchange. +/// Party1 private key is "x", +/// Party2 private key is "y", +/// The shared secret is Q = xyG +pub mod dh_key_exchange; // ///This is an implementation of a Diffie Hellman Key Exchange. // /// Party1 private key is "x", From 78012ea711d0a1e02ec99a168cad3ad6f178848b Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 15:53:45 +0300 Subject: [PATCH 40/93] Update dh_key_exchange_variant_with_pok_comm --- .../dh_key_exchange_variant_with_pok_comm.rs | 161 +++++++----------- src/cryptographic_primitives/twoparty/mod.rs | 22 +-- 2 files changed, 72 insertions(+), 111 deletions(-) diff --git a/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs b/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs index 5e9faeb7..63e9ff58 100644 --- a/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs +++ b/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs @@ -15,7 +15,6 @@ /// https://eprint.iacr.org/2017/552.pdf protocol 3.1 first 3 steps. use std::fmt::Debug; -use derivative::Derivative; use serde::{Deserialize, Serialize}; use crate::arithmetic::traits::*; @@ -23,28 +22,25 @@ use crate::cryptographic_primitives::commitments::hash_commitment::HashCommitmen use crate::cryptographic_primitives::commitments::traits::Commitment; use crate::cryptographic_primitives::proofs::sigma_dlog::*; use crate::cryptographic_primitives::proofs::ProofError; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::{Curve, Point, Scalar}; use crate::BigInt; -use zeroize::Zeroize; const SECURITY_BITS: usize = 256; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct EcKeyPair { - pub public_share: P, - secret_share: P::Scalar, +#[serde(bound = "")] +pub struct EcKeyPair { + pub public_share: Point, + secret_share: Scalar, } -#[derive(Serialize, Deserialize, Derivative)] -#[derivative(Clone(bound = "P: Clone, P::Scalar: Clone"))] -#[derivative(Debug(bound = "P: Debug, P::Scalar: Debug"))] -#[serde(bound(serialize = "P: Serialize, P::Scalar: Serialize"))] -#[serde(bound(deserialize = "P: Deserialize<'de>, P::Scalar: Deserialize<'de>"))] -pub struct CommWitness { +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct CommWitness { pub pk_commitment_blind_factor: BigInt, pub zk_pok_blind_factor: BigInt, - pub public_share: P, - pub d_log_proof: DLogProof

, + pub public_share: Point, + pub d_log_proof: DLogProof, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -52,52 +48,42 @@ pub struct Party1FirstMessage { pub pk_commitment: BigInt, pub zk_pok_commitment: BigInt, } -#[derive(Serialize, Deserialize, Derivative)] -#[derivative(Clone(bound = "P: Clone, P::Scalar: Clone"))] -#[derivative(Debug(bound = "P: Debug, P::Scalar: Debug"))] -#[serde(bound(serialize = "P: Serialize, P::Scalar: Serialize"))] -#[serde(bound(deserialize = "P: Deserialize<'de>, P::Scalar: Deserialize<'de>"))] -pub struct Party2FirstMessage { - pub d_log_proof: DLogProof

, - pub public_share: P, + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct Party2FirstMessage { + pub d_log_proof: DLogProof, + pub public_share: Point, } -#[derive(Serialize, Deserialize, Derivative)] -#[derivative(Debug(bound = "P: Debug, P::Scalar: Debug"))] -#[serde(bound(serialize = "P: Serialize, P::Scalar: Serialize"))] -#[serde(bound(deserialize = "P: Deserialize<'de>, P::Scalar: Deserialize<'de>"))] -pub struct Party1SecondMessage { - pub comm_witness: CommWitness

, +#[derive(Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct Party1SecondMessage { + pub comm_witness: CommWitness, } #[derive(Debug, Serialize, Deserialize)] pub struct Party2SecondMessage {} impl Party1FirstMessage { - pub fn create_commitments

() -> (Party1FirstMessage, CommWitness

, EcKeyPair

) - where - P: ECPoint + Clone, - P::Scalar: Zeroize, - { - let base: P = ECPoint::generator(); + pub fn create_commitments() -> (Party1FirstMessage, CommWitness, EcKeyPair) { + let base = Point::::generator(); - let secret_share: P::Scalar = ECScalar::new_random(); + let secret_share = Scalar::random(); - let public_share = base.scalar_mul(&secret_share.get_element()); + let public_share = base * &secret_share; - let d_log_proof = DLogProof::

::prove(&secret_share); + let d_log_proof = DLogProof::::prove(&secret_share); // we use hash based commitment let pk_commitment_blind_factor = BigInt::sample(SECURITY_BITS); let pk_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &public_share.bytes_compressed_to_big_int(), + &BigInt::from_bytes(&public_share.to_bytes(true)), &pk_commitment_blind_factor, ); let zk_pok_blind_factor = BigInt::sample(SECURITY_BITS); let zk_pok_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &d_log_proof - .pk_t_rand_commitment - .bytes_compressed_to_big_int(), + &BigInt::from_bytes(&d_log_proof.pk_t_rand_commitment.to_bytes(true)), &zk_pok_blind_factor, ); let ec_key_pair = EcKeyPair { @@ -119,29 +105,23 @@ impl Party1FirstMessage { ) } - pub fn create_commitments_with_fixed_secret_share

( - secret_share: P::Scalar, - ) -> (Party1FirstMessage, CommWitness

, EcKeyPair

) - where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, - { - let base: P = ECPoint::generator(); - let public_share = base * secret_share.clone(); + pub fn create_commitments_with_fixed_secret_share( + secret_share: Scalar, + ) -> (Party1FirstMessage, CommWitness, EcKeyPair) { + let base = Point::::generator(); + let public_share = base * &secret_share; - let d_log_proof = DLogProof::

::prove(&secret_share); + let d_log_proof = DLogProof::::prove(&secret_share); let pk_commitment_blind_factor = BigInt::sample(SECURITY_BITS); let pk_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &public_share.bytes_compressed_to_big_int(), + &BigInt::from_bytes(&public_share.to_bytes(true)), &pk_commitment_blind_factor, ); let zk_pok_blind_factor = BigInt::sample(SECURITY_BITS); let zk_pok_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &d_log_proof - .pk_t_rand_commitment - .bytes_compressed_to_big_int(), + &BigInt::from_bytes(&d_log_proof.pk_t_rand_commitment.to_bytes(true)), &zk_pok_blind_factor, ); @@ -165,28 +145,20 @@ impl Party1FirstMessage { } } -impl

Party1SecondMessage

-where - P: ECPoint + Clone, - P::Scalar: Zeroize, -{ +impl Party1SecondMessage { pub fn verify_and_decommit( - comm_witness: CommWitness

, - proof: &DLogProof

, - ) -> Result, ProofError> { + comm_witness: CommWitness, + proof: &DLogProof, + ) -> Result, ProofError> { DLogProof::verify(proof)?; Ok(Party1SecondMessage { comm_witness }) } } -impl

Party2FirstMessage

-where - P: ECPoint + Clone, - P::Scalar: Zeroize + Clone, -{ - pub fn create() -> (Party2FirstMessage

, EcKeyPair

) { - let base: P = ECPoint::generator(); - let secret_share: P::Scalar = ECScalar::new_random(); - let public_share = base * secret_share.clone(); +impl Party2FirstMessage { + pub fn create() -> (Party2FirstMessage, EcKeyPair) { + let base = Point::::generator(); + let secret_share = Scalar::random(); + let public_share = base * &secret_share; let d_log_proof = DLogProof::prove(&secret_share); let ec_key_pair = EcKeyPair { public_share: public_share.clone(), @@ -202,10 +174,10 @@ where } pub fn create_with_fixed_secret_share( - secret_share: P::Scalar, - ) -> (Party2FirstMessage

, EcKeyPair

) { - let base: P = ECPoint::generator(); - let public_share = base * secret_share.clone(); + secret_share: Scalar, + ) -> (Party2FirstMessage, EcKeyPair) { + let base = Point::generator(); + let public_share = base * &secret_share; let d_log_proof = DLogProof::prove(&secret_share); let ec_key_pair = EcKeyPair { public_share: public_share.clone(), @@ -222,14 +194,10 @@ where } impl Party2SecondMessage { - pub fn verify_commitments_and_dlog_proof

( + pub fn verify_commitments_and_dlog_proof( party_one_first_message: &Party1FirstMessage, - party_one_second_message: &Party1SecondMessage

, - ) -> Result - where - P: ECPoint + Clone, - P::Scalar: Zeroize, - { + party_one_second_message: &Party1SecondMessage, + ) -> Result { let party_one_pk_commitment = &party_one_first_message.pk_commitment; let party_one_zk_pok_commitment = &party_one_first_message.zk_pok_commitment; let party_one_zk_pok_blind_factor = @@ -243,7 +211,7 @@ impl Party2SecondMessage { let mut flag = true; if party_one_pk_commitment != &HashCommitment::create_commitment_with_user_defined_randomness( - &party_one_public_share.bytes_compressed_to_big_int(), + &BigInt::from_bytes(&party_one_public_share.to_bytes(true)), &party_one_pk_commitment_blind_factor, ) { @@ -252,9 +220,7 @@ impl Party2SecondMessage { if party_one_zk_pok_commitment != &HashCommitment::create_commitment_with_user_defined_randomness( - &party_one_d_log_proof - .pk_t_rand_commitment - .bytes_compressed_to_big_int(), + &BigInt::from_bytes(&party_one_d_log_proof.pk_t_rand_commitment.to_bytes(true)), &party_one_zk_pok_blind_factor, ) { @@ -266,12 +232,11 @@ impl Party2SecondMessage { Ok(Party2SecondMessage {}) } } -pub fn compute_pubkey

(local_share: &EcKeyPair

, other_share_public_share: &P) -> P -where - P: ECPoint + Clone, - P::Scalar: Clone, -{ - other_share_public_share.clone() * local_share.secret_share.clone() +pub fn compute_pubkey( + local_share: &EcKeyPair, + other_share_public_share: &Point, +) -> Point { + other_share_public_share * &local_share.secret_share } #[cfg(test)] @@ -279,14 +244,10 @@ mod tests { use crate::cryptographic_primitives::twoparty::dh_key_exchange_variant_with_pok_comm::*; crate::test_for_all_curves!(test_dh_key_exchange); - fn test_dh_key_exchange

() - where - P: ECPoint + Clone + Debug, - P::Scalar: Zeroize + Clone, - { + fn test_dh_key_exchange() { let (kg_party_one_first_message, kg_comm_witness, kg_ec_key_pair_party1) = - Party1FirstMessage::create_commitments::

(); - let (kg_party_two_first_message, kg_ec_key_pair_party2) = Party2FirstMessage::

::create(); + Party1FirstMessage::create_commitments::(); + let (kg_party_two_first_message, kg_ec_key_pair_party2) = Party2FirstMessage::::create(); let kg_party_one_second_message = Party1SecondMessage::verify_and_decommit( kg_comm_witness, &kg_party_two_first_message.d_log_proof, diff --git a/src/cryptographic_primitives/twoparty/mod.rs b/src/cryptographic_primitives/twoparty/mod.rs index a9e083aa..d4cb0d8b 100644 --- a/src/cryptographic_primitives/twoparty/mod.rs +++ b/src/cryptographic_primitives/twoparty/mod.rs @@ -17,14 +17,14 @@ pub mod coin_flip_optimal_rounds; /// The shared secret is Q = xyG pub mod dh_key_exchange; -// ///This is an implementation of a Diffie Hellman Key Exchange. -// /// Party1 private key is "x", -// /// Party2 private key is "y", -// ///protocol: -// /// party1 sends a commitmemt to P1 = xG a commitment to a proof of knowledge of x -// /// party2 sends P2 and a proof of knowledge of y -// /// party1 verifies party2 proof decommit to P1 and to the PoK -// /// party2 verifies party1 proof -// /// the shared secret is Q = xyG -// /// reference can be found in protocol 3.1 step 1 - 3(b) in the paper https://eprint.iacr.org/2017/552.pdf -// pub mod dh_key_exchange_variant_with_pok_comm; +///This is an implementation of a Diffie Hellman Key Exchange. +/// Party1 private key is "x", +/// Party2 private key is "y", +///protocol: +/// party1 sends a commitmemt to P1 = xG a commitment to a proof of knowledge of x +/// party2 sends P2 and a proof of knowledge of y +/// party1 verifies party2 proof decommit to P1 and to the PoK +/// party2 verifies party1 proof +/// the shared secret is Q = xyG +/// reference can be found in protocol 3.1 step 1 - 3(b) in the paper https://eprint.iacr.org/2017/552.pdf +pub mod dh_key_exchange_variant_with_pok_comm; From c3877dd73558d4d84edc7acc88de10ccc1409a14 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 15:57:26 +0300 Subject: [PATCH 41/93] Update diffie_hellman_key_exchange example --- examples/diffie_hellman_key_exchange.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/examples/diffie_hellman_key_exchange.rs b/examples/diffie_hellman_key_exchange.rs index a0a8bb4c..29187dc0 100644 --- a/examples/diffie_hellman_key_exchange.rs +++ b/examples/diffie_hellman_key_exchange.rs @@ -1,6 +1,4 @@ -use std::fmt::Debug; - -use curv::elliptic::curves::traits::ECPoint; +use curv::elliptic::curves::*; /// Diffie Hellman Key Exchange: /// TO RUN: @@ -11,17 +9,13 @@ use curv::elliptic::curves::traits::ECPoint; /// notice: this library includes also a more involved ECDH scheme. see /// dh_key_exchange_variant_with_pok_comm.rs -pub fn ecdh

() -where - P: ECPoint + Clone + Debug, - P::Scalar: Clone, -{ +pub fn ecdh() { use curv::cryptographic_primitives::twoparty::dh_key_exchange::{ compute_pubkey, Party1FirstMessage, Party2FirstMessage, }; - let (kg_party_one_first_message, kg_ec_key_pair_party1) = Party1FirstMessage::

::first(); - let (kg_party_two_first_message, kg_ec_key_pair_party2) = Party2FirstMessage::

::first(); + let (kg_party_one_first_message, kg_ec_key_pair_party1) = Party1FirstMessage::::first(); + let (kg_party_two_first_message, kg_ec_key_pair_party2) = Party2FirstMessage::::first(); assert_eq!( compute_pubkey( @@ -38,11 +32,11 @@ where fn main() { let curve_name = std::env::args().nth(1); match curve_name.as_deref() { - Some("secp256k1") => ecdh::(), - Some("ristretto") => ecdh::(), - Some("ed25519") => ecdh::(), - Some("bls12_381") => ecdh::(), - Some("p256") => ecdh::(), + Some("secp256k1") => ecdh::(), + // Some("ristretto") => ecdh::(), + // Some("ed25519") => ecdh::(), + // Some("bls12_381") => ecdh::(), + // Some("p256") => ecdh::(), Some(unknown_curve) => eprintln!("Unknown curve: {}", unknown_curve), None => eprintln!("Missing curve name"), } From c90c3fc19f718a92e2b4f6791968e13013aa4d43 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 16:00:22 +0300 Subject: [PATCH 42/93] Update pedersen_commitment --- examples/pedersen_commitment.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/examples/pedersen_commitment.rs b/examples/pedersen_commitment.rs index cc15ce16..b1331a21 100644 --- a/examples/pedersen_commitment.rs +++ b/examples/pedersen_commitment.rs @@ -1,5 +1,5 @@ -use curv::arithmetic::{traits::*, BigInt}; -use curv::elliptic::curves::traits::ECPoint; +use curv::arithmetic::*; +use curv::elliptic::curves::*; use std::fmt::Debug; @@ -14,16 +14,13 @@ use std::fmt::Debug; /// /// notice: this library includes also hash based commitments -pub fn ped_com

(message: &BigInt) -where - P: ECPoint + Debug, -{ +pub fn ped_com(message: &BigInt) { use curv::cryptographic_primitives::commitments::pedersen_commitment::PedersenCommitment; use curv::cryptographic_primitives::commitments::traits::Commitment; let security_bits = 256; let blinding_factor = BigInt::sample(security_bits); - let com = PedersenCommitment::

::create_commitment_with_user_defined_randomness( + let com = PedersenCommitment::::create_commitment_with_user_defined_randomness( message, &blinding_factor, ); @@ -36,15 +33,14 @@ where fn main() { let message = "commit me!"; - let message_bytes = message.as_bytes(); - let _message_bn = BigInt::from_bytes(message_bytes); + let _message_bn = BigInt::from_bytes(message.as_bytes()); let curve_name = std::env::args().nth(1); match curve_name.as_deref() { - Some("secp256k1") => ped_com::(&_message_bn), - Some("ristretto") => ped_com::(&_message_bn), - Some("ed25519") => ped_com::(&_message_bn), - Some("bls12_381") => ped_com::(&_message_bn), - Some("p256") => ped_com::(&_message_bn), + Some("secp256k1") => ped_com::(&_message_bn), + // Some("ristretto") => ped_com::(&_message_bn), + // Some("ed25519") => ped_com::(&_message_bn), + // Some("bls12_381") => ped_com::(&_message_bn), + // Some("p256") => ped_com::(&_message_bn), Some(unknown_curve) => eprintln!("Unknown curve: {}", unknown_curve), None => eprintln!("Missing curve name"), } From 0d5bbc29e3b76f02bad3c60ed20cde7a7be60a56 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 16:02:16 +0300 Subject: [PATCH 43/93] Update proof_of_knowledge_of_dlog example --- examples/proof_of_knowledge_of_dlog.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/examples/proof_of_knowledge_of_dlog.rs b/examples/proof_of_knowledge_of_dlog.rs index 0b3b1028..358fe409 100644 --- a/examples/proof_of_knowledge_of_dlog.rs +++ b/examples/proof_of_knowledge_of_dlog.rs @@ -1,5 +1,4 @@ -use curv::elliptic::curves::traits::ECPoint; -use zeroize::Zeroize; +use curv::elliptic::curves::*; /// Sigma protocol for proof of knowledge of discrete log /// TO RUN: @@ -10,27 +9,22 @@ use zeroize::Zeroize; /// notice: this library includes other more complex sigma protocol. /// see proofs folder for more details -pub fn dlog_proof

() -where - P: ECPoint + Clone, - P::Scalar: Zeroize, -{ +pub fn dlog_proof() { use curv::cryptographic_primitives::proofs::sigma_dlog::*; - use curv::elliptic::curves::traits::ECScalar; - let witness: P::Scalar = ECScalar::new_random(); - let dlog_proof = DLogProof::

::prove(&witness); + let witness = Scalar::random(); + let dlog_proof = DLogProof::::prove(&witness); assert!(DLogProof::verify(&dlog_proof).is_ok()); } fn main() { let curve_name = std::env::args().nth(1); match curve_name.as_deref() { - Some("secp256k1") => dlog_proof::(), - Some("ristretto") => dlog_proof::(), - Some("ed25519") => dlog_proof::(), - Some("bls12_381") => dlog_proof::(), - Some("p256") => dlog_proof::(), + Some("secp256k1") => dlog_proof::(), + // Some("ristretto") => dlog_proof::(), + // Some("ed25519") => dlog_proof::(), + // Some("bls12_381") => dlog_proof::(), + // Some("p256") => dlog_proof::(), Some(unknown_curve) => eprintln!("Unknown curve: {}", unknown_curve), None => eprintln!("Missing curve name"), } From 683986b15f1329339697ed207722c49899082269 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 16:05:18 +0300 Subject: [PATCH 44/93] Update verifiable_secret_sharing example --- examples/verifiable_secret_sharing.rs | 47 ++++++++++++--------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/examples/verifiable_secret_sharing.rs b/examples/verifiable_secret_sharing.rs index 870770e5..86ced47e 100644 --- a/examples/verifiable_secret_sharing.rs +++ b/examples/verifiable_secret_sharing.rs @@ -1,6 +1,4 @@ -use std::fmt::Debug; - -use curv::elliptic::curves::traits::ECPoint; +use curv::elliptic::curves::*; /// secret_sharing_3_out_of_5 /// Feldman VSS, based on Paul Feldman. 1987. A practical scheme for non-interactive verifiable secret sharing. @@ -13,17 +11,12 @@ use curv::elliptic::curves::traits::ECPoint; /// CURVE_NAME is any of the supported curves: i.e.: /// cargo run --example verifiable_secret_sharing -- ed25519 -pub fn secret_sharing_3_out_of_5

() -where - P: ECPoint + Clone, - P::Scalar: PartialEq + Clone + Debug, -{ +pub fn secret_sharing_3_out_of_5() { use curv::cryptographic_primitives::secret_sharing::feldman_vss::VerifiableSS; - use curv::elliptic::curves::traits::ECScalar; - let secret: P::Scalar = ECScalar::new_random(); + let secret = ScalarZ::random(); - let (vss_scheme, secret_shares) = VerifiableSS::

::share(3, 5, &secret); + let (vss_scheme, secret_shares) = VerifiableSS::::share(3, 5, &secret); let shares_vec = vec![ secret_shares[0].clone(), @@ -42,18 +35,18 @@ where assert!(valid3.is_ok()); assert!(valid1.is_ok()); - let g: P = ECPoint::generator(); - let share1_public = g * secret_shares[0].clone(); + let g = Point::generator(); + let share1_public = g * &secret_shares[0]; let valid1_public = vss_scheme.validate_share_public(&share1_public, 1); assert!(valid1_public.is_ok()); // test map (t,n) - (t',t') let s = &vec![0, 1, 2, 3, 4]; - let l0 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 0, &s); - let l1 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 1, &s); - let l2 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 2, &s); - let l3 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 3, &s); - let l4 = VerifiableSS::

::map_share_to_new_params(&vss_scheme.parameters, 4, &s); + let l0 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 0, &s); + let l1 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 1, &s); + let l2 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 2, &s); + let l3 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 3, &s); + let l4 = VerifiableSS::::map_share_to_new_params(&vss_scheme.parameters, 4, &s); let w = l0 * secret_shares[0].clone() + l1 * secret_shares[1].clone() @@ -66,15 +59,15 @@ where fn main() { let curve_name = std::env::args().nth(1); match curve_name.as_deref() { - Some("secp256k1") => secret_sharing_3_out_of_5::(), - Some("ristretto") => { - secret_sharing_3_out_of_5::() - } - Some("ed25519") => secret_sharing_3_out_of_5::(), - Some("bls12_381") => { - secret_sharing_3_out_of_5::() - } - Some("p256") => secret_sharing_3_out_of_5::(), + Some("secp256k1") => secret_sharing_3_out_of_5::(), + // Some("ristretto") => { + // secret_sharing_3_out_of_5::() + // } + // Some("ed25519") => secret_sharing_3_out_of_5::(), + // Some("bls12_381") => { + // secret_sharing_3_out_of_5::() + // } + // Some("p256") => secret_sharing_3_out_of_5::(), Some(unknown_curve) => eprintln!("Unknown curve: {}", unknown_curve), None => eprintln!("Missing curve name"), } From e88a14f7d640d2731743cfeb77dac8f88d55cebf Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 16:06:35 +0300 Subject: [PATCH 45/93] Fix warning --- examples/pedersen_commitment.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/pedersen_commitment.rs b/examples/pedersen_commitment.rs index b1331a21..b3ef26ed 100644 --- a/examples/pedersen_commitment.rs +++ b/examples/pedersen_commitment.rs @@ -1,8 +1,6 @@ use curv::arithmetic::*; use curv::elliptic::curves::*; -use std::fmt::Debug; - /// Pedesen Commitment: /// compute c = mG + rH /// where m is the commited value, G is the group generator, From 7b56c573a638a8444799a9504878077203aa448c Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 17:48:27 +0300 Subject: [PATCH 46/93] Fix clippy warnings --- .../proofs/sigma_dlog.rs | 2 +- src/cryptographic_primitives/twoparty/mod.rs | 4 +- src/elliptic/curves/mod.rs | 2 +- src/elliptic/curves/secp256_k1.rs | 2 +- src/elliptic/curves/wrappers/format.rs | 10 +++++ src/elliptic/curves/wrappers/point.rs | 36 +++++++++++++++ src/elliptic/curves/wrappers/point_ref.rs | 45 ++++++++++++++++--- src/elliptic/curves/wrappers/point_z.rs | 35 +++++++++++++++ src/elliptic/curves/wrappers/scalar.rs | 29 ++++++++++++ src/elliptic/curves/wrappers/scalar_z.rs | 19 ++++++++ 10 files changed, 172 insertions(+), 12 deletions(-) diff --git a/src/cryptographic_primitives/proofs/sigma_dlog.rs b/src/cryptographic_primitives/proofs/sigma_dlog.rs index 7e61102b..8c079163 100644 --- a/src/cryptographic_primitives/proofs/sigma_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_dlog.rs @@ -19,7 +19,7 @@ use crate::BigInt; /// sigma protocol for Proof of knowledge of the discrete log of an Elliptic-curve point: /// C.P. Schnorr. Efficient Identification and Signatures for Smart Cards. In /// CRYPTO 1989, Springer (LNCS 435), pages 239–252, 1990. -/// https://pdfs.semanticscholar.org/8d69/c06d48b618a090dd19185aea7a13def894a5.pdf. +/// . /// /// The protocol is using Fiat-Shamir Transform: Amos Fiat and Adi Shamir. /// How to prove yourself: Practical solutions to identification and signature problems. diff --git a/src/cryptographic_primitives/twoparty/mod.rs b/src/cryptographic_primitives/twoparty/mod.rs index d4cb0d8b..8acb0baf 100644 --- a/src/cryptographic_primitives/twoparty/mod.rs +++ b/src/cryptographic_primitives/twoparty/mod.rs @@ -8,7 +8,7 @@ /// This is an implementation of string coin tossing of a string, to generate a random string between ///two non-trusting parties. Based on the /// the protocol and proof analysis in "How To Simulate It – A Tutorial on the Simulation -/// Proof Technique∗" (https://eprint.iacr.org/2016/046.pdf) +/// Proof Technique∗" () pub mod coin_flip_optimal_rounds; ///This is an implementation of a Diffie Hellman Key Exchange. @@ -26,5 +26,5 @@ pub mod dh_key_exchange; /// party1 verifies party2 proof decommit to P1 and to the PoK /// party2 verifies party1 proof /// the shared secret is Q = xyG -/// reference can be found in protocol 3.1 step 1 - 3(b) in the paper https://eprint.iacr.org/2017/552.pdf +/// reference can be found in protocol 3.1 step 1 - 3(b) in the paper pub mod dh_key_exchange_variant_with_pok_comm; diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index baad6482..cd439b95 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -9,7 +9,7 @@ mod wrappers; pub use self::secp256_k1::Secp256k1; pub use self::{ - traits::{Curve, ECPoint, ECScalar}, + traits::{Curve, ECPoint, ECScalar, PointCoords}, wrappers::{Generator, Point, PointRef, PointZ, Scalar, ScalarZ}, }; diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index cdb11076..bf2edb45 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -554,7 +554,7 @@ impl ECPoint for Secp256k1Point { } }; - if let Err(_) = ge.mul_assign(&CONTEXT, &fe[..]) { + if ge.mul_assign(&CONTEXT, &fe[..]).is_err() { // Multiplication resulted into zero self.ge = None } diff --git a/src/elliptic/curves/wrappers/format.rs b/src/elliptic/curves/wrappers/format.rs index 75acd5c3..206943dc 100644 --- a/src/elliptic/curves/wrappers/format.rs +++ b/src/elliptic/curves/wrappers/format.rs @@ -97,6 +97,16 @@ impl From> for PointFormat { } } +impl<'p, E: Curve> From> for PointFormat { + fn from(point: PointRef<'p, E>) -> Self { + Self { + curve: E::CURVE_NAME.into(), + point: Some(point.coords()), + _ph: PhantomData, + } + } +} + #[derive(Debug, Error)] pub enum ConvertParsedPointError { #[error("invalid point ({0})")] diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index bf60d7dc..87452558 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -130,6 +130,16 @@ impl Point { PointRef::from(self) } + /// Constructs a `Point` from low-level [ECPoint] implementor + /// + /// Returns error if point is zero, or its order isn't equal to [group order]. + /// + /// Typically, you don't need to use this constructor. See [generator](Self::generator), + /// [base_point2](Self::base_point2), [from_coords](Self::from_coords), [from_bytes](Self::from_bytes) + /// constructors, and `From` and `TryFrom` traits implemented for `Point`. + /// + /// [ECPoint]: crate::elliptic::curves::ECPoint + /// [group order]: crate::elliptic::curves::ECScalar::group_order pub fn from_raw(raw_point: E::Point) -> Result { if raw_point.is_zero() { Err(InvalidPoint::ZeroPoint) @@ -140,14 +150,40 @@ impl Point { } } + /// Constructs a `Point` from low-level [ECPoint] implementor + /// + /// # Safety + /// + /// This function will not perform any checks against the point. You must guarantee that point + /// order is equal to curve [group order]. To perform this check, you may use + /// [ECPoint::check_point_order_equals_group_order][check_point_order_equals_group_order] + /// method. + /// + /// Note that it implies that point must not be zero (zero point has `order=1`). + /// + /// [ECPoint]: crate::elliptic::curves::ECPoint + /// [group order]: crate::elliptic::curves::ECScalar::group_order + /// [check_point_order_equals_group_order]: crate::elliptic::curves::ECPoint::check_point_order_equals_group_order pub unsafe fn from_raw_unchecked(point: E::Point) -> Self { Point { raw_point: point } } + /// Returns a reference to low-level point implementation + /// + /// Typically, you don't need to work with `ECPoint` trait directly. `Point` wraps `ECPoint` + /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization + /// traits, various getters (like [`.coords()`](Self::coords)). If you believe that some functionality + /// is missing, please [open an issue](https://github.com/ZenGo-X/curv). pub fn as_raw(&self) -> &E::Point { &self.raw_point } + /// Converts a point into inner low-level point implementation + /// + /// Typically, you don't need to work with `ECPoint` trait directly. `Point` wraps `ECPoint` + /// and provides convenient utilities around it, it implements arithmetic operators, (de)serialization + /// traits, various getters (like [`.coords()`](Self::coords)). If you believe that some functionality + /// is missing, please [open an issue](https://github.com/ZenGo-X/curv). pub fn into_raw(self) -> E::Point { self.raw_point } diff --git a/src/elliptic/curves/wrappers/point_ref.rs b/src/elliptic/curves/wrappers/point_ref.rs index 00b61656..3864d748 100644 --- a/src/elliptic/curves/wrappers/point_ref.rs +++ b/src/elliptic/curves/wrappers/point_ref.rs @@ -1,23 +1,23 @@ use std::fmt; +use serde::Serialize; + use crate::elliptic::curves::traits::*; use crate::BigInt; -use super::{error::InvalidPoint, Generator, Point, PointZ}; +use super::{error::InvalidPoint, format::PointFormat, Generator, Point, PointZ}; /// Reference on elliptic point of [group order](super::Scalar::group_order) /// /// Holds internally a reference on [`Point`](Point), refer to its documentation to learn /// more about Point/PointRef guarantees, security notes, and arithmetics. +#[derive(Serialize)] +#[serde(into = "PointFormat", bound = "")] pub struct PointRef<'p, E: Curve> { raw_point: &'p E::Point, } impl PointRef<'static, E> { - pub fn generator() -> Self { - Self::from_raw(E::Point::generator()).expect("generator must be non-zero") - } - pub fn base_point2() -> Self { Self::from_raw(E::Point::base_point2()).expect("base_point2 must be non-zero") } @@ -55,18 +55,28 @@ where } /// Serializes point into (un)compressed form - pub fn to_bytes(&self, compressed: bool) -> Vec { + pub fn to_bytes(self, compressed: bool) -> Vec { self.as_raw() .serialize(compressed) .expect("non-zero point must always be serializable") } /// Clones the referenced point - pub fn to_point(&self) -> Point { + pub fn to_point(self) -> Point { // Safety: `self` is guaranteed to have order = group_order unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } } + /// Constructs a `PointRef` from reference to low-level [ECPoint] implementor + /// + /// Returns error if point is zero, or its order isn't equal to [group order]. + /// + /// Typically, you don't need to use this constructor. See [generator](Point::generator), + /// [base_point2](Point::base_point2) constructors, and `From` and `TryFrom` traits + /// implemented for `Point` and `PointRef`. + /// + /// [ECPoint]: crate::elliptic::curves::ECPoint + /// [group order]: crate::elliptic::curves::ECScalar::group_order pub fn from_raw(raw_point: &'p E::Point) -> Result { if raw_point.is_zero() { Err(InvalidPoint::ZeroPoint) @@ -77,10 +87,31 @@ where } } + /// Constructs a `PointRef` from reference to low-level [ECPoint] implementor + /// + /// # Safety + /// + /// This function will not perform any checks against the point. You must guarantee that point + /// order is equal to curve [group order]. To perform this check, you may use + /// [ECPoint::check_point_order_equals_group_order][check_point_order_equals_group_order] + /// method. + /// + /// Note that it implies that point must not be zero (zero point has `order=1`). + /// + /// [ECPoint]: crate::elliptic::curves::ECPoint + /// [group order]: crate::elliptic::curves::ECScalar::group_order + /// [check_point_order_equals_group_order]: crate::elliptic::curves::ECPoint::check_point_order_equals_group_order pub unsafe fn from_raw_unchecked(raw_point: &'p E::Point) -> Self { PointRef { raw_point } } + /// Returns a reference to low-level point implementation + /// + /// Typically, you don't need to work with `ECPoint` trait directly. `PointRef` wraps a + /// reference to `ECPoint` implementation and provides convenient utilities around it: it + /// implements arithmetic operators, serialization trait, various getters (like + /// [`.coords()`](Self::coords)). If you believe that some functionality is missing, please + /// [open an issue](https://github.com/ZenGo-X/curv). pub fn as_raw(self) -> &'p E::Point { self.raw_point } diff --git a/src/elliptic/curves/wrappers/point_z.rs b/src/elliptic/curves/wrappers/point_z.rs index 14f71751..f2643308 100644 --- a/src/elliptic/curves/wrappers/point_z.rs +++ b/src/elliptic/curves/wrappers/point_z.rs @@ -125,6 +125,16 @@ impl PointZ { self.as_raw().serialize(compressed) } + /// Constructs a `Point` from low-level [ECPoint] implementor + /// + /// Returns error if point is zero, or its order isn't equal to [group order]. + /// + /// Typically, you don't need to use this constructor. See [generator](Point::generator), + /// [base_point2](Point::base_point2), [from_coords](Self::from_coords), [from_bytes](Self::from_bytes) + /// constructors, and `From` and `TryFrom` traits implemented for `PointZ`. + /// + /// [ECPoint]: crate::elliptic::curves::ECPoint + /// [group order]: crate::elliptic::curves::ECScalar::group_order pub fn from_raw(raw_point: E::Point) -> Result { if raw_point.is_zero() || raw_point.check_point_order_equals_group_order() { Ok(Self { raw_point }) @@ -133,14 +143,39 @@ impl PointZ { } } + /// Constructs a `PointZ` from low-level [ECPoint] implementor + /// + /// # Safety + /// + /// This function will not perform any checks against the point. You must guarantee that either + /// point order is equal to curve [group order] or it's a zero point. To perform this check, you + /// may use [ECPoint::check_point_order_equals_group_order][check_point_order_equals_group_order] + /// and [ECPoint::is_zero][is_zero] methods. + /// + /// [ECPoint]: crate::elliptic::curves::ECPoint + /// [group order]: crate::elliptic::curves::ECScalar::group_order + /// [check_point_order_equals_group_order]: crate::elliptic::curves::ECPoint::check_point_order_equals_group_order + /// [is_zero]: crate::elliptic::curves::ECPoint::is_zero pub unsafe fn from_raw_unchecked(raw_point: E::Point) -> Self { Self { raw_point } } + /// Returns a reference to low-level point implementation + /// + /// Typically, you don't need to work with `ECPoint` trait directly. `PointZ` wrapper + /// provides convenient utilities around it: it implements arithmetic operators, (de)serialization + /// traits, various getters (like [`.coords()`](Self::coords). If you believe that some functionality + /// is missing, please [open an issue](https://github.com/ZenGo-X/curv). pub fn as_raw(&self) -> &E::Point { &self.raw_point } + /// Converts a point into inner low-level point implementation + /// + /// Typically, you don't need to work with `ECPoint` trait directly. `PointZ` wraps `ECPoint` + /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization + /// traits, various getters (like [`.coords()`](Self::coords)). If you believe that some functionality + /// is missing, please [open an issue](https://github.com/ZenGo-X/curv). pub fn into_raw(self) -> E::Point { self.raw_point } diff --git a/src/elliptic/curves/wrappers/scalar.rs b/src/elliptic/curves/wrappers/scalar.rs index 77b78285..0b8add77 100644 --- a/src/elliptic/curves/wrappers/scalar.rs +++ b/src/elliptic/curves/wrappers/scalar.rs @@ -96,6 +96,15 @@ impl Scalar { Self::from_raw(E::Scalar::from_bigint(n)) } + /// Constructs a `Scalar` from low-level [ECScalar] implementor + /// + /// Returns error if scalar is zero + /// + /// Typically, you don't need to use this constructor. See [random](Self::random), + /// [from_bigint](Self::from_bigint) constructors, and `From`, `TryFrom` traits implemented + /// for `Scalar`. + /// + /// [ECScalar]: crate::elliptic::curves::ECScalar pub fn from_raw(raw_scalar: E::Scalar) -> Result { if raw_scalar.is_zero() { Err(ZeroScalarError(())) @@ -104,14 +113,34 @@ impl Scalar { } } + /// Constructs a `Scalar` from low-level [ECScalar] implementor + /// + /// # Safety + /// + /// This function will not perform any checks against the scalar. You must guarantee that scalar + /// is not zero. To perform this check, you may use [ECScalar::is_zero][is_zero] method. + /// + /// [is_zero]: crate::elliptic::curves::ECScalar::is_zero pub unsafe fn from_raw_unchecked(raw_scalar: E::Scalar) -> Self { Self { raw_scalar } } + /// Returns a reference to low-level scalar implementation + /// + /// Typically, you don't need to work with `ECScalar` trait directly. `Scalar` wraps `ECScalar` + /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization + /// traits, etc. If you believe that some functionality is missing, please + /// [open an issue](https://github.com/ZenGo-X/curv). pub fn as_raw(&self) -> &E::Scalar { &self.raw_scalar } + /// Converts a scalar into inner low-level scalar implementation + /// + /// Typically, you don't need to work with `ECScalar` trait directly. `Scalar` wraps `ECScalar` + /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization + /// traits, etc. If you believe that some functionality is missing, please + /// [open an issue](https://github.com/ZenGo-X/curv). pub fn into_raw(self) -> E::Scalar { self.raw_scalar } diff --git a/src/elliptic/curves/wrappers/scalar_z.rs b/src/elliptic/curves/wrappers/scalar_z.rs index a94ea8f7..2a11cfc1 100644 --- a/src/elliptic/curves/wrappers/scalar_z.rs +++ b/src/elliptic/curves/wrappers/scalar_z.rs @@ -87,14 +87,33 @@ impl ScalarZ { self.as_raw().invert().map(Self::from_raw) } + /// Constructs a `ScalarZ` from low-level [ECScalar] implementor + /// + /// Typically, you don't need to use this constructor. See [random](Self::random), + /// [from_bigint](Self::from_bigint) constructors, and `From`, `TryFrom` traits implemented + /// for `ScalarZ`. + /// + /// [ECScalar]: crate::elliptic::curves::ECScalar pub fn from_raw(raw_scalar: E::Scalar) -> Self { Self { raw_scalar } } + /// Returns a reference to low-level scalar implementation + /// + /// Typically, you don't need to work with `ECScalar` trait directly. `ScalarZ` wraps `ECScalar` + /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization + /// traits, etc. If you believe that some functionality is missing, please + /// [open an issue](https://github.com/ZenGo-X/curv). pub fn as_raw(&self) -> &E::Scalar { &self.raw_scalar } + /// Converts a scalar into inner low-level scalar implementation + /// + /// Typically, you don't need to work with `ECScalar` trait directly. `ScalarZ` wraps `ECScalar` + /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization + /// traits, etc. If you believe that some functionality is missing, please + /// [open an issue](https://github.com/ZenGo-X/curv). pub fn into_raw(self) -> E::Scalar { self.raw_scalar } From 48ea95a1953607a6b9c5272b22a51f058404ad3b Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 9 Jul 2021 18:07:54 +0300 Subject: [PATCH 47/93] Update doc --- .../proofs/low_degree_exponent_interpolation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs index b347cae8..22d04366 100644 --- a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs +++ b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs @@ -60,7 +60,7 @@ pub struct LdeiProof { } impl LdeiProof { - /// Constructs [LdeiStatement] and proves it correctness + /// Proves correctness of [LdeiStatement] /// /// ## Protocol /// From 64a3a578fdb126eaf807bf8ecdb5257d23ee0650 Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 11 Jul 2021 20:08:15 +0300 Subject: [PATCH 48/93] Improve hashing --- .../hashing/blake2b512.rs | 94 +++++- src/cryptographic_primitives/hashing/ext.rs | 311 ++++++++++++++++++ .../hashing/hash_sha256.rs | 3 + .../hashing/hash_sha512.rs | 3 + .../hashing/hmac_sha512.rs | 4 +- src/cryptographic_primitives/hashing/mod.rs | 4 + .../hashing/traits.rs | 2 + .../low_degree_exponent_interpolation.rs | 52 +-- .../sigma_correct_homomorphic_elgamal_enc.rs | 45 +-- ..._homomorphic_elgamal_encryption_of_dlog.rs | 40 +-- .../proofs/sigma_dlog.rs | 32 +- .../proofs/sigma_ec_ddh.rs | 28 +- .../proofs/sigma_valid_pedersen.rs | 46 ++- .../proofs/sigma_valid_pedersen_blind.rs | 48 ++- 14 files changed, 561 insertions(+), 151 deletions(-) create mode 100644 src/cryptographic_primitives/hashing/ext.rs diff --git a/src/cryptographic_primitives/hashing/blake2b512.rs b/src/cryptographic_primitives/hashing/blake2b512.rs index aa2d888c..d08ea729 100644 --- a/src/cryptographic_primitives/hashing/blake2b512.rs +++ b/src/cryptographic_primitives/hashing/blake2b512.rs @@ -4,14 +4,55 @@ (https://github.com/KZen-networks/curv) License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE */ +use blake2b_simd::{Params, State}; + use crate::arithmetic::traits::*; -use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; use crate::BigInt; -use blake2b_simd::Params; -pub struct Blake; +pub struct Blake { + state: State, +} impl Blake { + pub fn with_personal(persona: &[u8]) -> Self { + Self { + state: Params::new().hash_length(64).personal(persona).to_state(), + } + } + + pub fn chain_bigint(&mut self, n: &BigInt) -> &mut Self { + self.state.update(&n.to_bytes()); + self + } + + pub fn chain_point(&mut self, point: &Point) -> &mut Self { + self.state.update(&point.to_bytes(false)); + self + } + + pub fn chain_pointz(&mut self, point: &PointZ) -> &mut Self { + match point.to_bytes(false) { + Some(bytes) => self.state.update(&bytes), + None => self.state.update(b"point at infinity"), + }; + self + } + + pub fn result_bigint(&self) -> BigInt { + BigInt::from_bytes(self.state.finalize().as_ref()) + } + + pub fn result_scalar(&self) -> Scalar { + let n = self.result_bigint(); + let m = Scalar::::group_order() - 1; + Scalar::from_bigint(&(n.modulus(&m) + 1)).expect("scalar is guaranteed to be nonzero") + } + + #[deprecated( + since = "0.8.0", + note = "Blake API has been changed, this method is outdated" + )] pub fn create_hash(big_ints: &[&BigInt], persona: &[u8]) -> BigInt { let mut digest = Params::new().hash_length(64).personal(persona).to_state(); for value in big_ints { @@ -21,6 +62,10 @@ impl Blake { BigInt::from_bytes(digest.finalize().as_ref()) } + #[deprecated( + since = "0.8.0", + note = "Blake API has been changed, this method is outdated" + )] pub fn create_hash_from_ge(ge_vec: &[&Point], persona: &[u8]) -> ScalarZ { let mut digest = Params::new().hash_length(64).personal(persona).to_state(); // let mut digest = Blake2b::with_params(64, &[], &[], persona); @@ -33,6 +78,10 @@ impl Blake { ScalarZ::from(&result) } + #[deprecated( + since = "0.8.0", + note = "Blake API has been changed, this method is outdated" + )] pub fn create_hash_from_ge_z(ge_vec: &[&PointZ], persona: &[u8]) -> ScalarZ { let mut digest = Params::new().hash_length(64).personal(persona).to_state(); // let mut digest = Blake2b::with_params(64, &[], &[], persona); @@ -58,14 +107,24 @@ mod tests { #[test] // Very basic test here, TODO: suggest better testing - fn create_hash_test() { + fn create_hash_test_legacy() { + #![allow(deprecated)] let result = Blake::create_hash(&[&BigInt::one(), &BigInt::zero()], b"Zcash_RedJubjubH"); assert!(result > BigInt::zero()); } + #[test] + // Very basic test here, TODO: suggest better testing + fn create_hash_test() { + let result = Blake::with_personal(b"Zcash_RedJubjubH") + .chain_bigint(&BigInt::one()) + .chain_bigint(&BigInt::zero()) + .result_bigint(); + assert!(result > BigInt::zero()); + } - crate::test_for_all_curves!(create_hash_from_ge_test); - - fn create_hash_from_ge_test() { + crate::test_for_all_curves!(create_hash_from_ge_test_legacy); + fn create_hash_from_ge_test_legacy() { + #![allow(deprecated)] let base_point2 = Point::base_point2().to_point(); let generator = Point::generator().to_point(); let result1 = @@ -76,4 +135,25 @@ mod tests { let result3 = Blake::create_hash_from_ge(&[&generator, &base_point2], b"Zcash_RedJubjubH"); assert_eq!(result2, result3); } + + crate::test_for_all_curves!(create_hash_from_ge_test); + fn create_hash_from_ge_test() { + let base_point2 = Point::::base_point2().to_point(); + let generator = Point::::generator().to_point(); + let result1 = Blake::with_personal(b"Zcash_RedJubjubH") + .chain_point(&base_point2) + .chain_point(&generator) + .result_scalar::(); + assert!(result1.to_bigint().bit_length() > 240); + let result2 = Blake::with_personal(b"Zcash_RedJubjubH") + .chain_point(&generator) + .chain_point(&base_point2) + .result_scalar::(); + assert_ne!(result1, result2); + let result3 = Blake::with_personal(b"Zcash_RedJubjubH") + .chain_point(&generator) + .chain_point(&base_point2) + .result_scalar::(); + assert_eq!(result2, result3); + } } diff --git a/src/cryptographic_primitives/hashing/ext.rs b/src/cryptographic_primitives/hashing/ext.rs new file mode 100644 index 00000000..0e5446ee --- /dev/null +++ b/src/cryptographic_primitives/hashing/ext.rs @@ -0,0 +1,311 @@ +use digest::Digest; +use hmac::crypto_mac::MacError; +use hmac::{Hmac, Mac}; + +use crate::arithmetic::*; +use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; + +pub trait DigestExt { + fn input_bigint(&mut self, n: &BigInt); + fn input_point(&mut self, point: &Point); + fn input_pointz(&mut self, point: &PointZ); + fn input_scalar(&mut self, scalar: &Scalar); + fn input_scalarz(&mut self, scalar: &ScalarZ); + + fn chain_bigint(mut self, n: &BigInt) -> Self + where + Self: Sized, + { + self.input_bigint(n); + self + } + fn chain_point(mut self, point: &Point) -> Self + where + Self: Sized, + { + self.input_point(point); + self + } + fn chain_pointz(mut self, point: &PointZ) -> Self + where + Self: Sized, + { + self.input_pointz(point); + self + } + fn chain_scalar(mut self, scalar: &Scalar) -> Self + where + Self: Sized, + { + self.input_scalar(scalar); + self + } + fn chain_scalarz(mut self, scalar: &ScalarZ) -> Self + where + Self: Sized, + { + self.input_scalarz(scalar); + self + } + + fn result_bigint(self) -> BigInt; + fn result_scalar(self) -> Scalar; + + fn digest_bigint(bytes: &[u8]) -> BigInt; +} + +impl DigestExt for D +where + D: Digest, +{ + fn input_bigint(&mut self, n: &BigInt) { + self.input(&n.to_bytes()) + } + + fn input_point(&mut self, point: &Point) { + self.input(&point.to_bytes(false)) + } + + fn input_pointz(&mut self, point: &PointZ) { + match point.to_bytes(false) { + Some(bytes) => self.input(&bytes), + None => self.input(b"point at infinity"), + } + } + + fn input_scalar(&mut self, scalar: &Scalar) { + self.input(&scalar.to_bigint().to_bytes()) + } + fn input_scalarz(&mut self, scalar: &ScalarZ) { + self.input(&scalar.to_bigint().to_bytes()) + } + + fn result_bigint(self) -> BigInt { + let result = self.result(); + BigInt::from_bytes(&result) + } + + fn result_scalar(self) -> Scalar { + let n = self.result_bigint(); + let m = Scalar::::group_order() - 1; + Scalar::from_bigint(&(n.modulus(&m) + 1)).expect("scalar is guaranteed to be nonzero") + } + + fn digest_bigint(bytes: &[u8]) -> BigInt { + Self::new().chain(bytes).result_bigint() + } +} + +pub trait HmacExt: Sized { + fn new_bigint(key: &BigInt) -> Self; + + fn input_bigint(&mut self, n: &BigInt); + + fn chain_bigint(mut self, n: &BigInt) -> Self + where + Self: Sized, + { + self.input_bigint(n); + self + } + + fn result_bigint(self) -> BigInt; + fn verify_bigint(self, code: &BigInt) -> Result<(), MacError>; +} + +impl HmacExt for Hmac +where + D: digest::Input + digest::BlockInput + digest::FixedOutput + digest::Reset + Default + Clone, +{ + fn new_bigint(key: &BigInt) -> Self { + let bytes = key.to_bytes(); + Self::new_varkey(&bytes).expect("HMAC must take a key of any length") + } + + fn input_bigint(&mut self, n: &BigInt) { + self.input(&n.to_bytes()) + } + + fn result_bigint(self) -> BigInt { + BigInt::from_bytes(&self.result().code()) + } + + fn verify_bigint(self, code: &BigInt) -> Result<(), MacError> { + self.verify(&code.to_bytes()) + } +} + +#[cfg(test)] +mod test { + use sha2::{Sha256, Sha512}; + + use super::*; + + // Test Vectors taken from: + // https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs + #[test] + fn vector_sha256_test() { + // Empty Message + let result: BigInt = Sha256::new().result_bigint(); + assert_eq!( + result.to_hex(), + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ); + + // 256 bit message + let result: BigInt = Sha256::new() + .chain_bigint( + &BigInt::from_hex( + "09fc1accc230a205e4a208e64a8f204291f581a12756392da4b8c0cf5ef02b95", + ) + .unwrap(), + ) + .result_bigint(); + assert_eq!( + result.to_hex(), + "4f44c1c7fbebb6f9601829f3897bfd650c56fa07844be76489076356ac1886a4" + ); + + // 2x128 bit messages + let result: BigInt = Sha256::new() + .chain_bigint(&BigInt::from_hex("09fc1accc230a205e4a208e64a8f2042").unwrap()) + .chain_bigint(&BigInt::from_hex("91f581a12756392da4b8c0cf5ef02b95").unwrap()) + .result_bigint(); + assert_eq!( + result.to_hex(), + "4f44c1c7fbebb6f9601829f3897bfd650c56fa07844be76489076356ac1886a4" + ); + + // 512 bit message + let result: BigInt = Sha256::new() + .chain_bigint(&BigInt::from_hex("5a86b737eaea8ee976a0a24da63e7ed7eefad18a101c1211e2b3650c5187c2a8a650547208251f6d4237e661c7bf4c77f335390394c37fa1a9f9be836ac28509").unwrap()) + .result_bigint(); + assert_eq!( + result.to_hex(), + "42e61e174fbb3897d6dd6cef3dd2802fe67b331953b06114a65c772859dfc1aa" + ); + } + + #[test] + // Test Vectors taken from: + // https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs + fn vector_sha512_test() { + // Empty message + let result: BigInt = Sha512::new().result_bigint(); + assert_eq!( + result.to_hex(), + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + ); + + // 2x256 bit message + let result: BigInt = Sha512::new() + .chain_bigint( + &BigInt::from_hex( + "c1ca70ae1279ba0b918157558b4920d6b7fba8a06be515170f202fafd36fb7f7", + ) + .unwrap(), + ) + .chain_bigint( + &BigInt::from_hex( + "9d69fad745dba6150568db1e2b728504113eeac34f527fc82f2200b462ecbf5d", + ) + .unwrap(), + ) + .result_bigint(); + assert_eq!( + result.to_hex(), + "46e46623912b3932b8d662ab42583423843206301b58bf20ab6d76fd47f1cbbcf421df536ecd7e56db5354e7e0f98822d2129c197f6f0f222b8ec5231f3967d" + ); + + // 512 bit message + let result: BigInt = Sha512::new() + .chain_bigint(&BigInt::from_hex( + "c1ca70ae1279ba0b918157558b4920d6b7fba8a06be515170f202fafd36fb7f79d69fad745dba6150568db1e2b728504113eeac34f527fc82f2200b462ecbf5d").unwrap()) + .result_bigint(); + assert_eq!( + result.to_hex(), + "46e46623912b3932b8d662ab42583423843206301b58bf20ab6d76fd47f1cbbcf421df536ecd7e56db5354e7e0f98822d2129c197f6f0f222b8ec5231f3967d" + ); + + // 1024 bit message + let result: BigInt = Sha512::new() + .chain_bigint(&BigInt::from_hex("fd2203e467574e834ab07c9097ae164532f24be1eb5d88f1af7748ceff0d2c67a21f4e4097f9d3bb4e9fbf97186e0db6db0100230a52b453d421f8ab9c9a6043aa3295ea20d2f06a2f37470d8a99075f1b8a8336f6228cf08b5942fc1fb4299c7d2480e8e82bce175540bdfad7752bc95b577f229515394f3ae5cec870a4b2f8").unwrap()) + .result_bigint(); + assert_eq!( + result.to_hex(), + "a21b1077d52b27ac545af63b32746c6e3c51cb0cb9f281eb9f3580a6d4996d5c9917d2a6e484627a9d5a06fa1b25327a9d710e027387fc3e07d7c4d14c6086cc" + ); + } + + crate::test_for_all_curves!(create_sha512_from_ge_test); + fn create_sha256_from_ge_test() { + let generator = Point::::generator().to_point(); + let base_point2 = Point::::base_point2().to_point(); + let result1 = Sha256::new() + .chain_point(&generator) + .chain_point(&base_point2) + .result_scalar::(); + assert!(result1.to_bigint().bit_length() > 240); + let result2 = Sha256::new() + .chain_point(&base_point2) + .chain_point(&generator) + .result_scalar::(); + assert_ne!(result1, result2); + let result3 = Sha256::new() + .chain_point(&base_point2) + .chain_point(&generator) + .result_scalar::(); + assert_eq!(result2, result3); + } + + crate::test_for_all_curves!(create_sha256_from_ge_test); + fn create_sha512_from_ge_test() { + let generator = Point::::generator().to_point(); + let base_point2 = Point::::base_point2().to_point(); + let result1 = Sha512::new() + .chain_point(&generator) + .chain_point(&base_point2) + .result_scalar::(); + assert!(result1.to_bigint().bit_length() > 240); + let result2 = Sha512::new() + .chain_point(&base_point2) + .chain_point(&generator) + .result_scalar::(); + assert_ne!(result1, result2); + let result3 = Sha512::new() + .chain_point(&base_point2) + .chain_point(&generator) + .result_scalar::(); + assert_eq!(result2, result3); + } + + #[test] + fn create_hmac_test() { + let key = BigInt::sample(512); + let result1 = Hmac::::new_bigint(&key) + .chain_bigint(&BigInt::from(10)) + .result_bigint(); + assert!(Hmac::::new_bigint(&key) + .chain_bigint(&BigInt::from(10)) + .verify_bigint(&result1) + .is_ok()); + + let key2 = BigInt::sample(512); + // same data , different key + let result2 = Hmac::::new_bigint(&key2) + .chain_bigint(&BigInt::from(10)) + .result_bigint(); + assert_ne!(result1, result2); + // same key , different data + let result3 = Hmac::::new_bigint(&key) + .chain_bigint(&BigInt::from(10)) + .chain_bigint(&BigInt::from(11)) + .result_bigint(); + assert_ne!(result1, result3); + // same key, same data + let result4 = Hmac::::new_bigint(&key) + .chain_bigint(&BigInt::from(10)) + .result_bigint(); + assert_eq!(result1, result4) + } +} diff --git a/src/cryptographic_primitives/hashing/hash_sha256.rs b/src/cryptographic_primitives/hashing/hash_sha256.rs index f01757cb..a6664168 100644 --- a/src/cryptographic_primitives/hashing/hash_sha256.rs +++ b/src/cryptographic_primitives/hashing/hash_sha256.rs @@ -5,6 +5,8 @@ License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE */ +#![allow(deprecated)] + use super::traits::Hash; use crate::arithmetic::traits::*; use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; @@ -14,6 +16,7 @@ use sha2::Sha256; use crate::BigInt; +#[deprecated(since = "0.8.0", note = "use DigestExt instead")] pub struct HSha256; impl Hash for HSha256 { diff --git a/src/cryptographic_primitives/hashing/hash_sha512.rs b/src/cryptographic_primitives/hashing/hash_sha512.rs index 70530ef2..314d41d2 100644 --- a/src/cryptographic_primitives/hashing/hash_sha512.rs +++ b/src/cryptographic_primitives/hashing/hash_sha512.rs @@ -5,6 +5,8 @@ License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE */ +#![allow(deprecated)] + use super::traits::Hash; use crate::arithmetic::traits::*; use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; @@ -14,6 +16,7 @@ use sha2::Sha512; use crate::BigInt; +#[deprecated(since = "0.8.0", note = "use DigestExt instead")] pub struct HSha512; impl Hash for HSha512 { diff --git a/src/cryptographic_primitives/hashing/hmac_sha512.rs b/src/cryptographic_primitives/hashing/hmac_sha512.rs index 16c2fd90..5064c65e 100644 --- a/src/cryptographic_primitives/hashing/hmac_sha512.rs +++ b/src/cryptographic_primitives/hashing/hmac_sha512.rs @@ -5,6 +5,8 @@ License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE */ +#![allow(deprecated)] + use crate::BigInt; use super::traits::KeyedHash; @@ -15,6 +17,7 @@ use sha2::Sha512; use zeroize::Zeroize; type HmacSha256type = Hmac; +#[deprecated(since = "0.8.0", note = "use HmacExt instead")] pub struct HMacSha512; impl KeyedHash for HMacSha512 { @@ -49,7 +52,6 @@ impl KeyedHash for HMacSha512 { #[cfg(test)] mod tests { - use super::HMacSha512; use crate::arithmetic::traits::*; use crate::cryptographic_primitives::hashing::traits::KeyedHash; diff --git a/src/cryptographic_primitives/hashing/mod.rs b/src/cryptographic_primitives/hashing/mod.rs index a7943430..9de65bc0 100644 --- a/src/cryptographic_primitives/hashing/mod.rs +++ b/src/cryptographic_primitives/hashing/mod.rs @@ -10,3 +10,7 @@ pub mod hash_sha512; pub mod hmac_sha512; pub mod merkle_tree; pub mod traits; + +mod ext; +pub use digest::Digest; +pub use ext::*; diff --git a/src/cryptographic_primitives/hashing/traits.rs b/src/cryptographic_primitives/hashing/traits.rs index e6864acb..125a881d 100644 --- a/src/cryptographic_primitives/hashing/traits.rs +++ b/src/cryptographic_primitives/hashing/traits.rs @@ -8,6 +8,7 @@ use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; use crate::BigInt; +#[deprecated(since = "0.8.0", note = "use DigestExt instead")] pub trait Hash { fn create_hash(big_ints: &[&BigInt]) -> BigInt; fn create_hash_from_slice(byte_slice: &[u8]) -> BigInt; @@ -15,6 +16,7 @@ pub trait Hash { fn create_hash_from_ge_z(ge_vec: &[&PointZ]) -> ScalarZ; } +#[deprecated(since = "0.8.0", note = "use HmacExt instead")] pub trait KeyedHash { fn create_hmac(key: &BigInt, data: &[&BigInt]) -> BigInt; #[allow(clippy::result_unit_err)] diff --git a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs index 22d04366..aaf66e17 100644 --- a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs +++ b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs @@ -1,6 +1,8 @@ +use digest::Digest; + use thiserror::Error; -use crate::cryptographic_primitives::hashing::traits::Hash; +use crate::cryptographic_primitives::hashing::DigestExt; use crate::cryptographic_primitives::proofs::ProofError; use crate::cryptographic_primitives::secret_sharing::Polynomial; use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; @@ -73,7 +75,7 @@ impl LdeiProof { statement: &LdeiStatement, ) -> Result, InvalidLdeiStatement> where - H: Hash, + H: Digest, { if statement.alpha.len() != statement.g.len() { return Err(InvalidLdeiStatement::AlphaLengthDoesntMatchG); @@ -103,13 +105,17 @@ impl LdeiProof { .map(|(g, a)| g * u.evaluate(a)) .collect(); - let g: Vec> = statement - .g - .iter() - .map(|g| PointZ::from(g.clone())) - .collect(); - let hash_input: Vec<&PointZ> = g.iter().chain(&statement.x).chain(&a).collect(); - let e = H::create_hash_from_ge_z::(hash_input.as_slice()); + let mut h = H::new(); + for gi in &statement.g { + h.input_point(gi) + } + for xi in &statement.x { + h.input_pointz(xi) + } + for ai in &a { + h.input_pointz(ai) + } + let e = ScalarZ::from(h.result_scalar()); let z = &u - &(&witness.w * &e); @@ -125,15 +131,20 @@ impl LdeiProof { /// true, otherwise rejects. pub fn verify(&self, statement: &LdeiStatement) -> Result<(), ProofError> where - H: Hash, + H: Digest, { - let g: Vec> = statement - .g - .iter() - .map(|g| PointZ::from(g.clone())) - .collect(); - let hash_input: Vec<&PointZ> = g.iter().chain(&statement.x).chain(&self.a).collect(); - let e = H::create_hash_from_ge_z::(hash_input.as_slice()); + let mut h = H::new(); + for gi in &statement.g { + h.input_point(gi) + } + for xi in &statement.x { + h.input_pointz(xi) + } + for ai in &self.a { + h.input_pointz(ai) + } + let e = ScalarZ::from(h.result_scalar()); + if e != self.e { return Err(ProofError); } @@ -185,7 +196,8 @@ fn ensure_list_is_pairwise_distinct(list: &[S]) -> bool { mod tests { use std::iter; - use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; + use sha2::Sha256; + use crate::elliptic::curves::{Curve, Scalar}; use crate::test_for_all_curves; @@ -205,9 +217,9 @@ mod tests { let statement = LdeiStatement::new(&witness, alpha, g, d).unwrap(); - let proof = LdeiProof::prove::(&witness, &statement).expect("failed to prove"); + let proof = LdeiProof::prove::(&witness, &statement).expect("failed to prove"); proof - .verify::(&statement) + .verify::(&statement) .expect("failed to validate proof"); } } diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs index a1bc53b7..e31d9717 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs @@ -8,11 +8,14 @@ use serde::{Deserialize, Serialize}; -use super::ProofError; -use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; -use crate::cryptographic_primitives::hashing::traits::Hash; +use digest::Digest; +use sha2::Sha256; + +use crate::cryptographic_primitives::hashing::DigestExt; use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use super::ProofError; + /// This is a proof of knowledge that a pair of group elements {D, E} /// form a valid homomorphic ElGamal encryption (”in the exponent”) using public key Y . /// (HEG is defined in B. Schoenmakers and P. Tuyls. Practical Two-Party Computation Based on the Conditional Gate) @@ -56,15 +59,15 @@ impl HomoELGamalProof { let A2 = &delta.Y * &s2; let A3 = &delta.G * &s2; let T = A1 + A2; - let e = HSha256::create_hash_from_ge_z(&[ - &T, - &PointZ::from(A3.clone()), - &PointZ::from(delta.G.clone()), - &PointZ::from(delta.H.clone()), - &PointZ::from(delta.Y.clone()), - &delta.D, - &delta.E, - ]); + let e = Sha256::new() + .chain_pointz(&T) + .chain_point(&A3) + .chain_point(&delta.G) + .chain_point(&delta.H) + .chain_point(&delta.Y) + .chain_pointz(&delta.D) + .chain_pointz(&delta.E) + .result_scalar(); // dealing with zero field element let z1 = if !w.x.is_zero() { &s1 + &w.x * &e @@ -75,15 +78,15 @@ impl HomoELGamalProof { HomoELGamalProof { T, A3, z1, z2 } } pub fn verify(&self, delta: &HomoElGamalStatement) -> Result<(), ProofError> { - let e = HSha256::create_hash_from_ge_z(&[ - &self.T, - &PointZ::from(self.A3.clone()), - &PointZ::from(delta.G.clone()), - &PointZ::from(delta.H.clone()), - &PointZ::from(delta.Y.clone()), - &delta.D, - &delta.E, - ]); + let e = Sha256::new() + .chain_pointz(&self.T) + .chain_point(&self.A3) + .chain_point(&delta.G) + .chain_point(&delta.H) + .chain_point(&delta.Y) + .chain_pointz(&delta.D) + .chain_pointz(&delta.E) + .result_scalar(); let z1H_plus_z2Y = &delta.H * &self.z1 + &delta.Y * &self.z2; let T_plus_eD = &self.T + &delta.D * &e; let z2G = &delta.G * &self.z2; diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs index ce425852..29990b35 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs @@ -7,10 +7,10 @@ */ use serde::{Deserialize, Serialize}; +use sha2::Sha256; use super::ProofError; -use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; -use crate::cryptographic_primitives::hashing::traits::Hash; +use crate::cryptographic_primitives::hashing::{Digest, DigestExt}; use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; /// This is a proof of knowledge that a pair of group elements {D, E} @@ -56,30 +56,30 @@ impl HomoELGamalDlogProof { let A1 = &delta.G * &s1; let A2 = &delta.Y * &s2; let A3 = &delta.G * &s2; - let e = HSha256::create_hash_from_ge_z(&[ - &PointZ::from(A1.clone()), - &PointZ::from(A2.clone()), - &PointZ::from(A3.clone()), - &PointZ::from(delta.G.clone()), - &PointZ::from(delta.Y.clone()), - &delta.D, - &PointZ::from(delta.E.clone()), - ]); + let e = Sha256::new() + .chain_point(&A1) + .chain_point(&A2) + .chain_point(&A3) + .chain_point(&delta.G) + .chain_point(&delta.Y) + .chain_pointz(&delta.D) + .chain_point(&delta.E) + .result_scalar(); let z1 = &s1 + &e * &w.x; let z2 = &s2 + e * &w.r; HomoELGamalDlogProof { A1, A2, A3, z1, z2 } } pub fn verify(&self, delta: &HomoElGamalDlogStatement) -> Result<(), ProofError> { - let e = HSha256::create_hash_from_ge_z(&[ - &PointZ::from(self.A1.clone()), - &PointZ::from(self.A2.clone()), - &PointZ::from(self.A3.clone()), - &PointZ::from(delta.G.clone()), - &PointZ::from(delta.Y.clone()), - &delta.D, - &PointZ::from(delta.E.clone()), - ]); + let e = Sha256::new() + .chain_point(&self.A1) + .chain_point(&self.A2) + .chain_point(&self.A3) + .chain_point(&delta.G) + .chain_point(&delta.Y) + .chain_pointz(&delta.D) + .chain_point(&delta.E) + .result_scalar(); let z1G = &delta.G * &self.z1; let z2Y = &delta.Y * &self.z2; let z2G = &delta.G * &self.z2; diff --git a/src/cryptographic_primitives/proofs/sigma_dlog.rs b/src/cryptographic_primitives/proofs/sigma_dlog.rs index 8c079163..2b32264e 100644 --- a/src/cryptographic_primitives/proofs/sigma_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_dlog.rs @@ -6,14 +6,12 @@ */ use serde::{Deserialize, Serialize}; +use sha2::Sha256; -use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; -use crate::cryptographic_primitives::hashing::traits::Hash; +use crate::cryptographic_primitives::hashing::{Digest, DigestExt}; use crate::elliptic::curves::{Curve, Point, Scalar, ScalarZ}; use super::ProofError; -use crate::arithmetic::Converter; -use crate::BigInt; /// This is implementation of Schnorr's identification protocol for elliptic curve groups or a /// sigma protocol for Proof of knowledge of the discrete log of an Elliptic-curve point: @@ -42,14 +40,13 @@ impl DLogProof { let pk = Point::generator() * sk; - let challenge = HSha256::create_hash(&[ - &BigInt::from_bytes(&pk_t_rand_commitment.to_bytes(true)), - &BigInt::from_bytes(&generator.as_point().to_bytes(true)), - &BigInt::from_bytes(&pk.to_bytes(true)), - ]); + let challenge = Sha256::new() + .chain_point(&pk_t_rand_commitment) + .chain_point(&generator.to_point()) + .chain_point(&pk) + .result_scalar(); - let challenge_fe: ScalarZ = ScalarZ::from(&challenge); - let challenge_mul_sk = challenge_fe * sk; + let challenge_mul_sk = challenge * sk; let challenge_response = &sk_t_rand_commitment - &challenge_mul_sk; DLogProof { pk, @@ -61,14 +58,13 @@ impl DLogProof { pub fn verify(proof: &DLogProof) -> Result<(), ProofError> { let generator = Point::::generator(); - let challenge = HSha256::create_hash(&[ - &BigInt::from_bytes(&proof.pk_t_rand_commitment.to_bytes(true)), - &BigInt::from_bytes(&generator.as_point().to_bytes(true)), - &BigInt::from_bytes(&proof.pk.to_bytes(true)), - ]); + let challenge = Sha256::new() + .chain_point(&proof.pk_t_rand_commitment) + .chain_point(&generator.to_point()) + .chain_point(&proof.pk) + .result_scalar(); - let sk_challenge = ScalarZ::::from(&challenge); - let pk_challenge = &proof.pk * &sk_challenge; + let pk_challenge = &proof.pk * &challenge; let pk_verifier = generator * &proof.challenge_response + pk_challenge; diff --git a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs index 8add23cc..131305e2 100644 --- a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs +++ b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs @@ -6,12 +6,13 @@ */ use serde::{Deserialize, Serialize}; +use sha2::Sha256; -use super::ProofError; -use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; -use crate::cryptographic_primitives::hashing::traits::Hash; +use crate::cryptographic_primitives::hashing::{Digest, DigestExt}; use crate::elliptic::curves::{Curve, Point, Scalar, ScalarZ}; +use super::ProofError; + /// This protocol is the elliptic curve form of the protocol from : /// D. Chaum, T. P. Pedersen. Transferred cash grows in size. In Advances in Cryptology, EUROCRYPT , volume 658 of Lecture Notes in Computer Science, pages 390 - 407, 1993. /// This is a proof of membership of DDH: (G, xG, yG, xyG) @@ -50,16 +51,27 @@ impl ECDDHProof { let s = Scalar::random(); let a1 = &delta.g1 * &s; let a2 = &delta.g2 * &s; - let e = - HSha256::create_hash_from_ge(&[&delta.g1, &delta.h1, &delta.g2, &delta.h2, &a1, &a2]); + let e = Sha256::new() + .chain_point(&delta.g1) + .chain_point(&delta.h1) + .chain_point(&delta.g2) + .chain_point(&delta.h2) + .chain_point(&a1) + .chain_point(&a2) + .result_scalar(); let z = &s + e * &w.x; ECDDHProof { a1, a2, z } } pub fn verify(&self, delta: &ECDDHStatement) -> Result<(), ProofError> { - let e = HSha256::create_hash_from_ge(&[ - &delta.g1, &delta.h1, &delta.g2, &delta.h2, &self.a1, &self.a2, - ]); + let e = Sha256::new() + .chain_point(&delta.g1) + .chain_point(&delta.h1) + .chain_point(&delta.g2) + .chain_point(&delta.h2) + .chain_point(&self.a1) + .chain_point(&self.a2) + .result_scalar(); let z_g1 = &delta.g1 * &self.z; let z_g2 = &delta.g2 * &self.z; let a1_plus_e_h1 = &self.a1 + &delta.h1 * &e; diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs index 68ec875d..7fd3ce1c 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs @@ -6,15 +6,15 @@ */ use serde::{Deserialize, Serialize}; +use sha2::Sha256; -use super::ProofError; -use crate::arithmetic::*; use crate::cryptographic_primitives::commitments::pedersen_commitment::PedersenCommitment; use crate::cryptographic_primitives::commitments::traits::Commitment; -use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; -use crate::cryptographic_primitives::hashing::traits::Hash; +use crate::cryptographic_primitives::hashing::{Digest, DigestExt}; use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use super::ProofError; + /// protocol for proving that Pedersen commitment c was constructed correctly which is the same as /// proof of knowledge of (m,r) such that c = mG + rH. /// witness: (m,r), statement: c, The Relation R outputs 1 if c = mG + rH. The protocol: @@ -27,7 +27,7 @@ use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] #[serde(bound = "")] pub struct PedersenProof { - e: ScalarZ, + e: Scalar, a1: Point, a2: Point, pub com: PointZ, @@ -48,17 +48,14 @@ impl PedersenProof { &m.to_bigint(), &r.to_bigint(), ); - let challenge = HSha256::create_hash(&[ - &BigInt::from_bytes(&g.as_point().to_bytes(true)), - &BigInt::from_bytes(&h.to_bytes(true)), - &com.to_bytes(true) - .map(|b| BigInt::from_bytes(&b)) - .unwrap_or_else(|| BigInt::from_bytes(b"infinity point")), - &BigInt::from_bytes(&a1.to_bytes(true)), - &BigInt::from_bytes(&a2.to_bytes(true)), - ]); - let e = ScalarZ::from(&challenge); + let e = Sha256::new() + .chain_point(&g.to_point()) + .chain_point(&h.to_point()) + .chain_pointz(&com) + .chain_point(&a1) + .chain_point(&a2) + .result_scalar(); let em = &e * m; let z1 = &s1 + em; @@ -78,18 +75,13 @@ impl PedersenProof { pub fn verify(proof: &PedersenProof) -> Result<(), ProofError> { let g = Point::::generator(); let h = Point::::base_point2(); - let challenge = HSha256::create_hash(&[ - &BigInt::from_bytes(&g.as_point().to_bytes(true)), - &BigInt::from_bytes(&h.to_bytes(true)), - &proof - .com - .to_bytes(true) - .map(|b| BigInt::from_bytes(&b)) - .unwrap_or_else(|| BigInt::from_bytes(b"infinity point")), - &BigInt::from_bytes(&proof.a1.to_bytes(true)), - &BigInt::from_bytes(&proof.a2.to_bytes(true)), - ]); - let e = ScalarZ::from(challenge); + let e = Sha256::new() + .chain_point(&g.to_point()) + .chain_point(&h.to_point()) + .chain_pointz(&proof.com) + .chain_point(&proof.a1) + .chain_point(&proof.a2) + .result_scalar(); let z1g = g * &proof.z1; let z2h = h * &proof.z2; diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs index 55c62860..c615bfd9 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs @@ -6,15 +6,14 @@ */ use serde::{Deserialize, Serialize}; +use sha2::Sha256; -use super::ProofError; -use crate::arithmetic::Converter; use crate::cryptographic_primitives::commitments::pedersen_commitment::PedersenCommitment; use crate::cryptographic_primitives::commitments::traits::Commitment; -use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; -use crate::cryptographic_primitives::hashing::traits::Hash; +use crate::cryptographic_primitives::hashing::{Digest, DigestExt}; use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; -use crate::BigInt; + +use super::ProofError; /// protocol for proving that Pedersen commitment c was constructed correctly which is the same as /// proof of knowledge of (r) such that c = mG + rH. @@ -27,7 +26,7 @@ use crate::BigInt; #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] #[serde(bound = "")] pub struct PedersenBlindingProof { - e: ScalarZ, + e: Scalar, pub m: Scalar, a: Point, pub com: PointZ, @@ -46,16 +45,13 @@ impl PedersenBlindingProof { &r.to_bigint(), ); let g = Point::::generator(); - let challenge = HSha256::create_hash(&[ - &BigInt::from_bytes(&g.as_point().to_bytes(true)), - &BigInt::from_bytes(&h.to_bytes(true)), - &com.to_bytes(true) - .map(|b| BigInt::from_bytes(&b)) - .unwrap_or_else(|| BigInt::from_bytes(b"infinity point")), - &BigInt::from_bytes(&a.to_bytes(true)), - &m.to_bigint(), - ]); - let e = ScalarZ::from(&challenge); + let e = Sha256::new() + .chain_point(&g.to_point()) + .chain_point(&h.to_point()) + .chain_pointz(&com) + .chain_point(&a) + .chain_scalar(&m) + .result_scalar(); let er = &e * r; let z = &s + &er; @@ -71,19 +67,13 @@ impl PedersenBlindingProof { pub fn verify(proof: &PedersenBlindingProof) -> Result<(), ProofError> { let g = Point::::generator(); let h = Point::::base_point2(); - let challenge = HSha256::create_hash(&[ - &BigInt::from_bytes(&g.as_point().to_bytes(true)), - &BigInt::from_bytes(&h.to_bytes(true)), - &proof - .com - .to_bytes(true) - .map(|b| BigInt::from_bytes(&b)) - .unwrap_or_else(|| BigInt::from_bytes(b"infinity point")), - &BigInt::from_bytes(&proof.a.to_bytes(true)), - &proof.m.to_bigint(), - ]); - - let e = ScalarZ::from(&challenge); + let e = Sha256::new() + .chain_point(&g.to_point()) + .chain_point(&h.to_point()) + .chain_pointz(&proof.com) + .chain_point(&proof.a) + .chain_scalar(&proof.m) + .result_scalar(); let zh = h * &proof.z; let mg = g * &proof.m; From cddf56a5d5fd0aa9192f0a70b5e138629494a034 Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 11 Jul 2021 20:23:43 +0300 Subject: [PATCH 49/93] Write doc --- .../hashing/blake2b512.rs | 2 ++ src/cryptographic_primitives/hashing/ext.rs | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/cryptographic_primitives/hashing/blake2b512.rs b/src/cryptographic_primitives/hashing/blake2b512.rs index d08ea729..aac77b2d 100644 --- a/src/cryptographic_primitives/hashing/blake2b512.rs +++ b/src/cryptographic_primitives/hashing/blake2b512.rs @@ -10,6 +10,8 @@ use crate::arithmetic::traits::*; use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; use crate::BigInt; +/// Wrapper over [blake2b_simd](blake2b_simd::State) exposing facilities to hash bigints, elliptic points, +/// and scalars pub struct Blake { state: State, } diff --git a/src/cryptographic_primitives/hashing/ext.rs b/src/cryptographic_primitives/hashing/ext.rs index 0e5446ee..3cbe6423 100644 --- a/src/cryptographic_primitives/hashing/ext.rs +++ b/src/cryptographic_primitives/hashing/ext.rs @@ -5,6 +5,27 @@ use hmac::{Hmac, Mac}; use crate::arithmetic::*; use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +/// [Digest] extension allowing to hash elliptic points, scalars, and bigints +/// +/// Can be used with any hashing algorithm that implements `Digest` traits (e.g. [Sha256](sha2::Sha256), +/// [Sha512](sha2::Sha512), etc.) +/// +/// ## Example +/// +/// ```rust +/// use sha2::Sha256; +/// use curv::arithmetic::*; +/// use curv::cryptographic_primitives::hashing::{Digest, DigestExt}; +/// use curv::elliptic::curves::{Secp256k1, Point}; +/// +/// let hash = Sha256::new() +/// .chain_point(&Point::::generator().to_point()) +/// .chain_point(&Point::::base_point2().to_point()) +/// .chain_bigint(&BigInt::from(10)) +/// .result_bigint(); +/// +/// assert_eq!(hash, BigInt::from_hex("73764f937fbe25092466b417fa66ad9c62607865e1f8151df253aa3a2fd7599b").unwrap()); +/// ``` pub trait DigestExt { fn input_bigint(&mut self, n: &BigInt); fn input_point(&mut self, point: &Point); @@ -96,6 +117,7 @@ where } } +/// [Hmac] extension allowing to use bigints to instantiate hmac, update, and finalize it. pub trait HmacExt: Sized { fn new_bigint(key: &BigInt) -> Self; From a7b637c99702ab945d57877795100c007f48a159 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 12 Jul 2021 09:26:47 +0300 Subject: [PATCH 50/93] Fix typos --- examples/pedersen_commitment.rs | 2 +- src/elliptic/curves/traits.rs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/pedersen_commitment.rs b/examples/pedersen_commitment.rs index b3ef26ed..e3d8e535 100644 --- a/examples/pedersen_commitment.rs +++ b/examples/pedersen_commitment.rs @@ -1,7 +1,7 @@ use curv::arithmetic::*; use curv::elliptic::curves::*; -/// Pedesen Commitment: +/// Pedersen Commitment: /// compute c = mG + rH /// where m is the commited value, G is the group generator, /// H is a random point and r is a blinding value. diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 92403b70..3a600a12 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -48,34 +48,34 @@ pub trait ECScalar: Clone + PartialEq + fmt::Debug + 'static { /// Checks if the scalar equals to zero fn is_zero(&self) -> bool; - /// Constructs a scalar `n % curve_order` + /// Constructs a scalar `n % group_order` fn from_bigint(n: &BigInt) -> Self; /// Converts a scalar to BigInt fn to_bigint(&self) -> BigInt; - /// Calculates `(self + other) mod curve_order` + /// Calculates `(self + other) mod group_order` fn add(&self, other: &Self) -> Self; - /// Calculates `(self * other) mod curve_order` + /// Calculates `(self * other) mod group_order` fn mul(&self, other: &Self) -> Self; - /// Calculates `(self - other) mod curve_order` + /// Calculates `(self - other) mod group_order` fn sub(&self, other: &Self) -> Self; - /// Calculates `-self mod curve_order` + /// Calculates `-self mod group_order` fn neg(&self) -> Self; - /// Calculates `self^-1 (mod curve_order)`, returns None if self equals to zero + /// Calculates `self^-1 (mod group_order)`, returns None if self equals to zero fn invert(&self) -> Option; - /// Calculates `(self + other) mod curve_order`, and assigns result to `self` + /// Calculates `(self + other) mod group_order`, and assigns result to `self` fn add_assign(&mut self, other: &Self) { *self = self.add(other) } - /// Calculates `(self * other) mod curve_order`, and assigns result to `self` + /// Calculates `(self * other) mod group_order`, and assigns result to `self` fn mul_assign(&mut self, other: &Self) { *self = self.mul(other) } - /// Calculates `(self - other) mod curve_order`, and assigns result to `self` + /// Calculates `(self - other) mod group_order`, and assigns result to `self` fn sub_assign(&mut self, other: &Self) { *self = self.sub(other) } - /// Calculates `-self mod curve_order`, and assigns result to `self` + /// Calculates `-self mod group_order`, and assigns result to `self` fn neg_assign(&mut self) { *self = self.neg() } From aeb97611f77ead011ffd44b0dde09c41ed8ac4f8 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 12 Jul 2021 09:31:19 +0300 Subject: [PATCH 51/93] Update travis config --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d2e92617..9adf6e41 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,4 +22,4 @@ deploy: secure: "FE6A1XRyJtTK92rV3y5e0go+FDKn1HpJbYkHOacDqabTkUluXrCTw3ERFcQQ13QZdc9xkxoAs7roKp8ivl0Xg1IJCzI+yLb0ZR6YcYebKEqd06YFbBmejjvMsyyZHKPTQmroe+tBwcA1IqLLcAY8vmY5EGhJTsGUhovIomw1RvqM6gu9yUwII/sF0a5gqY761cJd4QoLlWTb1Er7DqZxoU9drhWAJQP7sLsspjLu6dOyWzb0A2mTmnek+iuVnt9mGPtjGk4FcNPGbEmNu3UPOVuXcyibFPIALEWrH0ouZB7E9k312g45LucSeKSimgQYQBNAzdsnkKyBwyTpGuaosGnMbI7mhoi3visV21RTbw61N05dmZTYb4VAMcx+93TslKMDv5nmIlUmKxULNRBSTPPtrg0/X7KuKaoHVstrxx0ohd8GFwGYQBB64mQaOxFBhoy//prpHjhFl+1cti4JHyaHFSV/PfaryvUfRg4q2Dlq1HP+ey5cPRPbwfpSO1RmXlIDWe21ncRnKSpgMHTPBzYNtil+gZyzHl5X4ZLvLCaHsZwZQPMFB+otlabFaS1caqkk1F1fHMrj8NMak/snb2IyUJqXgQivqzEn38G3k9/QHeQXhNVwyGDtdWV51P9XfXFpxrEuuWlXF56ABiWcF7bY7Y3DeCbnFNLkVkGZYvY=" on: tags: true - condition: '"$TRAVIS_TAG" =~ ^v[0-9.]+$ && "$BIGINT_BACKEND" = "rust-gmp-kzen"' + condition: '"$TRAVIS_TAG" =~ ^v[0-9].+$ && "$BIGINT_BACKEND" = "rust-gmp-kzen"' From 605320d5878ef77487223c1a4020cb54e73811eb Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 13 Jul 2021 14:58:31 +0300 Subject: [PATCH 52/93] Update P-256 curve implementation --- Cargo.toml | 4 +- src/elliptic/curves/mod.rs | 6 +- src/elliptic/curves/p256.rs | 946 +++++++----------------------- src/elliptic/curves/secp256_k1.rs | 96 +-- src/elliptic/curves/test.rs | 121 ++++ src/lib.rs | 10 +- 6 files changed, 363 insertions(+), 820 deletions(-) create mode 100644 src/elliptic/curves/test.rs diff --git a/Cargo.toml b/Cargo.toml index e659cb48..9651ee95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,8 +44,8 @@ version = "0.20" features = ["serde", "rand-std"] [dependencies.p256] -version = "0.5" -features = ["ecdsa"] +version = "0.9" +features = ["ecdsa", "ecdsa-core", "zeroize"] [dev-dependencies] bincode = "1.1" diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index cd439b95..e24f5577 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -1,13 +1,15 @@ // pub mod bls12_381; // pub mod curve_ristretto; // pub mod ed25519; -// pub mod p256; +pub mod p256; pub mod secp256_k1; +#[cfg(test)] +mod test; mod traits; mod wrappers; -pub use self::secp256_k1::Secp256k1; +pub use self::{p256::Secp256r1, secp256_k1::Secp256k1}; pub use self::{ traits::{Curve, ECPoint, ECScalar, PointCoords}, wrappers::{Generator, Point, PointRef, PointZ, Scalar, ScalarZ}, diff --git a/src/elliptic/curves/p256.rs b/src/elliptic/curves/p256.rs index 048ab7fc..5cb9094e 100644 --- a/src/elliptic/curves/p256.rs +++ b/src/elliptic/curves/p256.rs @@ -1,41 +1,41 @@ // NIST P-256 elliptic curve utility functions. -use super::traits::{ECPoint, ECScalar}; -use crate::arithmetic::traits::*; -use crate::BigInt; -use crate::ErrorKey; -use generic_array::typenum::U32; -use generic_array::GenericArray; -use p256::ecdsa::VerifyKey; +use p256::elliptic_curve::group::prime::PrimeCurveAffine; use p256::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint}; use p256::{AffinePoint, EncodedPoint, ProjectivePoint, Scalar}; + +use generic_array::typenum::U32; +use generic_array::GenericArray; use rand::{thread_rng, Rng}; -use serde::de; -use serde::de::Visitor; -use serde::ser::{Serialize, Serializer}; -use serde::{Deserialize, Deserializer}; -use std::ops::{Add, Mul, Sub}; -use std::sync::atomic; -use std::{fmt, ptr}; +use serde::{Deserialize, Serialize}; use zeroize::Zeroize; -pub type SK = Scalar; -pub type PK = VerifyKey; +use super::traits::{ECPoint, ECScalar}; +use crate::arithmetic::traits::*; +use crate::elliptic::curves::{Curve, DeserializationError, NotOnCurve, PointCoords}; +use crate::BigInt; -#[derive(Clone, Copy, Debug)] -pub struct Secp256r1Scalar { - purpose: &'static str, - fe: SK, +lazy_static::lazy_static! { + static ref GROUP_ORDER: BigInt = BigInt::from_bytes(&GROUP_ORDER_BYTES); + + static ref BASE_POINT2_ENCODED: EncodedPoint = { + let mut g = vec![4_u8]; + g.extend_from_slice(BASE_POINT2_X.as_ref()); + g.extend_from_slice(BASE_POINT2_Y.as_ref()); + EncodedPoint::from_bytes(&g).unwrap() + }; + + static ref BASE_POINT2: Secp256r1Point = Secp256r1Point { + purpose: "base_point2", + ge: PK::from_encoded_point(&BASE_POINT2_ENCODED).unwrap(), + }; + + static ref GENERATOR: Secp256r1Point = Secp256r1Point { + purpose: "generator", + ge: AffinePoint::generator() + }; } -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Secp256r1Point { - purpose: &'static str, - ge: PK, -} -pub type GE = Secp256r1Point; -pub type FE = Secp256r1Scalar; - /* X coordinate of a point of unknown discrete logarithm. Computed using a deterministic algorithm with the generator as input. See test_base_point2 */ @@ -47,48 +47,66 @@ const BASE_POINT2_Y: [u8; 32] = [ 0x30, 0xe2, 0xfe, 0xb3, 0x8d, 0x82, 0x4e, 0x0e, 0xa2, 0x95, 0x2f, 0x2a, 0x48, 0x5b, 0xbc, 0xdd, 0x4c, 0x72, 0x8a, 0x74, 0xf4, 0xfa, 0xc7, 0xdc, 0x0d, 0xc9, 0x90, 0x8d, 0x9a, 0x8d, 0xc1, 0xa4, ]; +const GROUP_ORDER_BYTES: [u8; 32] = [ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51, +]; -impl Zeroize for Secp256r1Scalar { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, Secp256r1Scalar::zero()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); - } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum Secp256r1 {} + +pub type SK = Scalar; +pub type PK = AffinePoint; + +#[derive(Clone, Debug)] +pub struct Secp256r1Scalar { + purpose: &'static str, + fe: zeroize::Zeroizing, +} + +#[derive(Clone, Copy, Debug)] +pub struct Secp256r1Point { + purpose: &'static str, + ge: PK, +} + +pub type GE = Secp256r1Point; +pub type FE = Secp256r1Scalar; + +impl Curve for Secp256r1 { + type Point = GE; + type Scalar = FE; + + const CURVE_NAME: &'static str = "secp256r1"; } impl ECScalar for Secp256r1Scalar { - type SecretKey = SK; + type Underlying = SK; - fn new_random() -> Secp256r1Scalar { + fn random() -> Secp256r1Scalar { let mut arr = [0u8; 32]; thread_rng().fill(&mut arr[..]); let gen_arr: GenericArray = *GenericArray::from_slice(&arr); Secp256r1Scalar { purpose: "random", - fe: Scalar::from_bytes_reduced(&gen_arr), + fe: Scalar::from_bytes_reduced(&gen_arr).into(), } } fn zero() -> Secp256r1Scalar { - let zero_arr = [0u8; 32]; - let zero = unsafe { std::mem::transmute::<[u8; 32], Scalar>(zero_arr) }; Secp256r1Scalar { purpose: "zero", - fe: zero, + fe: Scalar::zero().into(), } } - fn get_element(&self) -> SK { - self.fe + fn is_zero(&self) -> bool { + bool::from(self.fe.is_zero()) } - fn set_element(&mut self, element: SK) { - self.fe = element - } - - fn from(n: &BigInt) -> Secp256r1Scalar { - let curve_order = Secp256r1Scalar::q(); - let n_reduced = BigInt::mod_add(n, &BigInt::from(0), &curve_order); + fn from_bigint(n: &BigInt) -> Secp256r1Scalar { + let curve_order = Secp256r1Scalar::group_order(); + let n_reduced = n.modulus(&curve_order); let mut v = BigInt::to_bytes(&n_reduced); const SECRET_KEY_SIZE: usize = 32; @@ -100,248 +118,123 @@ impl ECScalar for Secp256r1Scalar { let arr: GenericArray = *GenericArray::from_slice(&v); Secp256r1Scalar { - purpose: "from_big_int", - fe: Scalar::from_bytes_reduced(&arr), + purpose: "from_bigint", + fe: Scalar::from_bytes_reduced(&arr).into(), } } - fn to_big_int(&self) -> BigInt { + fn to_bigint(&self) -> BigInt { BigInt::from_bytes(self.fe.to_bytes().as_slice()) } - fn q() -> BigInt { - const CURVE_ORDER: [u8; 32] = [ - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, - 0xfc, 0x63, 0x25, 0x51, - ]; - BigInt::from_bytes(CURVE_ORDER.as_ref()) - } - - fn add(&self, other: &SK) -> Secp256r1Scalar { + fn add(&self, other: &Self) -> Secp256r1Scalar { Secp256r1Scalar { purpose: "add", - fe: self.get_element() + other, + fe: (*self.fe + *other.fe).into(), } } - fn mul(&self, other: &SK) -> Secp256r1Scalar { + fn mul(&self, other: &Self) -> Secp256r1Scalar { Secp256r1Scalar { purpose: "mul", - fe: self.get_element() * other, + fe: (*self.fe * *other.fe).into(), } } - fn sub(&self, other: &SK) -> Secp256r1Scalar { + fn sub(&self, other: &Self) -> Secp256r1Scalar { Secp256r1Scalar { purpose: "sub", - fe: self.get_element() - other, + fe: (*self.fe - *other.fe).into(), } } - fn invert(&self) -> Secp256r1Scalar { + fn neg(&self) -> Self { Secp256r1Scalar { - purpose: "invert", - fe: self.fe.invert().unwrap(), + purpose: "sub", + fe: (-&*self.fe).into(), } } -} -impl Mul for Secp256r1Scalar { - type Output = Secp256r1Scalar; - fn mul(self, other: Secp256r1Scalar) -> Secp256r1Scalar { - (&self).mul(&other.get_element()) + fn invert(&self) -> Option { + Some(Secp256r1Scalar { + purpose: "invert", + fe: Option::::from(self.fe.invert())?.into(), + }) } -} -impl<'o> Mul<&'o Secp256r1Scalar> for Secp256r1Scalar { - type Output = Secp256r1Scalar; - fn mul(self, other: &'o Secp256r1Scalar) -> Secp256r1Scalar { - (&self).mul(&other.get_element()) + fn add_assign(&mut self, other: &Self) { + *self.fe += &*other.fe } -} - -impl Add for Secp256r1Scalar { - type Output = Secp256r1Scalar; - fn add(self, other: Secp256r1Scalar) -> Secp256r1Scalar { - (&self).add(&other.get_element()) + fn mul_assign(&mut self, other: &Self) { + *self.fe *= &*other.fe } -} - -impl<'o> Add<&'o Secp256r1Scalar> for Secp256r1Scalar { - type Output = Secp256r1Scalar; - fn add(self, other: &'o Secp256r1Scalar) -> Secp256r1Scalar { - (&self).add(&other.get_element()) + fn sub_assign(&mut self, other: &Self) { + *self.fe -= &*other.fe } -} -impl Sub for Secp256r1Scalar { - type Output = Secp256r1Scalar; - fn sub(self, other: Secp256r1Scalar) -> Secp256r1Scalar { - (&self).sub(&other.get_element()) + fn group_order() -> &'static BigInt { + &GROUP_ORDER } -} -impl<'o> Sub<&'o Secp256r1Scalar> for Secp256r1Scalar { - type Output = Secp256r1Scalar; - fn sub(self, other: &'o Secp256r1Scalar) -> Secp256r1Scalar { - (&self).sub(&other.get_element()) + fn underlying_ref(&self) -> &SK { + &self.fe } -} - -impl Serialize for Secp256r1Scalar { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&format!("{:0>64}", self.to_big_int().to_hex())) - } -} - -impl<'de> Deserialize<'de> for Secp256r1Scalar { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(Secp256r1ScalarVisitor) - } -} - -struct Secp256r1ScalarVisitor; -impl<'de> Visitor<'de> for Secp256r1ScalarVisitor { - type Value = Secp256r1Scalar; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Secp256r1Scalar") + fn underlying_mut(&mut self) -> &mut SK { + &mut self.fe } - fn visit_str(self, s: &str) -> Result { - let v = BigInt::from_hex(s).map_err(E::custom)?; - Ok(ECScalar::from(&v)) + fn from_underlying(fe: SK) -> Self { + Secp256r1Scalar { + purpose: "from_underlying", + fe: fe.into(), + } } } impl PartialEq for Secp256r1Scalar { fn eq(&self, other: &Secp256r1Scalar) -> bool { - self.get_element().to_bytes() == other.get_element().to_bytes() - } -} - -impl Zeroize for Secp256r1Point { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, GE::generator()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); + self.fe == other.fe } } impl ECPoint for Secp256r1Point { - type SecretKey = SK; - type PublicKey = PK; type Scalar = Secp256r1Scalar; + type Underlying = PK; - fn base_point2() -> Secp256r1Point { - let mut v = vec![4_u8]; - v.extend(BASE_POINT2_X.as_ref()); - v.extend(BASE_POINT2_Y.as_ref()); - Secp256r1Point::from_bytes(&v).unwrap() - } - - fn generator() -> Secp256r1Point { + fn zero() -> Secp256r1Point { Secp256r1Point { - purpose: "base_fe", - ge: VerifyKey::from_encoded_point(&AffinePoint::generator().to_encoded_point(true)) - .unwrap(), + purpose: "zero", + ge: AffinePoint::identity(), } } - fn get_element(&self) -> PK { - self.ge - } - - fn bytes_compressed_to_big_int(&self) -> BigInt { - BigInt::from_bytes(self.get_element().to_encoded_point(true).as_bytes()) - } - - fn x_coor(&self) -> Option { - Some(BigInt::from_bytes( - EncodedPoint::from(&self.ge).x().as_slice(), - )) + fn is_zero(&self) -> bool { + bool::from(self.ge.is_identity()) } - fn y_coor(&self) -> Option { - // need this back and forth conversion to get an uncompressed point - let tmp = AffinePoint::from_encoded_point(&EncodedPoint::from(&self.ge)).unwrap(); - Some(BigInt::from_bytes( - tmp.to_encoded_point(false).y().unwrap().as_slice(), - )) + fn generator() -> &'static Secp256r1Point { + &GENERATOR } - fn from_bytes(bytes: &[u8]) -> Result { - let result = PK::new(&bytes); - let test = result.map(|pk| Secp256r1Point { - purpose: "random", - ge: pk, - }); - test.map_err(|_err| ErrorKey::InvalidPublicKey) + fn base_point2() -> &'static Secp256r1Point { + &BASE_POINT2 } - fn pk_to_key_slice(&self) -> Vec { - let tmp = AffinePoint::from_encoded_point(&EncodedPoint::from(&self.ge)).unwrap(); - tmp.to_encoded_point(false).as_ref().to_vec() - } - - fn scalar_mul(&self, fe: &SK) -> Secp256r1Point { - let point = ProjectivePoint::from( - AffinePoint::from_encoded_point(&EncodedPoint::from(&self.ge)).unwrap(), - ); - let scalar = Scalar::from_bytes_reduced(&fe.to_bytes()); - Secp256r1Point { - purpose: "mul", - ge: VerifyKey::from_encoded_point(&(point * scalar).to_affine().to_encoded_point(true)) - .unwrap(), - } - } + fn from_coords(x: &BigInt, y: &BigInt) -> Result { + let mut vec_x = BigInt::to_bytes(x); + let mut vec_y = BigInt::to_bytes(y); - fn add_point(&self, other: &PK) -> Secp256r1Point { - let point1 = ProjectivePoint::from( - AffinePoint::from_encoded_point(&EncodedPoint::from(&self.ge)).unwrap(), - ); - let point2 = ProjectivePoint::from( - AffinePoint::from_encoded_point(&EncodedPoint::from(other)).unwrap(), - ); - Secp256r1Point { - purpose: "mul", - ge: VerifyKey::from_encoded_point( - &(point1 + point2).to_affine().to_encoded_point(true), - ) - .unwrap(), + const COORDINATE_SIZE: usize = 32; + if vec_x.len() > COORDINATE_SIZE { + // x coordinate is too big + return Err(NotOnCurve); } - } - - fn sub_point(&self, other: &PK) -> Secp256r1Point { - let point1 = ProjectivePoint::from( - AffinePoint::from_encoded_point(&EncodedPoint::from(&self.ge)).unwrap(), - ); - let point2 = ProjectivePoint::from( - AffinePoint::from_encoded_point(&EncodedPoint::from(other)).unwrap(), - ); - Secp256r1Point { - purpose: "sub", - ge: VerifyKey::from_encoded_point( - &(point1 - point2).to_affine().to_encoded_point(true), - ) - .unwrap(), + if vec_y.len() > COORDINATE_SIZE { + // y coordinate is too big + return Err(NotOnCurve); } - } - fn from_coor(x: &BigInt, y: &BigInt) -> Secp256r1Point { - let mut vec_x = BigInt::to_bytes(x); - let mut vec_y = BigInt::to_bytes(y); - const COORDINATE_SIZE: usize = 32; - assert!(vec_x.len() <= COORDINATE_SIZE, "x coordinate is too big."); - assert!(vec_x.len() <= COORDINATE_SIZE, "y coordinate is too big."); if vec_x.len() < COORDINATE_SIZE { // pad let mut x_buffer = vec![0; COORDINATE_SIZE - vec_x.len()]; @@ -357,528 +250,141 @@ impl ECPoint for Secp256r1Point { let x_arr: GenericArray = *GenericArray::from_slice(&vec_x); let y_arr: GenericArray = *GenericArray::from_slice(&vec_y); - Secp256r1Point { - purpose: "base_fe", - ge: VerifyKey::from_encoded_point(&EncodedPoint::from_affine_coordinates( - &x_arr, &y_arr, false, - )) - .unwrap(), - } - } -} -impl Secp256r1Point { - // derive point from BigInt - fn from_bigint(i: &BigInt) -> Result { - let vec = BigInt::to_bytes(i); - let point = match Secp256r1Point::from_bytes(&vec) { - Ok(v) => v, - Err(_) => return Err(()), - }; - Ok(point) - } -} + let ge = PK::from_encoded_point(&EncodedPoint::from_affine_coordinates( + &x_arr, &y_arr, false, + )) + .ok_or(NotOnCurve)?; -impl Mul for Secp256r1Point { - type Output = Secp256r1Point; - fn mul(self, other: Secp256r1Scalar) -> Self::Output { - self.scalar_mul(&other.get_element()) + Ok(Secp256r1Point { + purpose: "from_coords", + ge, + }) } -} -impl<'o> Mul<&'o Secp256r1Scalar> for Secp256r1Point { - type Output = Secp256r1Point; - fn mul(self, other: &'o Secp256r1Scalar) -> Self::Output { - self.scalar_mul(&other.get_element()) + fn x_coord(&self) -> Option { + let encoded = self.ge.to_encoded_point(false); + let x = BigInt::from_bytes(encoded.x()?.as_slice()); + Some(x) } -} -impl<'o> Mul<&'o Secp256r1Scalar> for &'o Secp256r1Point { - type Output = Secp256r1Point; - fn mul(self, other: &'o Secp256r1Scalar) -> Self::Output { - self.scalar_mul(&other.get_element()) + fn y_coord(&self) -> Option { + let encoded = self.ge.to_encoded_point(false); + let y = BigInt::from_bytes(encoded.y()?.as_slice()); + Some(y) } -} -impl Add for Secp256r1Point { - type Output = Secp256r1Point; - fn add(self, other: Secp256r1Point) -> Self::Output { - self.add_point(&other.get_element()) + fn coords(&self) -> Option { + let encoded = self.ge.to_encoded_point(false); + let x = BigInt::from_bytes(encoded.x()?.as_slice()); + let y = BigInt::from_bytes(encoded.y()?.as_slice()); + Some(PointCoords { x, y }) } -} -impl<'o> Add<&'o Secp256r1Point> for Secp256r1Point { - type Output = Secp256r1Point; - fn add(self, other: &'o Secp256r1Point) -> Self::Output { - self.add_point(&other.get_element()) + fn serialize(&self, compressed: bool) -> Option> { + if self.is_zero() { + None + } else { + Some(self.ge.to_encoded_point(compressed).to_bytes().into()) + } } -} -impl<'o> Add<&'o Secp256r1Point> for &'o Secp256r1Point { - type Output = Secp256r1Point; - fn add(self, other: &'o Secp256r1Point) -> Self::Output { - self.add_point(&other.get_element()) + fn deserialize(bytes: &[u8]) -> Result { + let encoded = EncodedPoint::from_bytes(bytes).map_err(|_| DeserializationError)?; + Ok(Secp256r1Point { + purpose: "deserialize", + ge: AffinePoint::from_encoded_point(&encoded).ok_or(DeserializationError)?, + }) } -} -impl Sub for Secp256r1Point { - type Output = Secp256r1Point; - fn sub(self, other: Secp256r1Point) -> Self::Output { - self.sub_point(&other.get_element()) + fn check_point_order_equals_group_order(&self) -> bool { + // This curve has cofactor=1 => any nonzero point has order GROUP_ORDER + !self.is_zero() } -} -impl<'o> Sub<&'o Secp256r1Point> for Secp256r1Point { - type Output = Secp256r1Point; - fn sub(self, other: &'o Secp256r1Point) -> Self::Output { - self.sub_point(&other.get_element()) + fn scalar_mul(&self, fe: &Self::Scalar) -> Secp256r1Point { + // TODO: p256 v0.5.0 cannot multiply AffinePoint * Scalar, but can multiply + // ProjectivePoint * Scalar. It was fixed in v0.9.0 + Secp256r1Point { + purpose: "scalar_mul", + ge: (ProjectivePoint::from(self.ge) * *fe.fe).to_affine(), + } } -} -impl<'o> Sub<&'o Secp256r1Point> for &'o Secp256r1Point { - type Output = Secp256r1Point; - fn sub(self, other: &'o Secp256r1Point) -> Self::Output { - self.sub_point(&other.get_element()) + fn add_point(&self, other: &Self) -> Self { + Secp256r1Point { + purpose: "add_point", + ge: (ProjectivePoint::from(self.ge) + other.ge).to_affine(), + } } -} -impl Serialize for Secp256r1Point { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&format!( - "{:0>66}", - self.bytes_compressed_to_big_int().to_hex() - )) + fn sub_point(&self, other: &Self) -> Self { + Secp256r1Point { + purpose: "sub_point", + ge: (ProjectivePoint::from(self.ge) - other.ge).to_affine(), + } } -} -impl<'de> Deserialize<'de> for Secp256r1Point { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(Secp256r1PointVisitor) + fn neg_point(&self) -> Self { + Secp256r1Point { + purpose: "neg_point", + ge: -self.ge, + } } -} - -struct Secp256r1PointVisitor; - -impl<'de> Visitor<'de> for Secp256r1PointVisitor { - type Value = Secp256r1Point; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Secp256r1Point") + /// Reference to underlying curve implementation + fn underlying_ref(&self) -> &Self::Underlying { + &self.ge } - - fn visit_str(self, s: &str) -> Result - where - E: de::Error, - { - let bn = BigInt::from_hex(s).map_err(E::custom)?; - match Secp256r1Point::from_bigint(&bn) { - Ok(v) => Ok(v), - Err(_) => Err(E::custom(format!( - "Error deriving Secp256r1Point from string: {}", - s - ))), - } + /// Mutual reference to underlying curve implementation + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.ge } -} - -#[cfg(test)] -mod tests { - use super::{BigInt, ErrorKey}; - use super::{Secp256r1Point, Secp256r1Scalar}; - use crate::arithmetic::traits::*; - use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; - use crate::cryptographic_primitives::hashing::traits::Hash; - use crate::elliptic::curves::traits::{ECPoint, ECScalar}; - - fn random_point() -> Secp256r1Point { - let random_scalar: Secp256r1Scalar = Secp256r1Scalar::new_random(); - let base_point = Secp256r1Point::generator(); - let pk = base_point.scalar_mul(&random_scalar.get_element()); + /// Construct a point from its underlying representation + fn from_underlying(ge: Self::Underlying) -> Self { Secp256r1Point { - purpose: "random_point", - ge: pk.get_element(), + purpose: "from_underlying", + ge, } } +} - #[test] - fn serialize_sk() { - let scalar: Secp256r1Scalar = ECScalar::from(&BigInt::from(123456)); - let s = serde_json::to_string(&scalar).expect("Failed in serialization"); - assert_eq!( - s, - "\"000000000000000000000000000000000000000000000000000000000001e240\"" - ); - } - - #[test] - fn serialize_rand_pk_verify_pad() { - let vx = BigInt::from_hex( - &"9e6b4c9775d5af0aff94a55035a2b039f7cfc19b9e67004f190ddfaada82b405".to_string(), - ) - .unwrap(); - - let vy = BigInt::from_hex( - &"d3fa4d180ea04d8da373bb61782bc6b509f7b6e374d6a47b253e4853ad1cd5fc".to_string(), - ) - .unwrap(); - Secp256r1Point::from_coor(&vx, &vy); // x and y of size 32 - - let x = BigInt::from_hex( - &"2d054d254d1d112b1e7a134780ae7975a2a57b35089b2afa45dc42ed9afe1b".to_string(), - ) - .unwrap(); - - let y = BigInt::from_hex( - &"16f436c897a9733a4d83eed96147b273348c98fb680d7361d915ec6b5ce761ca".to_string(), - ) - .unwrap(); - Secp256r1Point::from_coor(&x, &y); // x and y not of size 32 each - - let r = random_point(); - let r_expected = Secp256r1Point::from_coor(&r.x_coor().unwrap(), &r.y_coor().unwrap()); - assert_eq!(r.x_coor().unwrap(), r_expected.x_coor().unwrap()); - assert_eq!(r.y_coor().unwrap(), r_expected.y_coor().unwrap()); - } - - #[test] - fn deserialize_sk() { - let s = "\"1e240\""; - let dummy: Secp256r1Scalar = serde_json::from_str(s).expect("Failed in serialization"); - - let sk: Secp256r1Scalar = ECScalar::from(&BigInt::from(123456)); - - assert_eq!(dummy.to_big_int(), sk.to_big_int()); - } - - #[test] - fn serialize_pk() { - let pk = Secp256r1Point::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let expected = pk.bytes_compressed_to_big_int().to_hex(); - assert_eq!( - s, - serde_json::to_string(&("0".to_string() + &expected)).unwrap() - ); - let des_pk: Secp256r1Point = serde_json::from_str(&s).expect("Failed in serialization"); - assert_eq!(des_pk.ge, pk.ge); - } - - #[test] - fn bincode_pk() { - let pk = Secp256r1Point::generator(); - let bin = bincode::serialize(&pk).unwrap(); - let decoded: Secp256r1Point = bincode::deserialize(bin.as_slice()).unwrap(); - assert_eq!(decoded.get_element(), pk.get_element()); - } - - #[test] - fn test_serdes_pk() { - let pk = Secp256r1Point::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let des_pk: Secp256r1Point = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk.get_element(), pk.get_element()); - - let pk = Secp256r1Point::base_point2(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let des_pk: Secp256r1Point = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk.get_element(), pk.get_element()); - } - - #[test] - #[should_panic] - fn test_serdes_bad_pk() { - let pk = Secp256r1Point::generator(); - let mut s = serde_json::to_string(&pk).expect("Failed in serialization"); - // we make sure that the string encodes invalid point: - s = s.replace("2770", "2780"); - let des_pk: Secp256r1Point = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); - } - - #[test] - fn test_from_bytes() { - let vec = BigInt::to_bytes(&BigInt::from(1337)); - let result = Secp256r1Point::from_bytes(&vec); - assert_eq!(result.unwrap_err(), ErrorKey::InvalidPublicKey) - } - - #[test] - fn test_from_bytes_3() { - let test_vec = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 3, 4, 5, 6, - ]; - let result = Secp256r1Point::from_bytes(&test_vec); - assert!(result.is_ok() | result.is_err()) - } - - #[test] - fn test_from_bytes_4() { - let test_vec = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, - ]; - let result = Secp256r1Point::from_bytes(&test_vec); - assert!(result.is_ok() | result.is_err()) - } - - #[test] - fn test_from_bytes_5() { - let test_vec = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, - 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, - 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, - 4, 5, 6, - ]; - let result = Secp256r1Point::from_bytes(&test_vec); - assert!(result.is_ok() | result.is_err()) - } - - #[test] - fn test_add_sub() { - let q = Secp256r1Scalar::q(); - let start: Secp256r1Scalar = ECScalar::new_random(); - let b: Secp256r1Scalar = ECScalar::new_random(); - let tmp = BigInt::mod_add(&start.to_big_int(), &b.to_big_int(), &q); - let end = BigInt::mod_sub(&tmp, &b.to_big_int(), &q); - assert_eq!(start.to_big_int(), end); - } - - #[test] - fn test_minus_point() { - let a: Secp256r1Scalar = ECScalar::new_random(); - let b: Secp256r1Scalar = ECScalar::new_random(); - let b_bn = b.to_big_int(); - let q = Secp256r1Scalar::q(); - let minus_b = BigInt::mod_sub(&q, &b_bn, &q); - let a_minus_b = BigInt::mod_add(&a.to_big_int(), &minus_b, &q); - let a_minus_b_fe: Secp256r1Scalar = ECScalar::from(&a_minus_b); - let base: Secp256r1Point = ECPoint::generator(); - let point_ab1 = base * a_minus_b_fe; - let point_a = base * a; - let point_b = base * b; - let point_ab2 = point_a.sub_point(&point_b.get_element()); - assert_eq!(point_ab1.get_element(), point_ab2.get_element()); - } - - #[test] - fn test_simple_inversion2() { - let a: Secp256r1Scalar = ECScalar::from(&BigInt::from(2)); - let a_inv = a.invert(); - let a_inv_int = a_inv.to_big_int(); - assert_eq!( - a_inv_int, - BigInt::from_hex("7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a9") - .unwrap(), - ); - } - - #[test] - fn test_simple_inversion3() { - let a: Secp256r1Scalar = ECScalar::from(&BigInt::from(1234567890)); - let a_inv = a.invert().to_big_int(); - assert_eq!( - a_inv, - BigInt::from_hex("93a24a3b7e3b3a49a5acf862e8360bdd456e4c095dec9b97772bb758f725715a") - .unwrap(), - ); - } - - #[test] - fn test_invert() { - let a_bn = BigInt::sample(256); - let a: Secp256r1Scalar = ECScalar::from(&a_bn); - let a_inv = a.invert(); - let a_inv_bn_1 = BigInt::mod_inv(&a_bn, &Secp256r1Scalar::q()).unwrap(); - let a_inv_bn_2 = a_inv.to_big_int(); - assert_eq!(a_inv_bn_1, a_inv_bn_2); - } - - #[test] - fn test_scalar_mul_scalar() { - let a: Secp256r1Scalar = ECScalar::new_random(); - let b: Secp256r1Scalar = ECScalar::new_random(); - let c1 = a.mul(&b.get_element()); - let c2 = a * b; - assert_eq!(c1.get_element().to_bytes(), c2.get_element().to_bytes()); - } - - #[test] - fn test_scalar_mul1() { - let base_point = Secp256r1Point::generator(); - let int: Secp256r1Scalar = ECScalar::from(&BigInt::from(1)); - let test = base_point * int; - assert_eq!( - test.x_coor().unwrap().to_hex(), - "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296".to_lowercase() - ); - assert_eq!( - test.y_coor().unwrap().to_hex(), - "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5".to_lowercase() - ); - } - - #[test] - fn test_scalar_mul2() { - let base_point = Secp256r1Point::generator(); - let int: Secp256r1Scalar = ECScalar::from(&BigInt::from(2)); - let test = base_point * int; - assert_eq!( - test.x_coor().unwrap().to_hex(), - "7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978".to_lowercase() - ); - assert_eq!( - format!("{:0>64}", test.y_coor().unwrap().to_hex()), - "07775510DB8ED040293D9AC69F7430DBBA7DADE63CE982299E04B79D227873D1".to_lowercase() - ); - } - - #[test] - fn test_scalar_mul3() { - let base_point = Secp256r1Point::generator(); - let int: Secp256r1Scalar = ECScalar::from( - &BigInt::from_hex("7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978") - .unwrap(), - ); - let test = base_point * int; - assert_eq!( - test.x_coor().unwrap().to_hex(), - "4F6DD42033C0666A04DFC107F4CB4D5D22E33AE178006803D967CB25D95B7DB4".to_lowercase() - ); - assert_eq!( - format!("{:0>64}", test.y_coor().unwrap().to_hex()), - "085DB1B0952D8E081A3E13398A89911A038AAB054AE3E26718A5E582ED9FDD38".to_lowercase() - ); - } - - #[test] - fn test_pk_to_key_slice() { - for _ in 1..200 { - let r = Secp256r1Scalar::new_random(); - let rg = Secp256r1Point::generator() * r; - let key_slice = rg.pk_to_key_slice(); - assert!(key_slice.len() == 65); - assert!(key_slice[0] == 4); - let rg_prime: Secp256r1Point = ECPoint::from_bytes(&key_slice).unwrap(); - assert_eq!(rg_prime.get_element(), rg.get_element()); - } +impl Zeroize for Secp256r1Point { + fn zeroize(&mut self) { + self.ge.zeroize() } +} - #[test] - fn test_base_point2() { - /* Show that base_point2() is returning a point of unknown discrete logarithm. - It is done by using SHA256 repeatedly as a pseudo-random function, with the generator - as the initial input, until receiving a valid Secp256r1 point. */ - - let base_point2 = Secp256r1Point::base_point2(); - - let g = Secp256r1Point::generator(); - let mut hash = HSha256::create_hash(&[&g.bytes_compressed_to_big_int()]); - hash = HSha256::create_hash(&[&hash]); - - assert_eq!(hash, base_point2.x_coor().unwrap(),); - - // check that base_point2 is indeed on the curve (from_coor() will fail otherwise) - assert_eq!( - Secp256r1Point::from_coor( - &base_point2.x_coor().unwrap(), - &base_point2.y_coor().unwrap() - ) - .get_element(), - base_point2.get_element() - ); - } - - #[test] - fn scalar_bigint_conversion1() { - let int = BigInt::sample(256); - let scalar: Secp256r1Scalar = ECScalar::from(&int); - assert_eq!(scalar.to_big_int(), int); - } - - #[test] - fn point_bigint_conversion1() { - let g = Secp256r1Point::generator(); - let h = g.bytes_compressed_to_big_int(); - let i = Secp256r1Point::from_bigint(&h).unwrap(); - assert_eq!(i.get_element(), g.get_element()); - } - - #[test] - fn point_bigint_conversion2() { - let g = Secp256r1Point::generator(); - let r: Secp256r1Scalar = ECScalar::from(&BigInt::sample(256)); - let point = g * r; - let point_int = point.bytes_compressed_to_big_int(); - let point_test = Secp256r1Point::from_bigint(&point_int).unwrap(); - assert_eq!(point.get_element(), point_test.get_element()); - } - - #[test] - fn scalar_bigint_conversion2() { - let i = Secp256r1Scalar::new_random(); - let int = i.to_big_int(); - let j: Secp256r1Scalar = ECScalar::from(&int); - assert_eq!(i.to_big_int(), j.to_big_int()); - } - - #[test] - fn pk_to_hex() { - let secret = - BigInt::from_hex("79196b247effbe3192763a5c37b18f5d89e7d0a8c83d246917add0a842d5af8b") - .unwrap(); - let sk: Secp256r1Scalar = ECScalar::from(&secret); - let g = Secp256r1Point::generator(); - let h = g * sk; - assert_eq!( - format!("{:0>66}", h.bytes_compressed_to_big_int().to_hex()), - "025c31225f77535b1ceb7f603ef73627bf096a1efb65c1fdf0f7c1c9d64cf167ca" - ); - } - - #[test] - fn scalar_from_bigint() { - let r = Secp256r1Scalar::new_random(); - let int = r.to_big_int(); - let s: Secp256r1Scalar = ECScalar::from(&int); - assert_eq!(r.to_big_int(), s.to_big_int()); - } - - #[test] - fn add_sub_point() { - let g = Secp256r1Point::generator(); - let i: Secp256r1Scalar = ECScalar::from(&BigInt::from(3)); - assert_eq!((g + g + g).get_element(), (g * i).get_element()); - assert_eq!((g + g).get_element(), (g + g - g + g).get_element()); - } - - #[test] - fn add_scalar() { - let i: Secp256r1Scalar = ECScalar::from(&BigInt::from(1)); - let j: Secp256r1Scalar = ECScalar::from(&BigInt::from(2)); - assert_eq!((i + i).to_big_int(), j.to_big_int()); - assert_eq!((i + i + i + i).to_big_int(), (j + j).to_big_int()); - } - - #[test] - fn sub_scalar() { - let i: Secp256r1Scalar = ECScalar::from(&BigInt::from(1)); - assert_eq!((i + i - i).to_big_int(), i.to_big_int()); - let j: Secp256r1Scalar = ECScalar::from(&BigInt::from(2)); - assert_eq!((j + j - j).to_big_int(), j.to_big_int()); - let k = Secp256r1Scalar::new_random(); - assert_eq!((k + k - k).to_big_int(), k.to_big_int()); - } - - #[test] - fn mul_scalar() { - let i: Secp256r1Scalar = ECScalar::from(&BigInt::from(1)); - let j: Secp256r1Scalar = ECScalar::from(&BigInt::from(2)); - assert_eq!((j * i).to_big_int(), j.to_big_int()); +impl PartialEq for Secp256r1Point { + fn eq(&self, other: &Self) -> bool { + self.ge == other.ge } } + +#[cfg(test)] +mod tests { + // #[test] + // fn test_base_point2() { + // /* Show that base_point2() is returning a point of unknown discrete logarithm. + // It is done by using SHA256 repeatedly as a pseudo-random function, with the generator + // as the initial input, until receiving a valid Secp256r1 point. */ + // + // let base_point2 = Secp256r1Point::base_point2(); + // + // let g = Secp256r1Point::generator(); + // let mut hash = HSha256::create_hash(&[&g.bytes_compressed_to_big_int()]); + // hash = HSha256::create_hash(&[&hash]); + // + // assert_eq!(hash, base_point2.x_coor().unwrap(),); + // + // // check that base_point2 is indeed on the curve (from_coor() will fail otherwise) + // assert_eq!( + // Secp256r1Point::from_coor( + // &base_point2.x_coor().unwrap(), + // &base_point2.y_coor().unwrap() + // ) + // .get_element(), + // base_point2.get_element() + // ); + // } +} diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index bf2edb45..c1af9ca6 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -413,6 +413,11 @@ impl ECPoint for Secp256k1Point { }) } + fn check_point_order_equals_group_order(&self) -> bool { + // This curve has cofactor=1 => any nonzero point has order GROUP_ORDER + !self.is_zero() + } + fn scalar_mul(&self, scalar: &Self::Scalar) -> Secp256k1Point { let mut new_point = match &self.ge { Some(ge) => *ge, @@ -588,97 +593,6 @@ impl Zeroize for Secp256k1Point { #[cfg(test)] mod test { - use std::iter; - - use crate::elliptic::curves::traits::*; - use crate::BigInt; - - use super::{FE, GE}; - - #[test] - fn valid_zero_point() { - let zero = GE::zero(); - assert!(zero.is_zero()); - assert_eq!(zero, GE::zero()); - } - - #[test] - fn zero_point_arithmetic() { - let zero_point = GE::zero(); - let point = GE::generator().scalar_mul(&FE::random()); - - assert_eq!(zero_point.add_point(&point), point, "O + P = P"); - assert_eq!(point.add_point(&zero_point), point, "P + O = P"); - - let point_neg = point.neg_point(); - assert!(point.add_point(&point_neg).is_zero(), "P + (-P) = O"); - assert!(point.sub_point(&point).is_zero(), "P - P = O"); - - let zero_scalar = FE::zero(); - assert!(point.scalar_mul(&zero_scalar).is_zero(), "P * 0 = O"); - let scalar = FE::random(); - assert!(zero_point.scalar_mul(&scalar).is_zero(), "O * s = O") - } - - #[test] - fn scalar_modulo_curve_order() { - let n = FE::group_order(); - let s = FE::from_bigint(n); - assert!(s.is_zero()); - - let s = FE::from_bigint(&(n + 1)); - assert_eq!(s, FE::from_bigint(&BigInt::from(1))); - } - - #[test] - fn zero_scalar_arithmetic() { - let s = FE::random(); - let z = FE::zero(); - assert!(s.mul(&z).is_zero()); - assert!(z.mul(&s).is_zero()); - assert_eq!(s.add(&z), s); - assert_eq!(z.add(&s), s); - } - - #[test] - fn point_addition_multiplication() { - let point = GE::generator().scalar_mul(&FE::random()); - assert!(!point.is_zero(), "G * s != O"); - - let addition = iter::successors(Some(point), |p| Some(p.add_point(&point))) - .take(10) - .collect::>(); - let multiplication = (1..=10) - .map(|i| FE::from_bigint(&BigInt::from(i))) - .map(|s| point.scalar_mul(&s)) - .collect::>(); - assert_eq!(addition, multiplication); - } - - #[test] - fn serialize_deserialize() { - let point = GE::generator().scalar_mul(&FE::random()); - let bytes = point - .serialize(true) - .expect("point has coordinates => must be serializable"); - let deserialized = GE::deserialize(&bytes).unwrap(); - assert_eq!(point, deserialized); - - let bytes = point - .serialize(false) - .expect("point has coordinates => must be serializable"); - let deserialized = GE::deserialize(&bytes).unwrap(); - assert_eq!(point, deserialized); - } - - #[test] - fn generator_mul_curve_order_is_zero() { - let g = GE::generator(); - let n = FE::group_order() - 1; - let s = FE::from_bigint(&n); - assert!(g.scalar_mul(&s).add_point(&g).is_zero()); - } - // #[test] // fn test_base_point2() { // /* Show that base_point2() is returning a point of unknown discrete logarithm. diff --git a/src/elliptic/curves/test.rs b/src/elliptic/curves/test.rs new file mode 100644 index 00000000..ce6011ce --- /dev/null +++ b/src/elliptic/curves/test.rs @@ -0,0 +1,121 @@ +use std::iter; + +use crate::arithmetic::*; +use crate::test_for_all_curves; + +use super::traits::*; + +test_for_all_curves!(valid_zero_point); +fn valid_zero_point() { + let zero = E::Scalar::zero(); + assert!(zero.is_zero()); + assert_eq!(zero, E::Scalar::zero()); +} + +test_for_all_curves!(zero_point_arithmetic); +fn zero_point_arithmetic() { + let zero_point = E::Point::zero(); + let point = E::Point::generator().scalar_mul(&E::Scalar::random()); + + assert_eq!(zero_point.add_point(&point), point, "O + P = P"); + assert_eq!(point.add_point(&zero_point), point, "P + O = P"); + + let point_neg = point.neg_point(); + assert!(point.add_point(&point_neg).is_zero(), "P + (-P) = O"); + assert!(point.sub_point(&point).is_zero(), "P - P = O"); + + let zero_scalar = E::Scalar::zero(); + assert!(point.scalar_mul(&zero_scalar).is_zero(), "P * 0 = O"); + let scalar = E::Scalar::random(); + assert!(zero_point.scalar_mul(&scalar).is_zero(), "O * s = O") +} + +test_for_all_curves!(scalar_modulo_curve_order); +fn scalar_modulo_curve_order() { + let n = E::Scalar::group_order(); + let s = E::Scalar::from_bigint(n); + assert!(s.is_zero()); + + let s = E::Scalar::from_bigint(&(n + 1)); + assert_eq!(s, E::Scalar::from_bigint(&BigInt::from(1))); +} + +test_for_all_curves!(zero_scalar_arithmetic); +fn zero_scalar_arithmetic() { + let s = E::Scalar::random(); + let z = E::Scalar::zero(); + assert!(s.mul(&z).is_zero()); + assert!(z.mul(&s).is_zero()); + assert_eq!(s.add(&z), s); + assert_eq!(z.add(&s), s); +} + +test_for_all_curves!(point_addition_multiplication); +fn point_addition_multiplication() { + let point = E::Point::generator().scalar_mul(&E::Scalar::random()); + assert!(!point.is_zero(), "G * s != O"); + + let addition = iter::successors(Some(point.clone()), |p| Some(p.add_point(&point))) + .take(10) + .collect::>(); + let multiplication = (1..=10) + .map(|i| E::Scalar::from_bigint(&BigInt::from(i))) + .map(|s| point.scalar_mul(&s)) + .collect::>(); + assert_eq!(addition, multiplication); +} + +test_for_all_curves!(serialize_deserialize); +fn serialize_deserialize() { + let point = ::generator().scalar_mul(&E::Scalar::random()); + let bytes = point + .serialize(true) + .expect("point has coordinates => must be serializable"); + let deserialized = ::deserialize(&bytes).unwrap(); + assert_eq!(point, deserialized); + assert!( + bytes.starts_with(&[2]) || bytes.starts_with(&[3]), + "compressed form must start either with 2 or 3" + ); + + let bytes = point + .serialize(false) + .expect("point has coordinates => must be serializable"); + let deserialized = E::Point::deserialize(&bytes).unwrap(); + assert_eq!(point, deserialized); + assert!(bytes.starts_with(&[4]), "compressed form must start with 4"); +} + +test_for_all_curves!(generator_mul_curve_order_is_zero); +fn generator_mul_curve_order_is_zero() { + let g: &E::Point = ECPoint::generator(); + let n = E::Scalar::group_order() - 1; + let s = E::Scalar::from_bigint(&n); + assert!(g.scalar_mul(&s).add_point(&g).is_zero()); +} + +test_for_all_curves!(scalar_behaves_the_same_as_bigint); +fn scalar_behaves_the_same_as_bigint() { + let q = E::Scalar::group_order(); + + let mut n = BigInt::zero(); + let mut s: E::Scalar = ECScalar::zero(); + + for _ in 0..100 { + let k = BigInt::sample_below(&(q * 2)); + + let n_was = n.clone(); + n += &k; + s.add_assign(&E::Scalar::from_bigint(&k)); + + assert_eq!( + s.to_bigint(), + n.modulus(q), + "{} + {} = {} (got {})", + n_was, + k, + n, + s.to_bigint() + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index c41fbea3..fad0fedc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,11 @@ macro_rules! test_for_all_curves { fn [<$fn _secp256k1>]() { $fn::() } + #[test] + $($attrs)* + fn [<$fn _p256>]() { + $fn::() + } // #[test] // $($attrs)* // fn [<$fn _ristretto>]() { @@ -54,11 +59,6 @@ macro_rules! test_for_all_curves { // fn [<$fn _bls12_381>]() { // $fn::() // } - // #[test] - // $($attrs)* - // fn [<$fn _p256>]() { - // $fn::() - // } } }; } From 9c7bd7d4c942b23e914b2e6b2b10395ece539fb4 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 13 Jul 2021 14:55:47 +0300 Subject: [PATCH 53/93] Add tests --- src/elliptic/curves/test.rs | 130 ++++++++++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 20 deletions(-) diff --git a/src/elliptic/curves/test.rs b/src/elliptic/curves/test.rs index ce6011ce..c54c551e 100644 --- a/src/elliptic/curves/test.rs +++ b/src/elliptic/curves/test.rs @@ -1,5 +1,9 @@ +#![allow(non_snake_case)] + use std::iter; +use rand::{rngs::StdRng, FromEntropy, Rng}; + use crate::arithmetic::*; use crate::test_for_all_curves; @@ -73,17 +77,12 @@ fn serialize_deserialize() { .expect("point has coordinates => must be serializable"); let deserialized = ::deserialize(&bytes).unwrap(); assert_eq!(point, deserialized); - assert!( - bytes.starts_with(&[2]) || bytes.starts_with(&[3]), - "compressed form must start either with 2 or 3" - ); let bytes = point .serialize(false) .expect("point has coordinates => must be serializable"); let deserialized = E::Point::deserialize(&bytes).unwrap(); assert_eq!(point, deserialized); - assert!(bytes.starts_with(&[4]), "compressed form must start with 4"); } test_for_all_curves!(generator_mul_curve_order_is_zero); @@ -96,26 +95,117 @@ fn generator_mul_curve_order_is_zero() { test_for_all_curves!(scalar_behaves_the_same_as_bigint); fn scalar_behaves_the_same_as_bigint() { + let mut rng = StdRng::from_entropy(); let q = E::Scalar::group_order(); let mut n = BigInt::zero(); let mut s: E::Scalar = ECScalar::zero(); for _ in 0..100 { - let k = BigInt::sample_below(&(q * 2)); - - let n_was = n.clone(); - n += &k; - s.add_assign(&E::Scalar::from_bigint(&k)); - - assert_eq!( - s.to_bigint(), - n.modulus(q), - "{} + {} = {} (got {})", - n_was, - k, - n, - s.to_bigint() - ); + let operation = rng.gen_range(0, 4); + if operation == 0 { + let n_inv = BigInt::mod_inv(&n, q); + let s_inv = s.invert().map(|s| s.to_bigint()); + + assert_eq!( + s_inv, + n_inv, + "{}^-1 = {} (got {})", + n, + n_inv + .as_ref() + .map(|i| i.to_string()) + .unwrap_or("None".to_string()), + s_inv + .as_ref() + .map(|i| i.to_string()) + .unwrap_or("None".to_string()), + ); + } else { + let n_was = n.clone(); + let k = BigInt::sample_below(&(q * 2)); + let op; + + match operation { + 1 => { + op = "+"; + n = BigInt::mod_add(&n, &k, q); + s.add_assign(&E::Scalar::from_bigint(&k)); + } + 2 => { + op = "*"; + n = BigInt::mod_mul(&n, &k, q); + s.mul_assign(&E::Scalar::from_bigint(&k)); + } + 3 => { + op = "-"; + n = BigInt::mod_sub(&n, &k, q); + s.sub_assign(&E::Scalar::from_bigint(&k)); + } + _ => unreachable!(), + } + + assert_eq!( + s.to_bigint(), + n.modulus(q), + "{} {} {} = {} (got {})", + n_was, + op, + k, + n, + s.to_bigint() + ); + } } } + +test_for_all_curves!(from_coords_produces_the_same_point); +fn from_coords_produces_the_same_point() { + let s: E::Scalar = ECScalar::random(); + println!("s={}", s.to_bigint()); + + let p: E::Point = ::generator().scalar_mul(&s); + if let Some(coords) = p.coords() { + let p2: E::Point = ECPoint::from_coords(&coords.x, &coords.y).unwrap(); + assert_eq!(p, p2); + } +} + +test_for_all_curves!(test_point_addition); +fn test_point_addition() { + let a: E::Scalar = ECScalar::random(); + let b: E::Scalar = ECScalar::random(); + + let aG: E::Point = ECPoint::generator_mul(&a); + let bG: E::Point = ECPoint::generator_mul(&b); + let a_plus_b = a.add(&b); + let a_plus_b_G: E::Point = ECPoint::generator_mul(&a_plus_b); + + assert_eq!(aG.add_point(&bG), a_plus_b_G); +} + +test_for_all_curves!(test_point_subtraction); +fn test_point_subtraction() { + let a: E::Scalar = ECScalar::random(); + let b: E::Scalar = ECScalar::random(); + + let aG: E::Point = ECPoint::generator_mul(&a); + let bG: E::Point = ECPoint::generator_mul(&b); + let a_minus_b = a.sub(&b); + let a_minus_b_G: E::Point = ECPoint::generator_mul(&a_minus_b); + + assert_eq!(aG.sub_point(&bG), a_minus_b_G); +} + +test_for_all_curves!(test_multiplication_point_at_scalar); +fn test_multiplication_point_at_scalar() { + let a: E::Scalar = ECScalar::random(); + let b: E::Scalar = ECScalar::random(); + + let aG: E::Point = ECPoint::generator_mul(&a); + let abG: E::Point = aG.scalar_mul(&b); + let a_mul_b = a.mul(&b); + let a_mul_b_G: E::Point = ECPoint::generator_mul(&a_mul_b); + + assert_eq!(abG, a_mul_b_G); +} From 72552a7d1f4d60aa1bdbd895a9e1c343870157df Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 13 Jul 2021 14:58:35 +0300 Subject: [PATCH 54/93] Update Ed25519 curve --- Cargo.toml | 2 +- src/elliptic/curves/ed25519.rs | 829 ++++++++++----------------------- src/elliptic/curves/mod.rs | 4 +- src/lib.rs | 10 +- 4 files changed, 262 insertions(+), 583 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9651ee95..0eef9b16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "curv" -version = "0.7.1" +version = "0.8.0-rc1" edition = "2018" authors = ["Omer Shlomovits"] license = "MIT" diff --git a/src/elliptic/curves/ed25519.rs b/src/elliptic/curves/ed25519.rs index 2c65a7c7..f59415df 100644 --- a/src/elliptic/curves/ed25519.rs +++ b/src/elliptic/curves/ed25519.rs @@ -8,38 +8,96 @@ // paper: https://ed25519.cr.yp.to/ed25519-20110926.pdf // based on https://docs.rs/cryptoxide/0.1.0/cryptoxide/curve25519/index.html // https://cr.yp.to/ecdh/curve25519-20060209.pdf + +use std::fmt; use std::fmt::Debug; +use std::ops; +use std::ptr; use std::str; -pub const TWO_TIMES_SECRET_KEY_SIZE: usize = 64; -use super::traits::{ECPoint, ECScalar}; -use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; -use crate::cryptographic_primitives::hashing::traits::Hash; -use serde::de::{self, Error, MapAccess, SeqAccess, Visitor}; -use serde::ser::SerializeStruct; -use serde::ser::{Serialize, Serializer}; -use serde::{Deserialize, Deserializer}; -use std::fmt; -use std::ops::{Add, Mul}; -pub type SK = Fe; -pub type PK = GeP3; +use std::sync::atomic; + +use cryptoxide::curve25519::*; +use zeroize::{Zeroize, Zeroizing}; + use crate::arithmetic::traits::*; +use crate::cryptographic_primitives::hashing::Digest; use crate::BigInt; -use crate::ErrorKey::{self, InvalidPublicKey}; -#[cfg(feature = "merkle")] -use crypto::digest::Digest; -#[cfg(feature = "merkle")] -use crypto::sha3::Sha3; -use cryptoxide::curve25519::*; -#[cfg(feature = "merkle")] -use merkle::Hashable; -use std::ptr; -use std::sync::atomic; -use zeroize::Zeroize; -#[derive(Clone, Copy)] +use super::traits::{ECPoint, ECScalar}; +use crate::elliptic::curves::{Curve, DeserializationError, NotOnCurve, PointCoords}; + +lazy_static::lazy_static! { + static ref GROUP_ORDER: BigInt = Ed25519Scalar { + purpose: "intermediate group_order", + fe: SK(Fe::from_bytes(&[ + 237, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, + ])).into() + }.to_bigint(); + + static ref ZERO: Ed25519Point = Ed25519Point { + purpose: "zero", + ge: ge_scalarmult_base(&[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + ]), + }; + + static ref GENERATOR: Ed25519Point = Ed25519Point { + purpose: "generator", + ge: ge_scalarmult_base(&[ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + ]), + }; + + static ref BASE_POINT2: Ed25519Point = { + let bytes = GENERATOR.serialize(true).unwrap(); + let hashed = sha2::Sha256::digest(&bytes); + let hashed_twice = sha2::Sha256::digest(&hashed); + let p = Ed25519Point::deserialize(&hashed_twice).unwrap(); + let eight = Ed25519Scalar::from_bigint(&BigInt::from(8)); + Ed25519Point { + purpose: "base_point2", + ge: p.scalar_mul(&eight).ge, + } + }; +} + +const FE_ZERO: Fe = Fe([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); +const TWO_TIMES_SECRET_KEY_SIZE: usize = 64; + +/// Alias to [Edwards point](GeP3) +pub type PK = GeP3; +/// Wraps [Fe] and implements Zeroize to it +#[derive(Clone)] +pub struct SK(pub Fe); + +impl Zeroize for SK { + fn zeroize(&mut self) { + self.0 .0.zeroize() + } +} +impl ops::Deref for SK { + type Target = Fe; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl ops::DerefMut for SK { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Ed25519 {} + +#[derive(Clone)] pub struct Ed25519Scalar { purpose: &'static str, - fe: SK, + fe: Zeroizing, } #[derive(Clone, Copy)] pub struct Ed25519Point { @@ -49,40 +107,39 @@ pub struct Ed25519Point { pub type GE = Ed25519Point; pub type FE = Ed25519Scalar; -impl Zeroize for Ed25519Scalar { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, FE::zero()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); - } +impl Curve for Ed25519 { + type Point = GE; + type Scalar = FE; + + const CURVE_NAME: &'static str = "ed25519"; } + impl ECScalar for Ed25519Scalar { - type SecretKey = SK; + type Underlying = SK; // we chose to multiply by 8 (co-factor) all group elements to work in the prime order sub group. // each random fe is having its 3 first bits zeroed - fn new_random() -> Ed25519Scalar { - let rnd_bn = BigInt::sample_below(&FE::q()); - let rnd_bn_mul_8 = BigInt::mod_mul(&rnd_bn, &BigInt::from(8), &FE::q()); - ECScalar::from(&rnd_bn_mul_8) + fn random() -> Ed25519Scalar { + let rnd_bn = BigInt::sample_below(Self::group_order()); + let rnd_bn_mul_8 = BigInt::mod_mul(&rnd_bn, &BigInt::from(8), Self::group_order()); + Ed25519Scalar { + purpose: "random", + fe: Self::from_bigint(&rnd_bn_mul_8).fe, + } } fn zero() -> Ed25519Scalar { - let q_fe: FE = ECScalar::from(&FE::q()); Ed25519Scalar { purpose: "zero", - fe: q_fe.get_element(), + fe: SK(FE_ZERO).into(), } } - fn get_element(&self) -> SK { - self.fe - } - fn set_element(&mut self, element: SK) { - self.fe = element + fn is_zero(&self) -> bool { + self.fe.0 == FE_ZERO } - fn from(n: &BigInt) -> Ed25519Scalar { + fn from_bigint(n: &BigInt) -> Ed25519Scalar { let mut v = BigInt::to_bytes(&n); if v.len() > TWO_TIMES_SECRET_KEY_SIZE { v = v[0..TWO_TIMES_SECRET_KEY_SIZE].to_vec(); @@ -94,74 +151,91 @@ impl ECScalar for Ed25519Scalar { v.reverse(); sc_reduce(&mut v[..]); Ed25519Scalar { - purpose: "from_big_int", - fe: SK::from_bytes(&v[..]), + purpose: "from_bigint", + fe: SK(Fe::from_bytes(&v[..])).into(), } } - fn to_big_int(&self) -> BigInt { - let t1 = &self.fe.to_bytes()[0..self.fe.to_bytes().len()]; - let mut t2 = t1.to_vec(); - t2.reverse(); - BigInt::from_bytes(&t2[0..self.fe.to_bytes().len()]) + fn to_bigint(&self) -> BigInt { + let mut t = self.fe.to_bytes().to_vec(); + t.reverse(); + BigInt::from_bytes(&t) } - fn q() -> BigInt { - let q_bytes_array: [u8; 32]; - q_bytes_array = [ - 237, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, - ]; - let l_fe = SK::from_bytes(&q_bytes_array); - let l_fe = Ed25519Scalar { - purpose: "q", - fe: l_fe, - }; - l_fe.to_big_int() + fn add(&self, other: &Self) -> Ed25519Scalar { + Ed25519Scalar { + purpose: "add", + fe: Self::from_bigint(&BigInt::mod_add( + &self.to_bigint(), + &other.to_bigint(), + Self::group_order(), + )) + .fe, + } } - fn add(&self, other: &SK) -> Ed25519Scalar { - let other_point = Ed25519Scalar { - purpose: "other add", - fe: *other, - }; - let lhs_bn = self.to_big_int(); - let rhs_bn = other_point.to_big_int(); - let sum = BigInt::mod_add(&lhs_bn, &rhs_bn, &FE::q()); - let sum_fe: FE = ECScalar::from(&sum); + fn mul(&self, other: &Self) -> Ed25519Scalar { + Ed25519Scalar { + purpose: "mul", + fe: Self::from_bigint(&BigInt::mod_mul( + &self.to_bigint(), + &other.to_bigint(), + Self::group_order(), + )) + .fe, + } + } - sum_fe + fn sub(&self, other: &Self) -> Ed25519Scalar { + Ed25519Scalar { + purpose: "sub", + fe: Self::from_bigint(&BigInt::mod_sub( + &self.to_bigint(), + &other.to_bigint(), + Self::group_order(), + )) + .fe, + } } - fn mul(&self, other: &SK) -> Ed25519Scalar { - let other_point = Ed25519Scalar { - purpose: "other mul", - fe: *other, - }; - let lhs_bn = self.to_big_int(); - let rhs_bn = other_point.to_big_int(); - let mul = BigInt::mod_mul(&lhs_bn, &rhs_bn, &FE::q()); - let mul_fe: FE = ECScalar::from(&mul); - mul_fe + fn neg(&self) -> Self { + Ed25519Scalar { + purpose: "neg", + fe: Self::from_bigint(&BigInt::mod_add( + &Self::zero().to_bigint(), + &self.to_bigint(), + Self::group_order(), + )) + .fe, + } } - fn sub(&self, other: &SK) -> Ed25519Scalar { - let other_point = Ed25519Scalar { - purpose: "other sub", - fe: *other, - }; - let lhs_bn = self.to_big_int(); - let rhs_bn = other_point.to_big_int(); - let sub = BigInt::mod_sub(&lhs_bn, &rhs_bn, &FE::q()); - let sub_fe: FE = ECScalar::from(&sub); - sub_fe + fn invert(&self) -> Option { + if self.is_zero() { + None + } else { + Some(Ed25519Scalar { + purpose: "invert", + fe: Self::from_bigint(&BigInt::mod_inv(&self.to_bigint(), Self::group_order())?).fe, + }) + } } - fn invert(&self) -> Ed25519Scalar { - let self_bn = self.to_big_int(); - let inv = BigInt::mod_inv(&self_bn, &FE::q()).unwrap(); - let inv_fe: FE = ECScalar::from(&inv); - inv_fe + fn group_order() -> &'static BigInt { + &GROUP_ORDER + } + + fn underlying_ref(&self) -> &Self::Underlying { + &self.fe + } + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.fe + } + fn from_underlying(fe: Self::Underlying) -> Ed25519Scalar { + Ed25519Scalar { + purpose: "from_underlying", + fe: fe.into(), + } } } @@ -178,68 +252,7 @@ impl Debug for Ed25519Scalar { impl PartialEq for Ed25519Scalar { fn eq(&self, other: &Ed25519Scalar) -> bool { - self.get_element().to_bytes() == other.get_element().to_bytes() - } -} - -impl Mul for Ed25519Scalar { - type Output = Ed25519Scalar; - fn mul(self, other: Ed25519Scalar) -> Ed25519Scalar { - (&self).mul(&other.get_element()) - } -} - -impl<'o> Mul<&'o Ed25519Scalar> for Ed25519Scalar { - type Output = Ed25519Scalar; - fn mul(self, other: &'o Ed25519Scalar) -> Ed25519Scalar { - (&self).mul(&other.get_element()) - } -} - -impl Add for Ed25519Scalar { - type Output = Ed25519Scalar; - fn add(self, other: Ed25519Scalar) -> Ed25519Scalar { - (&self).add(&other.get_element()) - } -} - -impl<'o> Add<&'o Ed25519Scalar> for Ed25519Scalar { - type Output = Ed25519Scalar; - fn add(self, other: &'o Ed25519Scalar) -> Ed25519Scalar { - (&self).add(&other.get_element()) - } -} - -impl Serialize for Ed25519Scalar { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_big_int().to_hex()) - } -} - -impl<'de> Deserialize<'de> for Ed25519Scalar { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(Ed25519ScalarVisitor) - } -} - -struct Ed25519ScalarVisitor; - -impl<'de> Visitor<'de> for Ed25519ScalarVisitor { - type Value = Ed25519Scalar; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("ed25519") - } - - fn visit_str(self, s: &str) -> Result { - let v = BigInt::from_hex(s).map_err(E::custom)?; - Ok(ECScalar::from(&v)) + self.fe.0 == other.fe.0 } } @@ -256,76 +269,80 @@ impl Debug for Ed25519Point { impl PartialEq for Ed25519Point { fn eq(&self, other: &Ed25519Point) -> bool { - self.get_element().to_bytes() == other.get_element().to_bytes() + self.ge.to_bytes() == other.ge.to_bytes() } } impl Zeroize for Ed25519Point { fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, GE::generator()) }; + unsafe { ptr::write_volatile(&mut self.ge, GENERATOR.ge) }; atomic::fence(atomic::Ordering::SeqCst); atomic::compiler_fence(atomic::Ordering::SeqCst); } } impl ECPoint for Ed25519Point { - type SecretKey = SK; - type PublicKey = PK; + type Underlying = PK; type Scalar = Ed25519Scalar; - fn base_point2() -> Ed25519Point { - let g: GE = ECPoint::generator(); - let hash = HSha256::create_hash(&[&g.bytes_compressed_to_big_int()]); - let hash = HSha256::create_hash(&[&hash]); - let bytes = BigInt::to_bytes(&hash); - let h: GE = ECPoint::from_bytes(&bytes[..]).unwrap(); - Ed25519Point { - purpose: "random", - ge: h.get_element(), - } + fn zero() -> Ed25519Point { + *ZERO } - fn generator() -> Ed25519Point { - let vec_1: [u8; 32]; - vec_1 = [ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - ]; - Ed25519Point { - purpose: "base_fe", - ge: ge_scalarmult_base(&vec_1[..]), - } + fn is_zero(&self) -> bool { + self == &*ZERO } - fn get_element(&self) -> PK { - self.ge + fn generator() -> &'static Ed25519Point { + &GENERATOR } - fn x_coor(&self) -> Option { - let y = self.y_coor().unwrap(); - Some(xrecover(y)) + fn base_point2() -> &'static Ed25519Point { + &BASE_POINT2 } - fn y_coor(&self) -> Option { - let y_fe = SK::from_bytes(self.ge.to_bytes()[0..self.ge.to_bytes().len()].as_ref()); - let y = Ed25519Scalar { - purpose: "base_fe", - fe: y_fe, + fn from_coords(x: &BigInt, y: &BigInt) -> Result { + let expected_x = xrecover(y); + if &expected_x != x { + return Err(NotOnCurve); + } + let y_bytes = y.to_bytes(); + let mut padded = match y_bytes.len() { + n if n > 32 => return Err(NotOnCurve), + 32 => y_bytes, + _ => { + let mut padding = vec![0; 32 - y_bytes.len()]; + padding.extend_from_slice(&y_bytes); + padding + } }; - Some(y.to_big_int()) + padded.reverse(); + Self::deserialize(&padded).map_err(|_e| NotOnCurve) + } + + fn x_coord(&self) -> Option { + let y = self.y_coord().unwrap(); + Some(xrecover(&y)) + } + + fn y_coord(&self) -> Option { + let mut bytes = self.ge.to_bytes().to_vec(); + bytes.reverse(); + Some(BigInt::from_bytes(&bytes)) + } + + fn coords(&self) -> Option { + let y = self + .y_coord() + .expect("coordinates are always defined for edwards curves"); + Some(PointCoords { x: xrecover(&y), y }) } - fn bytes_compressed_to_big_int(&self) -> BigInt { - BigInt::from_bytes(self.ge.to_bytes()[0..self.ge.to_bytes().len()].as_ref()) + fn serialize(&self, _compress: bool) -> Option> { + Some(self.ge.to_bytes().to_vec()) } - // from_bytes will return Ok only if the bytes encode a valid point. - // since valid point are not necessarily in the sub group of prime order this needs to be checked - // as well such that Ok will be returned only for valid point of the sub group prime order. - // currently we change the encoded point by multiply by 8 to make sure it is in the sub group of prime order. - // This is because for our use cases so far it doesn't matter and multiply by 8 is faster than testing for a point - // in the sub group prime order - fn from_bytes(bytes: &[u8]) -> Result { + fn deserialize(bytes: &[u8]) -> Result { let bytes_vec = bytes.to_vec(); let mut bytes_array_32 = [0u8; 32]; let byte_len = bytes_vec.len(); @@ -342,18 +359,14 @@ impl ECPoint for Ed25519Point { let ge_bytes = ge_from_bytes.unwrap().to_bytes(); let ge_from_bytes = PK::from_bytes_negate_vartime(&ge_bytes[..]); match ge_from_bytes { - Some(y) => { - let eight: FE = ECScalar::from(&BigInt::from(8)); - let new_point = Ed25519Point { - purpose: "random", - ge: y, - }; - Ok(new_point * eight) - } - None => Err(InvalidPublicKey), + Some(y) => Ok(Ed25519Point { + purpose: "deserialize", + ge: y, + }), + None => Err(DeserializationError), } } - None => Err(InvalidPublicKey), + None => Err(DeserializationError), } } _ => { @@ -365,36 +378,26 @@ impl ECPoint for Ed25519Point { let ge_bytes = ge_from_bytes.unwrap().to_bytes(); let ge_from_bytes = PK::from_bytes_negate_vartime(&ge_bytes[..]); match ge_from_bytes { - Some(y) => { - let eight: FE = ECScalar::from(&BigInt::from(8)); - let new_point = Ed25519Point { - purpose: "random", - ge: y, - }; - Ok(new_point * eight) - } - None => Err(InvalidPublicKey), + Some(y) => Ok(Ed25519Point { + purpose: "random", + ge: y, + }), + None => Err(DeserializationError), } } - None => Err(InvalidPublicKey), + None => Err(DeserializationError), } } } } - fn pk_to_key_slice(&self) -> Vec { - let result = self.ge.to_bytes(); - result.to_vec() - } - - fn scalar_mul(&self, fe: &SK) -> Ed25519Point { + fn scalar_mul(&self, fe: &Self::Scalar) -> Ed25519Point { let vec_0: [u8; 32]; vec_0 = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - let p2_point = - GeP2::double_scalarmult_vartime(&fe.to_bytes()[..], self.get_element(), &vec_0[..]); + let p2_point = GeP2::double_scalarmult_vartime(&fe.fe.to_bytes()[..], self.ge, &vec_0[..]); let mut p2_bytes = p2_point.to_bytes(); p2_bytes[31] ^= 1 << 7; @@ -402,23 +405,23 @@ impl ECPoint for Ed25519Point { let ge = GeP3::from_bytes_negate_vartime(&p2_bytes[..]).unwrap(); Ed25519Point { - purpose: "scalar_point_mul", + purpose: "scalar_mul", ge, } } - fn add_point(&self, other: &PK) -> Ed25519Point { - let pkpk = self.ge + other.to_cached(); + fn add_point(&self, other: &Self) -> Ed25519Point { + let pkpk = self.ge + other.ge.to_cached(); let mut pk_p2_bytes = pkpk.to_p2().to_bytes(); pk_p2_bytes[31] ^= 1 << 7; Ed25519Point { - purpose: "combine", + purpose: "add", ge: PK::from_bytes_negate_vartime(&pk_p2_bytes).unwrap(), } } - fn sub_point(&self, other: &PK) -> Ed25519Point { - let pkpk = self.ge - other.to_cached(); + fn sub_point(&self, other: &Self) -> Ed25519Point { + let pkpk = self.ge - other.ge.to_cached(); let mut pk_p2_bytes = pkpk.to_p2().to_bytes(); pk_p2_bytes[31] ^= 1 << 7; @@ -428,130 +431,27 @@ impl ECPoint for Ed25519Point { } } - fn from_coor(_x: &BigInt, _y: &BigInt) -> Ed25519Point { - unimplemented!(); - } -} - -impl Mul for Ed25519Point { - type Output = Ed25519Point; - fn mul(self, other: Ed25519Scalar) -> Ed25519Point { - self.scalar_mul(&other.get_element()) - } -} - -impl<'o> Mul<&'o Ed25519Scalar> for Ed25519Point { - type Output = Ed25519Point; - fn mul(self, other: &'o Ed25519Scalar) -> Ed25519Point { - self.scalar_mul(&other.get_element()) + fn neg_point(&self) -> Self { + ZERO.sub_point(self) } -} -impl<'o> Mul<&'o Ed25519Scalar> for &'o Ed25519Point { - type Output = Ed25519Point; - fn mul(self, other: &'o Ed25519Scalar) -> Ed25519Point { - self.scalar_mul(&other.get_element()) + fn underlying_ref(&self) -> &Self::Underlying { + &self.ge } -} - -impl Add for Ed25519Point { - type Output = Ed25519Point; - fn add(self, other: Ed25519Point) -> Ed25519Point { - self.add_point(&other.get_element()) + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.ge } -} - -impl<'o> Add<&'o Ed25519Point> for Ed25519Point { - type Output = Ed25519Point; - fn add(self, other: &'o Ed25519Point) -> Ed25519Point { - self.add_point(&other.get_element()) - } -} - -impl<'o> Add<&'o Ed25519Point> for &'o Ed25519Point { - type Output = Ed25519Point; - fn add(self, other: &'o Ed25519Point) -> Ed25519Point { - self.add_point(&other.get_element()) - } -} - -#[cfg(feature = "merkle")] -impl Hashable for Ed25519Point { - fn update_context(&self, context: &mut Sha3) { - let bytes: Vec = self.pk_to_key_slice(); - context.input(&bytes[..]); - } -} - -impl Serialize for Ed25519Point { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let bytes = self.pk_to_key_slice(); - let bytes_as_bn = BigInt::from_bytes(&bytes[..]); - let padded_bytes_hex = format!("{:0>64}", bytes_as_bn.to_hex()); - let mut state = serializer.serialize_struct("ed25519CurvePoint", 1)?; - state.serialize_field("bytes_str", &padded_bytes_hex)?; - state.end() - } -} - -impl<'de> Deserialize<'de> for Ed25519Point { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let fields = &["bytes_str"]; - deserializer.deserialize_struct("Ed25519Point", fields, Ed25519PointVisitor) - } -} - -struct Ed25519PointVisitor; - -impl<'de> Visitor<'de> for Ed25519PointVisitor { - type Value = Ed25519Point; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Ed25519Point") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let bytes_str = seq - .next_element()? - .ok_or_else(|| V::Error::invalid_length(0, &"a single element"))?; - let bytes_bn = BigInt::from_hex(bytes_str).map_err(V::Error::custom)?; - let bytes = BigInt::to_bytes(&bytes_bn); - Ed25519Point::from_bytes(&bytes[..]) - .map_err(|_| V::Error::custom("failed to parse ed25519 point")) - } - - fn visit_map>(self, mut map: E) -> Result { - let mut bytes_str: String = "".to_string(); - - while let Some(key) = map.next_key::<&'de str>()? { - let v = map.next_value::<&'de str>()?; - match key { - "bytes_str" => { - bytes_str = String::from(v); - } - _ => return Err(E::Error::unknown_field(key, &["bytes_str"])), - } + fn from_underlying(ge: Self::Underlying) -> Ed25519Point { + Ed25519Point { + purpose: "from_underlying", + ge, } - - let bytes_bn = BigInt::from_hex(&bytes_str).map_err(E::Error::custom)?; - let bytes = BigInt::to_bytes(&bytes_bn); - - Ed25519Point::from_bytes(&bytes[..]).map_err(|_| E::Error::custom("invalid ed25519 point")) } } #[allow(clippy::many_single_char_names)] //helper function, based on https://ed25519.cr.yp.to/python/ed25519.py -pub fn xrecover(y_coor: BigInt) -> BigInt { +fn xrecover(y_coor: &BigInt) -> BigInt { // let d = "37095705934669439343138083508754565189542113879843219016388785533085940283555"; // let d_bn = BigInt::from(d.as_bytes()); let q = BigInt::from(2u32).pow(255u32) - BigInt::from(19u32); @@ -560,7 +460,7 @@ pub fn xrecover(y_coor: BigInt) -> BigInt { let d_d = expmod(&BigInt::from(121_666), &(q.clone() - BigInt::from(2)), &q); let d_bn = d_n * d_d; - let y_sqr = y_coor.clone() * y_coor; + let y_sqr = y_coor * y_coor; let u = y_sqr.clone() - one.clone(); let v = y_sqr * d_bn + one; let v_inv = expmod(&v, &(q.clone() - BigInt::from(2)), &q); @@ -582,7 +482,7 @@ pub fn xrecover(y_coor: BigInt) -> BigInt { } //helper function, based on https://ed25519.cr.yp.to/python/ed25519.py -pub fn expmod(b: &BigInt, e: &BigInt, m: &BigInt) -> BigInt { +fn expmod(b: &BigInt, e: &BigInt, m: &BigInt) -> BigInt { let one = BigInt::one(); if e.clone() == BigInt::zero() { return one; @@ -595,224 +495,3 @@ pub fn expmod(b: &BigInt, e: &BigInt, m: &BigInt) -> BigInt { } t } - -#[cfg(test)] -mod tests { - use super::{Ed25519Point, Ed25519Scalar}; - use crate::arithmetic::traits::*; - use crate::elliptic::curves::traits::ECPoint; - use crate::elliptic::curves::traits::ECScalar; - use crate::BigInt; - - type GE = Ed25519Point; - type FE = Ed25519Scalar; - - #[test] - #[allow(clippy::op_ref)] // Enables type inference. - fn test_serdes_pk() { - let mut pk = GE::generator(); - let mut s = serde_json::to_string(&pk).expect("Failed in serialization"); - let mut des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - let eight = ECScalar::from(&BigInt::from(8)); - assert_eq!(des_pk, pk * &eight); - - pk = GE::base_point2(); - s = serde_json::to_string(&pk).expect("Failed in serialization"); - des_pk = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk * &eight); - - // deserialize serialization of bytes_str < 64 hex - s = "{\"bytes_str\":\"2c42d43e1a277e8f3d7d5aacde519c80b913341e425b624d867f790d1578e0\"}" - .to_string(); - des_pk = serde_json::from_str(&s).expect("Failed in deserialization"); - let eight_inverse: FE = eight.invert(); - let des_pk_mul = des_pk * &eight_inverse; - assert_eq!( - des_pk_mul.bytes_compressed_to_big_int().to_hex(), - "2c42d43e1a277e8f3d7d5aacde519c80b913341e425b624d867f790d1578e0" - ); - - // serialize with padding - let ser_pk = serde_json::to_string(&des_pk_mul).expect("Failed in serialization"); - assert_eq!( - &ser_pk, - "{\"bytes_str\":\"002c42d43e1a277e8f3d7d5aacde519c80b913341e425b624d867f790d1578e0\"}" - ); - - // deserialize a padded serialization - let des_pk2: GE = serde_json::from_str(&ser_pk).expect("Failed in deserialization"); - assert_eq!(des_pk_mul, des_pk2 * &eight_inverse); - } - - #[test] - #[allow(clippy::op_ref)] // Enables type inference. - fn bincode_pk() { - let pk = GE::generator(); - let encoded = bincode::serialize(&pk).unwrap(); - let decoded: Ed25519Point = bincode::deserialize(encoded.as_slice()).unwrap(); - let eight = ECScalar::from(&BigInt::from(8)); - assert_eq!(pk * &eight, decoded); - } - - #[test] - #[should_panic] - #[allow(clippy::op_ref)] // Enables type inference. - fn test_serdes_bad_pk() { - let pk = GE::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - // we make sure that the string encodes invalid point: - let s: String = s.replace("5866", "5867"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - let eight = ECScalar::from(&BigInt::from(8)); - assert_eq!(des_pk, pk * &eight); - } - - #[test] - fn test_from_mpz() { - let rand_scalar: FE = ECScalar::new_random(); - let rand_bn = rand_scalar.to_big_int(); - let rand_scalar2: FE = ECScalar::from(&rand_bn); - assert_eq!(rand_scalar, rand_scalar2); - } - - #[test] - fn test_minus_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let a_minus_b_fe: FE = a.sub(&b.get_element()); - let base: GE = ECPoint::generator(); - let point_ab1 = base * a_minus_b_fe; - let point_a = base * a; - let point_b = base * b; - let point_ab2 = point_a.sub_point(&point_b.get_element()); - assert_eq!(point_ab1, point_ab2); - } - - #[test] - fn test_add_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let a_plus_b_fe = a + b; - let base: GE = ECPoint::generator(); - let point_ab1 = base * a_plus_b_fe; - let point_a = base * a; - let point_b = base * b; - let point_ab2 = point_a.add_point(&point_b.get_element()); - - assert_eq!(point_ab1, point_ab2); - } - - #[test] - fn test_add_scalar() { - let a: FE = ECScalar::new_random(); - let zero: FE = FE::zero(); - let a_plus_zero: FE = a + zero; - - assert_eq!(a_plus_zero, a); - } - - #[test] - fn test_mul_scalar() { - let a = [ - 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 10, 10, 10, - ]; - let a_bn = BigInt::from_bytes(&a[..]); - let a_fe: FE = ECScalar::from(&a_bn); - - let five = BigInt::from(5); - let five_fe: FE = ECScalar::from(&five); - let five_a_bn = BigInt::mod_mul(&a_bn, &five, &FE::q()); - let five_a_fe = five_fe * a_fe; - let five_a_fe_2: FE = ECScalar::from(&five_a_bn); - - assert_eq!(five_a_fe, five_a_fe_2); - } - - #[test] - fn test_mul_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let a_mul_b_fe = a * b; - let base: GE = ECPoint::generator(); - let point_ab1 = base * a_mul_b_fe; - let point_a = base * a; - let point_ab2 = point_a.scalar_mul(&b.get_element()); - - assert_eq!(point_ab1, point_ab2); - } - - #[test] - fn test_invert() { - let a: FE = ECScalar::new_random(); - - let a_bn = a.to_big_int(); - - let a_inv = a.invert(); - let a_inv_bn_1 = BigInt::mod_inv(&a_bn, &FE::q()).unwrap(); - let a_inv_bn_2 = a_inv.to_big_int(); - - assert_eq!(a_inv_bn_1, a_inv_bn_2); - } - #[test] - fn test_from_bytes_2() { - let test_vec = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, - 6, - ]; - let result = Ed25519Point::from_bytes(&test_vec); - assert!(result.is_ok()) - } - #[test] - fn test_from_bytes_3() { - let test_vec = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 3, 4, 5, 6, - ]; - let result = Ed25519Point::from_bytes(&test_vec); - assert!(result.is_ok()) - } - - #[test] - fn test_scalar_mul_multiply_by_1() { - let g: GE = ECPoint::generator(); - - let fe: FE = ECScalar::from(&BigInt::from(1)); - let b_tag = g * fe; - assert_eq!(b_tag, g); - } - - #[test] - fn test_gep3_to_bytes_from_bytes() { - let g: GE = ECPoint::generator(); - let test_vec: [u8; 32]; - test_vec = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, - ]; - let tv_bn = BigInt::from_bytes(&test_vec[..]); - let test_fe: FE = ECScalar::from(&tv_bn); - let test_ge = g * test_fe; - let test_ge_bytes = test_ge.get_element().to_bytes(); - let test_ge2: GE = ECPoint::from_bytes(&test_ge_bytes[..]).unwrap(); - let eight: FE = ECScalar::from(&BigInt::from(8)); - - assert_eq!(test_ge2, test_ge * eight); - } - - #[test] - fn test_scalar_to_bn_and_back() { - let s_a: FE = ECScalar::new_random(); - let s_bn = s_a.to_big_int(); - let s_b: FE = ECScalar::from(&s_bn); - assert_eq!(s_a, s_b); - } - #[test] - fn test_xy_coor() { - let g: GE = GE::generator(); - assert_eq!( - g.x_coor().unwrap().to_hex(), - "216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a" - ); - } -} diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index e24f5577..9b2a8bc8 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -1,6 +1,6 @@ // pub mod bls12_381; // pub mod curve_ristretto; -// pub mod ed25519; +pub mod ed25519; pub mod p256; pub mod secp256_k1; @@ -9,7 +9,7 @@ mod test; mod traits; mod wrappers; -pub use self::{p256::Secp256r1, secp256_k1::Secp256k1}; +pub use self::{ed25519::Ed25519, p256::Secp256r1, secp256_k1::Secp256k1}; pub use self::{ traits::{Curve, ECPoint, ECScalar, PointCoords}, wrappers::{Generator, Point, PointRef, PointZ, Scalar, ScalarZ}, diff --git a/src/lib.rs b/src/lib.rs index fad0fedc..d9fdcc1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,11 @@ macro_rules! test_for_all_curves { fn [<$fn _p256>]() { $fn::() } + #[test] + $($attrs)* + fn [<$fn _ed25519>]() { + $fn::() + } // #[test] // $($attrs)* // fn [<$fn _ristretto>]() { @@ -51,11 +56,6 @@ macro_rules! test_for_all_curves { // } // #[test] // $($attrs)* - // fn [<$fn _ed25519>]() { - // $fn::() - // } - // #[test] - // $($attrs)* // fn [<$fn _bls12_381>]() { // $fn::() // } From e651b0f7d035a278e021ff365813c0120aff4a8e Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 14 Jul 2021 17:09:31 +0300 Subject: [PATCH 55/93] Update Ristretto curve --- Cargo.toml | 5 +- src/arithmetic/samplable.rs | 2 +- src/elliptic/curves/curve_ristretto.rs | 653 ++++++++----------------- src/elliptic/curves/mod.rs | 6 +- src/elliptic/curves/secp256_k1.rs | 3 +- src/elliptic/curves/test.rs | 23 +- src/elliptic/curves/traits.rs | 4 +- src/lib.rs | 10 +- 8 files changed, 248 insertions(+), 458 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0eef9b16..6cf14142 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ crate-type = ["lib"] [dependencies] blake2b_simd = "0.5.7" cryptoxide = "0.1.2" -curve25519-dalek = "1.2.3" +curve25519-dalek = "3" derivative = "2.2" digest = "0.8.1" ff-zeroize = "0.6.3" @@ -27,7 +27,8 @@ lazy_static = "1.4" num-traits = "0.2" num-integer = "0.1" pairing-plus = "0.19" -rand = "0.6" +rand = "0.7" +rand_legacy = { package = "rand", version = "0.6" } ring-algorithm = "0.2.3" rust-crypto = "^0.2" serde = { version = "1.0", features = ["derive"] } diff --git a/src/arithmetic/samplable.rs b/src/arithmetic/samplable.rs index 1b069b3a..8be7a47c 100644 --- a/src/arithmetic/samplable.rs +++ b/src/arithmetic/samplable.rs @@ -35,7 +35,7 @@ impl Samplable for BigInt { if bit_size == 0 { return BigInt::zero(); } - let mut rng = OsRng::new().unwrap(); + let mut rng = OsRng; let bytes = (bit_size - 1) / 8 + 1; let mut buf: Vec = vec![0; bytes]; rng.fill_bytes(&mut buf); diff --git a/src/elliptic/curves/curve_ristretto.rs b/src/elliptic/curves/curve_ristretto.rs index a123c3bf..801eaf4b 100644 --- a/src/elliptic/curves/curve_ristretto.rs +++ b/src/elliptic/curves/curve_ristretto.rs @@ -6,89 +6,93 @@ License MIT: */ -use super::traits::{ECPoint, ECScalar}; -use crate::arithmetic::traits::*; -use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; -use crate::cryptographic_primitives::hashing::traits::Hash; -use crate::BigInt; -use crate::ErrorKey::{self, InvalidPublicKey}; -use curve25519_dalek::constants::BASEPOINT_ORDER; -use curve25519_dalek::constants::RISTRETTO_BASEPOINT_COMPRESSED; +use std::ptr; +use std::sync::atomic; + +use curve25519_dalek::constants::{BASEPOINT_ORDER, RISTRETTO_BASEPOINT_POINT}; use curve25519_dalek::ristretto::CompressedRistretto; -use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::traits::{Identity, IsIdentity}; use rand::thread_rng; -use serde::de::{self, Error, MapAccess, SeqAccess, Visitor}; -use serde::ser::SerializeStruct; -use serde::ser::{Serialize, Serializer}; -use serde::{Deserialize, Deserializer}; -use std::fmt; -use std::ops::{Add, Mul}; -use std::str; +use sha2::{Digest, Sha256}; +use zeroize::{Zeroize, Zeroizing}; + +use crate::arithmetic::*; +use crate::elliptic::curves::traits::*; + +use super::traits::{ECPoint, ECScalar}; + +lazy_static::lazy_static! { + static ref GROUP_ORDER: BigInt = RistrettoScalar { + purpose: "intermediate GROUP_ORDER", + fe: BASEPOINT_ORDER.into(), + }.to_bigint(); + + static ref GENERATOR: RistrettoPoint = RistrettoPoint { + purpose: "generator", + ge: RISTRETTO_BASEPOINT_POINT, + }; + + static ref BASE_POINT2: RistrettoPoint = { + let g = RistrettoPoint::generator(); + let hash = Sha256::new() + .chain(g.serialize(true).unwrap()) + .result(); + RistrettoPoint { + purpose: "base_point2", + ge: RistrettoPoint::deserialize(&hash).unwrap().ge, + } + }; + + static ref NOT_REAL_COORD: BigInt = BigInt::from_bytes(b"not a real coordinate"); +} + pub const SECRET_KEY_SIZE: usize = 32; pub const COOR_BYTE_SIZE: usize = 32; pub const NUM_OF_COORDINATES: usize = 4; -use std::ptr; -use std::sync::atomic; -use zeroize::Zeroize; - -#[cfg(feature = "merkle")] -use crypto::digest::Digest; -#[cfg(feature = "merkle")] -use crypto::sha3::Sha3; -#[cfg(feature = "merkle")] -use merkle::Hashable; - -pub type SK = Scalar; -pub type PK = CompressedRistretto; +pub type SK = curve25519_dalek::scalar::Scalar; +pub type PK = curve25519_dalek::ristretto::RistrettoPoint; -#[derive(Clone, Debug, Copy)] +#[derive(Debug, PartialEq, Clone)] +pub enum Ristretto {} +#[derive(Clone, Debug)] pub struct RistrettoScalar { purpose: &'static str, - fe: SK, + fe: Zeroizing, } #[derive(Clone, Debug, Copy)] -pub struct RistrettoCurvPoint { +pub struct RistrettoPoint { purpose: &'static str, ge: PK, } -pub type GE = RistrettoCurvPoint; +pub type GE = RistrettoPoint; pub type FE = RistrettoScalar; -impl Zeroize for RistrettoScalar { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, FE::zero()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); - } +impl Curve for Ristretto { + type Point = GE; + type Scalar = FE; + + const CURVE_NAME: &'static str = "ristretto"; } impl ECScalar for RistrettoScalar { - type SecretKey = SK; + type Underlying = SK; - fn new_random() -> RistrettoScalar { + fn random() -> RistrettoScalar { RistrettoScalar { purpose: "random", - fe: SK::random(&mut thread_rng()), + fe: SK::random(&mut thread_rng()).into(), } } fn zero() -> RistrettoScalar { - let q_fe: FE = ECScalar::from(&FE::q()); RistrettoScalar { purpose: "zero", - fe: q_fe.get_element(), + fe: SK::zero().into(), } } - fn get_element(&self) -> SK { - self.fe - } - fn set_element(&mut self, element: SK) { - self.fe = element - } - - fn from(n: &BigInt) -> RistrettoScalar { + fn from_bigint(n: &BigInt) -> RistrettoScalar { let mut v = BigInt::to_bytes(n); //TODO: add consistency check for sizes max 32/ max 64 let mut bytes_array_32: [u8; 32]; @@ -97,20 +101,20 @@ impl ECScalar for RistrettoScalar { let mut template = vec![0; SECRET_KEY_SIZE - v.len()]; template.extend_from_slice(&v); v = template; - } - if v.len() > SECRET_KEY_SIZE && v.len() < 2 * SECRET_KEY_SIZE { + } else if v.len() > SECRET_KEY_SIZE && v.len() < 2 * SECRET_KEY_SIZE { let mut template = vec![0; 2 * SECRET_KEY_SIZE - v.len()]; template.extend_from_slice(&v); v = template; } + if v.len() == SECRET_KEY_SIZE { bytes_array_32 = [0; SECRET_KEY_SIZE]; let bytes = &v[..]; bytes_array_32.copy_from_slice(&bytes); bytes_array_32.reverse(); RistrettoScalar { - purpose: "from_big_int", - fe: SK::from_bytes_mod_order(bytes_array_32), + purpose: "from_bigint", + fe: SK::from_bytes_mod_order(bytes_array_32).into(), } } else { bytes_array_64 = [0; 2 * SECRET_KEY_SIZE]; @@ -118,481 +122,244 @@ impl ECScalar for RistrettoScalar { bytes_array_64.copy_from_slice(&bytes); bytes_array_64.reverse(); RistrettoScalar { - purpose: "from_big_int", - fe: SK::from_bytes_mod_order_wide(&bytes_array_64), + purpose: "from_bigint", + fe: SK::from_bytes_mod_order_wide(&bytes_array_64).into(), } } } - fn to_big_int(&self) -> BigInt { - let t1 = &self.fe.to_bytes()[0..self.fe.to_bytes().len()]; - let mut t2 = t1.to_vec(); - t2.reverse(); - BigInt::from_bytes(&t2[0..self.fe.to_bytes().len()]) + fn to_bigint(&self) -> BigInt { + let mut t = self.fe.to_bytes(); + t.reverse(); + BigInt::from_bytes(&t) } - fn q() -> BigInt { - let l = BASEPOINT_ORDER; - let l_fe = RistrettoScalar { - purpose: "q", - fe: l, - }; - l_fe.to_big_int() - } - - fn add(&self, other: &SK) -> RistrettoScalar { + fn add(&self, other: &Self) -> RistrettoScalar { RistrettoScalar { purpose: "add", - fe: self.get_element() + other, + fe: (*self.fe + *other.fe).into(), } } - fn mul(&self, other: &SK) -> RistrettoScalar { + fn mul(&self, other: &Self) -> RistrettoScalar { RistrettoScalar { purpose: "mul", - fe: self.get_element() * other, + fe: (*self.fe * *other.fe).into(), } } - fn sub(&self, other: &SK) -> RistrettoScalar { + fn sub(&self, other: &Self) -> RistrettoScalar { RistrettoScalar { purpose: "sub", - fe: self.get_element() - other, + fe: (*self.fe - *other.fe).into(), } } - fn invert(&self) -> RistrettoScalar { - let inv: SK = self.get_element().invert(); + fn neg(&self) -> Self { RistrettoScalar { - purpose: "invert", - fe: inv, + purpose: "neg", + fe: (-&*self.fe).into(), } } -} -impl Mul for RistrettoScalar { - type Output = RistrettoScalar; - fn mul(self, other: RistrettoScalar) -> RistrettoScalar { - (&self).mul(&other.get_element()) + fn invert(&self) -> Option { + if self.is_zero() { + None + } else { + Some(RistrettoScalar { + purpose: "invert", + fe: self.fe.invert().into(), + }) + } } -} -impl<'o> Mul<&'o RistrettoScalar> for RistrettoScalar { - type Output = RistrettoScalar; - fn mul(self, other: &'o RistrettoScalar) -> RistrettoScalar { - (&self).mul(&other.get_element()) + fn add_assign(&mut self, other: &Self) { + *self.fe += &*other.fe; } -} - -impl Add for RistrettoScalar { - type Output = RistrettoScalar; - fn add(self, other: RistrettoScalar) -> RistrettoScalar { - (&self).add(&other.get_element()) + fn mul_assign(&mut self, other: &Self) { + *self.fe *= &*other.fe; } -} - -impl<'o> Add<&'o RistrettoScalar> for RistrettoScalar { - type Output = RistrettoScalar; - fn add(self, other: &'o RistrettoScalar) -> RistrettoScalar { - (&self).add(&other.get_element()) + fn sub_assign(&mut self, other: &Self) { + *self.fe -= &*other.fe; } -} -impl Serialize for RistrettoScalar { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_big_int().to_hex()) + fn group_order() -> &'static BigInt { + &GROUP_ORDER } -} -impl<'de> Deserialize<'de> for RistrettoScalar { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(Secp256k1ScalarVisitor) + fn underlying_ref(&self) -> &Self::Underlying { + &self.fe } -} - -struct Secp256k1ScalarVisitor; - -impl<'de> Visitor<'de> for Secp256k1ScalarVisitor { - type Value = RistrettoScalar; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("ristretto") + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.fe } - - fn visit_str(self, s: &str) -> Result { - let v = BigInt::from_hex(s).map_err(E::custom)?; - Ok(ECScalar::from(&v)) + fn from_underlying(fe: Self::Underlying) -> RistrettoScalar { + RistrettoScalar { + purpose: "from_underlying", + fe: fe.into(), + } } } impl PartialEq for RistrettoScalar { fn eq(&self, other: &RistrettoScalar) -> bool { - self.get_element() == other.get_element() - } -} - -impl PartialEq for RistrettoCurvPoint { - fn eq(&self, other: &RistrettoCurvPoint) -> bool { - self.get_element() == other.get_element() + self.fe == other.fe } } -impl Zeroize for RistrettoCurvPoint { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, GE::generator()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); - } -} - -impl ECPoint for RistrettoCurvPoint { - type SecretKey = SK; - type PublicKey = PK; +impl ECPoint for RistrettoPoint { type Scalar = RistrettoScalar; + type Underlying = PK; - fn base_point2() -> RistrettoCurvPoint { - let g: GE = ECPoint::generator(); - let hash = HSha256::create_hash(&[&g.bytes_compressed_to_big_int()]); - let bytes = BigInt::to_bytes(&hash); - let h: GE = ECPoint::from_bytes(&bytes[..]).unwrap(); - RistrettoCurvPoint { - purpose: "random", - ge: h.get_element(), + fn zero() -> RistrettoPoint { + RistrettoPoint { + purpose: "zero", + ge: PK::identity(), } } - fn generator() -> RistrettoCurvPoint { - RistrettoCurvPoint { - purpose: "base_fe", - ge: RISTRETTO_BASEPOINT_COMPRESSED, - } + fn is_zero(&self) -> bool { + self.ge.is_identity() } - fn get_element(&self) -> PK { - self.ge + fn generator() -> &'static RistrettoPoint { + &GENERATOR } - fn x_coor(&self) -> Option { - unimplemented!(); + fn base_point2() -> &'static RistrettoPoint { + &BASE_POINT2 } - fn y_coor(&self) -> Option { - let y_fe = SK::from_bytes_mod_order(self.ge.to_bytes()); - let y_fe = RistrettoScalar { - purpose: "y_coor", - fe: y_fe, - }; - Some(y_fe.to_big_int()) - } - - fn bytes_compressed_to_big_int(&self) -> BigInt { - BigInt::from_bytes(self.ge.to_bytes()[0..self.ge.to_bytes().len()].as_ref()) - } - fn from_bytes(bytes: &[u8]) -> Result { - let bytes_vec = bytes.to_vec(); - let mut bytes_array_32 = [0u8; 32]; - let byte_len = bytes_vec.len(); - match byte_len { - 0..=32 => { - let mut template = vec![0; 32 - bytes_vec.len()]; - template.extend_from_slice(&bytes); - let bytes_vec = template; - let bytes_slice = &bytes_vec[0..32]; - bytes_array_32.copy_from_slice(&bytes_slice); - let r_point: PK = CompressedRistretto::from_slice(&bytes_array_32); - let r_point_compress = r_point.decompress(); - match r_point_compress { - Some(x) => { - let new_point = RistrettoCurvPoint { - purpose: "random", - ge: x.compress(), - }; - Ok(new_point) - } - None => Err(InvalidPublicKey), - } - } + fn from_coords(x: &BigInt, y: &BigInt) -> Result { + if x != &*NOT_REAL_COORD { + // TODO: can the point be recovered using xrecover from ed25519? + return Err(NotOnCurve); + } - _ => { - let bytes_slice = &bytes_vec[0..32]; - bytes_array_32.copy_from_slice(&bytes_slice); - let r_point: PK = CompressedRistretto::from_slice(&bytes_array_32); - let r_point_compress = r_point.decompress(); - match r_point_compress { - Some(x) => { - let new_point = RistrettoCurvPoint { - purpose: "random", - ge: x.compress(), - }; - Ok(new_point) - } - None => Err(InvalidPublicKey), - } + let y = y.to_bytes(); + let mut y = match y.len() { + 32 => y, + n if n < 32 => { + let mut padded = vec![0u8; 32 - y.len()]; + padded.extend_from_slice(&y); + padded } - } - } + _ => y[y.len() - 32..].to_vec(), + }; - fn pk_to_key_slice(&self) -> Vec { - let result = self.ge.to_bytes(); - result.to_vec() - } + y.reverse(); + let compressed = CompressedRistretto::from_slice(&y); - fn scalar_mul(&self, fe: &SK) -> RistrettoCurvPoint { - let skpk = fe * (self.ge.decompress().unwrap()); - RistrettoCurvPoint { - purpose: "scalar_point_mul", - ge: skpk.compress(), - } + Ok(RistrettoPoint { + purpose: "from_coords", + ge: compressed.decompress().ok_or(NotOnCurve)?, + }) } - fn add_point(&self, other: &PK) -> RistrettoCurvPoint { - let pkpk = self.ge.decompress().unwrap() + other.decompress().unwrap(); - RistrettoCurvPoint { - purpose: "combine", - ge: pkpk.compress(), - } + fn x_coord(&self) -> Option { + // TODO: can the point be recovered using xrecover from ed25519? + Some(NOT_REAL_COORD.clone()) } - fn sub_point(&self, other: &PK) -> RistrettoCurvPoint { - let pkpk = self.ge.decompress().unwrap() - other.decompress().unwrap(); - RistrettoCurvPoint { - purpose: "sub", - ge: pkpk.compress(), - } + fn y_coord(&self) -> Option { + let mut y = self.ge.compress().to_bytes(); + y.reverse(); + Some(BigInt::from_bytes(&y[..])) } - fn from_coor(_x: &BigInt, _y: &BigInt) -> RistrettoCurvPoint { - unimplemented!(); + fn coords(&self) -> Option { + Some(PointCoords { + x: NOT_REAL_COORD.clone(), + y: self.y_coord()?, + }) } -} -impl Mul for RistrettoCurvPoint { - type Output = RistrettoCurvPoint; - fn mul(self, other: RistrettoScalar) -> RistrettoCurvPoint { - self.scalar_mul(&other.get_element()) + fn serialize(&self, _compressed: bool) -> Option> { + Some(self.ge.compress().to_bytes().to_vec()) } -} + fn deserialize(bytes: &[u8]) -> Result { + let mut buffer = [0u8; 32]; + let n = bytes.len(); -impl<'o> Mul<&'o RistrettoScalar> for RistrettoCurvPoint { - type Output = RistrettoCurvPoint; - fn mul(self, other: &'o RistrettoScalar) -> RistrettoCurvPoint { - self.scalar_mul(&other.get_element()) - } -} + if n == 0 || n > 32 { + return Err(DeserializationError); + } + buffer[32 - n..].copy_from_slice(bytes); -impl<'o> Mul<&'o RistrettoScalar> for &'o RistrettoCurvPoint { - type Output = RistrettoCurvPoint; - fn mul(self, other: &'o RistrettoScalar) -> RistrettoCurvPoint { - self.scalar_mul(&other.get_element()) + CompressedRistretto::from_slice(&buffer) + .decompress() + .ok_or(DeserializationError) + .map(|ge| RistrettoPoint { + purpose: "deserialize", + ge, + }) } -} -impl Add for RistrettoCurvPoint { - type Output = RistrettoCurvPoint; - fn add(self, other: RistrettoCurvPoint) -> RistrettoCurvPoint { - self.add_point(&other.get_element()) + fn check_point_order_equals_group_order(&self) -> bool { + !self.is_zero() } -} -impl<'o> Add<&'o RistrettoCurvPoint> for RistrettoCurvPoint { - type Output = RistrettoCurvPoint; - fn add(self, other: &'o RistrettoCurvPoint) -> RistrettoCurvPoint { - self.add_point(&other.get_element()) + fn scalar_mul(&self, fe: &Self::Scalar) -> RistrettoPoint { + RistrettoPoint { + purpose: "scalar_mul", + ge: self.ge * *fe.fe, + } } -} -impl<'o> Add<&'o RistrettoCurvPoint> for &'o RistrettoCurvPoint { - type Output = RistrettoCurvPoint; - fn add(self, other: &'o RistrettoCurvPoint) -> RistrettoCurvPoint { - self.add_point(&other.get_element()) + fn add_point(&self, other: &Self) -> RistrettoPoint { + RistrettoPoint { + purpose: "add_point", + ge: self.ge + other.ge, + } } -} -#[cfg(feature = "merkle")] -impl Hashable for RistrettoCurvPoint { - fn update_context(&self, context: &mut Sha3) { - let bytes: Vec = self.pk_to_key_slice(); - context.input(&bytes[..]); + fn sub_point(&self, other: &Self) -> RistrettoPoint { + RistrettoPoint { + purpose: "sub_point", + ge: self.ge - other.ge, + } } -} -impl Serialize for RistrettoCurvPoint { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let bytes = self.pk_to_key_slice(); - let bytes_as_bn = BigInt::from_bytes(&bytes[..]); - let mut state = serializer.serialize_struct("RistrettoCurvPoint", 1)?; - state.serialize_field("bytes_str", &bytes_as_bn.to_hex())?; - state.end() + fn neg_point(&self) -> RistrettoPoint { + RistrettoPoint { + purpose: "sub_point", + ge: -self.ge, + } } -} -impl<'de> Deserialize<'de> for RistrettoCurvPoint { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - const FIELDS: &[&str] = &["bytes_str"]; - deserializer.deserialize_struct("RistrettoCurvPoint", FIELDS, RistrettoCurvPointVisitor) + fn scalar_mul_assign(&mut self, scalar: &Self::Scalar) { + self.ge *= &*scalar.fe } -} - -struct RistrettoCurvPointVisitor; - -impl<'de> Visitor<'de> for RistrettoCurvPointVisitor { - type Value = RistrettoCurvPoint; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("RistrettoCurvPoint") + fn add_point_assign(&mut self, other: &Self) { + self.ge += &other.ge } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let bytes_str = seq - .next_element()? - .ok_or_else(|| V::Error::invalid_length(0, &"a single element"))?; - let bytes_bn = BigInt::from_hex(bytes_str).map_err(V::Error::custom)?; - let bytes = BigInt::to_bytes(&bytes_bn); - RistrettoCurvPoint::from_bytes(&bytes[..]) - .map_err(|_| V::Error::custom("failed to parse ristretto point")) + fn sub_point_assign(&mut self, other: &Self) { + self.ge -= &other.ge } - - fn visit_map>(self, mut map: E) -> Result { - let mut bytes_str: String = "".to_string(); - - while let Some(key) = map.next_key::<&'de str>()? { - let v = map.next_value::<&'de str>()?; - match key { - "bytes_str" => { - bytes_str = String::from(v); - } - _ => return Err(E::Error::unknown_field(key, &["bytes_str"])), - } + fn underlying_ref(&self) -> &Self::Underlying { + &self.ge + } + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.ge + } + fn from_underlying(ge: Self::Underlying) -> RistrettoPoint { + RistrettoPoint { + purpose: "from_underlying", + ge, } - let bytes_bn = BigInt::from_hex(&bytes_str).map_err(E::Error::custom)?; - let bytes = BigInt::to_bytes(&bytes_bn); + } +} - RistrettoCurvPoint::from_bytes(&bytes[..]) - .map_err(|_| E::Error::custom("failed to parse ristretto point")) +impl PartialEq for RistrettoPoint { + fn eq(&self, other: &RistrettoPoint) -> bool { + self.ge == other.ge } } -#[cfg(test)] -mod tests { - use super::{RistrettoCurvPoint, RistrettoScalar}; - use crate::arithmetic::traits::*; - use crate::elliptic::curves::traits::ECPoint; - use crate::elliptic::curves::traits::ECScalar; - use crate::BigInt; - - type GE = RistrettoCurvPoint; - type FE = RistrettoScalar; - - #[test] - fn test_serdes_pk() { - let pk = GE::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); - - let pk = GE::base_point2(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); - } - - #[test] - fn bincode_pk() { - let pk = GE::generator(); - let encoded = bincode::serialize(&pk).unwrap(); - let decoded: RistrettoCurvPoint = bincode::deserialize(encoded.as_slice()).unwrap(); - assert_eq!(decoded, pk); - } - - #[test] - #[should_panic] - fn test_serdes_bad_pk() { - let pk = GE::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - // we make sure that the string encodes invalid point: - let s: String = s.replace("e2f2", "e2f5"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); - } - - #[test] - fn test_from_mpz() { - let rand_scalar: FE = ECScalar::new_random(); - let rand_bn = rand_scalar.to_big_int(); - let rand_scalar2: FE = ECScalar::from(&rand_bn); - assert_eq!(rand_scalar, rand_scalar2); - } - - #[test] - fn test_from_slice() { - let point: GE = GE::base_point2(); - let point_bn = point.bytes_compressed_to_big_int(); - let point_bytes = BigInt::to_bytes(&point_bn); - let point_reconstruct = GE::from_bytes(&point_bytes[..]).expect("bad encoding of point"); - assert_eq!(point_reconstruct, point); - } - - #[test] - #[should_panic] - fn test_from_slice_bad_point() { - // let rng = &mut thread_rng(); - // rng.fill(&mut scalar_bytes); - let scalar_bytes = [ - 47, 99, 244, 119, 185, 184, 77, 196, 233, 191, 206, 168, 191, 24, 226, 7, 254, 11, 131, - 172, 57, 35, 110, 9, 103, 25, 98, 249, 219, 248, 33, 115, - ]; - GE::from_bytes(&scalar_bytes[..]).expect("bad encoding of point"); - } - // this test fails once in a while. - #[test] - fn test_minus_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let b_bn = b.to_big_int(); - let order = FE::q(); - let minus_b = BigInt::mod_sub(&order, &b_bn, &order); - let a_minus_b = BigInt::mod_add(&a.to_big_int(), &minus_b, &order); - let a_minus_b_fe: FE = ECScalar::from(&a_minus_b); - let base: GE = ECPoint::generator(); - let point_ab1 = base * a_minus_b_fe; - let point_a = base * a; - let point_b = base * b; - let point_ab2 = point_a.sub_point(&point_b.get_element()); - assert_eq!(point_ab1, point_ab2); - } - - #[test] - fn test_invert() { - let a: FE = ECScalar::new_random(); - let a_bn = a.to_big_int(); - let a_inv = a.invert(); - let a_inv_bn_1 = BigInt::mod_inv(&a_bn, &FE::q()).unwrap(); - let a_inv_bn_2 = a_inv.to_big_int(); - assert_eq!(a_inv_bn_1, a_inv_bn_2); - } - - #[test] - fn test_from_bytes_3() { - let test_vec = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 3, 4, 5, 6, - ]; - let result = RistrettoCurvPoint::from_bytes(&test_vec); - assert!(result.is_ok()) +impl Zeroize for RistrettoPoint { + fn zeroize(&mut self) { + unsafe { ptr::write_volatile(&mut self.ge, PK::default()) }; + atomic::fence(atomic::Ordering::SeqCst); + atomic::compiler_fence(atomic::Ordering::SeqCst); } } diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index 9b2a8bc8..e1a29eea 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -1,5 +1,5 @@ // pub mod bls12_381; -// pub mod curve_ristretto; +pub mod curve_ristretto; pub mod ed25519; pub mod p256; pub mod secp256_k1; @@ -9,7 +9,9 @@ mod test; mod traits; mod wrappers; -pub use self::{ed25519::Ed25519, p256::Secp256r1, secp256_k1::Secp256k1}; +pub use self::{ + curve_ristretto::Ristretto, ed25519::Ed25519, p256::Secp256r1, secp256_k1::Secp256k1, +}; pub use self::{ traits::{Curve, ECPoint, ECScalar, PointCoords}, wrappers::{Generator, Point, PointRef, PointZ, Scalar, ScalarZ}, diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index c1af9ca6..1ac85360 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -20,7 +20,6 @@ use std::ops; use std::ptr; use std::sync::atomic; -use rand::thread_rng; use secp256k1::constants::{ self, GENERATOR_X, GENERATOR_Y, SECRET_KEY_SIZE, UNCOMPRESSED_PUBLIC_KEY_SIZE, }; @@ -156,7 +155,7 @@ impl ECScalar for Secp256k1Scalar { type Underlying = Option; fn random() -> Secp256k1Scalar { - let sk = SK(SecretKey::new(&mut thread_rng())); + let sk = SK(SecretKey::new(&mut rand_legacy::thread_rng())); Secp256k1Scalar { purpose: "random", fe: Zeroizing::new(Some(sk)), diff --git a/src/elliptic/curves/test.rs b/src/elliptic/curves/test.rs index c54c551e..a83b091c 100644 --- a/src/elliptic/curves/test.rs +++ b/src/elliptic/curves/test.rs @@ -2,7 +2,7 @@ use std::iter; -use rand::{rngs::StdRng, FromEntropy, Rng}; +use rand::{rngs::OsRng, Rng}; use crate::arithmetic::*; use crate::test_for_all_curves; @@ -95,7 +95,7 @@ fn generator_mul_curve_order_is_zero() { test_for_all_curves!(scalar_behaves_the_same_as_bigint); fn scalar_behaves_the_same_as_bigint() { - let mut rng = StdRng::from_entropy(); + let mut rng = OsRng; let q = E::Scalar::group_order(); let mut n = BigInt::zero(); @@ -209,3 +209,22 @@ fn test_multiplication_point_at_scalar() { assert_eq!(abG, a_mul_b_G); } + +test_for_all_curves!(scalar_invert); +fn scalar_invert() { + let n: E::Scalar = ECScalar::random(); + if n.is_zero() { + // Scalar is zero => restart the test + scalar_invert::() + } + + let n_inv = n.invert().unwrap(); + assert_eq!(n.mul(&n_inv), ECScalar::from_bigint(&BigInt::one())) +} + +test_for_all_curves!(zero_scalar_invert); +fn zero_scalar_invert() { + let n: E::Scalar = ECScalar::zero(); + let n_inv = n.invert(); + assert!(n_inv.is_none()) +} diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 3a600a12..0beac311 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -46,7 +46,9 @@ pub trait ECScalar: Clone + PartialEq + fmt::Debug + 'static { /// Constructs a zero scalar fn zero() -> Self; /// Checks if the scalar equals to zero - fn is_zero(&self) -> bool; + fn is_zero(&self) -> bool { + self == &Self::zero() + } /// Constructs a scalar `n % group_order` fn from_bigint(n: &BigInt) -> Self; diff --git a/src/lib.rs b/src/lib.rs index d9fdcc1b..6635e297 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,11 +49,11 @@ macro_rules! test_for_all_curves { fn [<$fn _ed25519>]() { $fn::() } - // #[test] - // $($attrs)* - // fn [<$fn _ristretto>]() { - // $fn::() - // } + #[test] + $($attrs)* + fn [<$fn _ristretto>]() { + $fn::() + } // #[test] // $($attrs)* // fn [<$fn _bls12_381>]() { From e9c149b72f6afb04c7cc889d1531766de1997a35 Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 14 Jul 2021 17:39:59 +0300 Subject: [PATCH 56/93] Ristretto: x=hash(y) --- src/elliptic/curves/curve_ristretto.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/elliptic/curves/curve_ristretto.rs b/src/elliptic/curves/curve_ristretto.rs index 801eaf4b..3729f986 100644 --- a/src/elliptic/curves/curve_ristretto.rs +++ b/src/elliptic/curves/curve_ristretto.rs @@ -42,8 +42,6 @@ lazy_static::lazy_static! { ge: RistrettoPoint::deserialize(&hash).unwrap().ge, } }; - - static ref NOT_REAL_COORD: BigInt = BigInt::from_bytes(b"not a real coordinate"); } pub const SECRET_KEY_SIZE: usize = 32; @@ -231,8 +229,7 @@ impl ECPoint for RistrettoPoint { } fn from_coords(x: &BigInt, y: &BigInt) -> Result { - if x != &*NOT_REAL_COORD { - // TODO: can the point be recovered using xrecover from ed25519? + if x != &BigInt::from_bytes(&Sha256::digest(&y.to_bytes())) { return Err(NotOnCurve); } @@ -257,8 +254,11 @@ impl ECPoint for RistrettoPoint { } fn x_coord(&self) -> Option { - // TODO: can the point be recovered using xrecover from ed25519? - Some(NOT_REAL_COORD.clone()) + // Underlying library intentionally hides x coordinate. We return x=hash(y) as was proposed + // here: https://github.com/dalek-cryptography/curve25519-dalek/issues/235 + let y = self.y_coord()?.to_bytes(); + let x = Sha256::digest(&y); + Some(BigInt::from_bytes(&x)) } fn y_coord(&self) -> Option { @@ -268,9 +268,11 @@ impl ECPoint for RistrettoPoint { } fn coords(&self) -> Option { + let y = self.y_coord()?; + let x = Sha256::digest(&y.to_bytes()); Some(PointCoords { - x: NOT_REAL_COORD.clone(), - y: self.y_coord()?, + x: BigInt::from_bytes(&x), + y, }) } From 0f364890a6e243b7bb6b851914c3742c9461980c Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 15 Jul 2021 23:48:59 +0300 Subject: [PATCH 57/93] Add the first BLS curve --- src/elliptic/curves/bls12_381/g1.rs | 820 +++++++++------------------ src/elliptic/curves/bls12_381/mod.rs | 162 +++--- src/elliptic/curves/mod.rs | 5 +- src/lib.rs | 5 + 4 files changed, 369 insertions(+), 623 deletions(-) diff --git a/src/elliptic/curves/bls12_381/g1.rs b/src/elliptic/curves/bls12_381/g1.rs index 367680a4..dc5afe8c 100644 --- a/src/elliptic/curves/bls12_381/g1.rs +++ b/src/elliptic/curves/bls12_381/g1.rs @@ -5,531 +5,392 @@ License MIT: */ -pub const SECRET_KEY_SIZE: usize = 32; -pub const COMPRESSED_SIZE: usize = 48; - use std::fmt; -use std::fmt::Debug; -use std::ops::{Add, Mul, Neg}; -use std::str; +use std::io::Cursor; use ff_zeroize::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; use pairing_plus::bls12_381::{Fr, G1Compressed, G1Uncompressed, G1}; use pairing_plus::hash_to_curve::HashToCurve; use pairing_plus::hash_to_field::ExpandMsgXmd; -use pairing_plus::serdes::SerDes; -use pairing_plus::EncodedPoint; use pairing_plus::{CurveAffine, CurveProjective, Engine}; +use pairing_plus::{EncodedPoint, SubgroupCheck}; +use rand::rngs::OsRng; use sha2::Sha256; +use zeroize::{Zeroize, Zeroizing}; + +use crate::arithmetic::traits::*; +use crate::elliptic::curves::traits::*; +use crate::BigInt; + +lazy_static::lazy_static! { + static ref GROUP_ORDER: BigInt = { + let q_u64: [u64; 4] = [ + 0xffffffff00000001, + 0x53bda402fffe5bfe, + 0x3339d80809a1d805, + 0x73eda753299d7d48, + ]; + let to_bn = q_u64.iter().rev().fold(BigInt::zero(), |acc, x| { + let element_bn = BigInt::from(*x); + element_bn + (acc << 64) + }); + to_bn + }; -use serde::de::{self, Error, MapAccess, SeqAccess, Visitor}; -use serde::ser::SerializeStruct; -use serde::ser::{Serialize, Serializer}; -use serde::{Deserialize, Deserializer}; + static ref GENERATOR: G1Point = G1Point { + purpose: "generator", + ge: PK::one(), + }; + + static ref BASE_POINT2: G1Point = { + const BASE_POINT2: [u8; 96] = [ + 10, 18, 122, 36, 178, 251, 236, 31, 139, 88, 242, 163, 21, 198, 168, 208, 122, 195, + 135, 122, 7, 153, 197, 255, 160, 0, 89, 138, 39, 245, 105, 108, 99, 113, 78, 70, 130, + 172, 183, 57, 170, 180, 39, 32, 173, 29, 238, 62, 13, 166, 109, 90, 181, 17, 76, 247, + 26, 155, 130, 211, 18, 42, 235, 137, 225, 184, 210, 140, 54, 83, 233, 228, 226, 70, + 194, 50, 55, 116, 229, 2, 115, 227, 223, 31, 165, 39, 191, 209, 49, 127, 106, 196, 123, + 71, 70, 243, + ]; + let mut point = G1Uncompressed::empty(); + point.as_mut().copy_from_slice(&BASE_POINT2); + G1Point { + purpose: "base_point2", + ge: point.into_affine().expect("invalid base_point"), + } + }; +} + +pub const SECRET_KEY_SIZE: usize = 32; +pub const COMPRESSED_SIZE: usize = 48; pub type SK = ::Fr; pub type PK = ::G1Affine; -use crate::arithmetic::traits::*; -use crate::BigInt; -use crate::ErrorKey::{self}; - -use std::ptr; -use std::sync::atomic; -use zeroize::Zeroize; - -use crate::elliptic::curves::traits::ECPoint; -use crate::elliptic::curves::traits::ECScalar; -#[cfg(feature = "merkle")] -use crypto::digest::Digest; -#[cfg(feature = "merkle")] -use crypto::sha3::Sha3; -#[cfg(feature = "merkle")] -use merkle::Hashable; -use std::io::Cursor; +#[derive(Debug, PartialEq, Clone)] +pub enum Bls12_381_1 {} -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct FieldScalar { purpose: &'static str, - fe: SK, + fe: Zeroizing, } #[derive(Clone, Copy)] pub struct G1Point { purpose: &'static str, ge: PK, } -pub type GE = G1Point; -pub type FE = FieldScalar; +pub type GE1 = G1Point; +pub type FE1 = FieldScalar; -impl Zeroize for FieldScalar { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, FE::zero()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); - } +impl Curve for Bls12_381_1 { + type Point = GE1; + type Scalar = FE1; + + const CURVE_NAME: &'static str = "bls12_381_1"; } impl ECScalar for FieldScalar { - type SecretKey = SK; + type Underlying = SK; - fn new_random() -> FieldScalar { - let rnd_bn = BigInt::sample_below(&FE::q()); - ECScalar::from(&rnd_bn) + fn random() -> FieldScalar { + FieldScalar { + purpose: "random", + fe: Zeroizing::new(Field::random(&mut OsRng)), + } } fn zero() -> FieldScalar { FieldScalar { purpose: "zero", - fe: SK::default(), + fe: Zeroizing::new(Field::zero()), } } - fn get_element(&self) -> SK { - self.fe - } - fn set_element(&mut self, element: SK) { - self.fe = element - } - - fn from(n: &BigInt) -> FieldScalar { - let n_mod = BigInt::modulus(n, &FE::q()); - let mut v = BigInt::to_bytes(&n_mod); - let mut bytes_array: [u8; SECRET_KEY_SIZE]; - if v.len() < SECRET_KEY_SIZE { - let mut template = vec![0; SECRET_KEY_SIZE - v.len()]; - template.extend_from_slice(&v); - v = template; + fn from_bigint(n: &BigInt) -> FieldScalar { + let n_mod = BigInt::modulus(n, &FE1::group_order()); + let n_mod = n_mod.to_bytes(); + let mut bytes_array = [0u8; SECRET_KEY_SIZE]; + if n_mod.len() < SECRET_KEY_SIZE { + bytes_array[SECRET_KEY_SIZE - n_mod.len()..].copy_from_slice(&n_mod) + } else { + bytes_array.copy_from_slice(&n_mod[..SECRET_KEY_SIZE]) } - bytes_array = [0; SECRET_KEY_SIZE]; - let bytes = &v[..SECRET_KEY_SIZE]; - bytes_array.copy_from_slice(&bytes); - - // bytes_array.reverse(); let mut repr = SK::default().into_repr(); repr.read_be(Cursor::new(&bytes_array[..])).unwrap(); FieldScalar { - purpose: "from_big_int", - fe: Fr::from_repr(repr).unwrap(), + purpose: "from_bigint", + fe: Fr::from_repr(repr).unwrap().into(), } } - fn to_big_int(&self) -> BigInt { - let tmp = self.fe.into_repr(); - let scalar_u64 = tmp.as_ref(); - - let to_bn = scalar_u64.iter().rev().fold(BigInt::zero(), |acc, x| { - let element_bn = BigInt::from(*x); - element_bn + (acc << 64) - }); - to_bn - } - - fn q() -> BigInt { - let q_u64: [u64; 4] = [ - 0xffffffff00000001, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ]; - let to_bn = q_u64.iter().rev().fold(BigInt::zero(), |acc, x| { - let element_bn = BigInt::from(*x); - element_bn + (acc << 64) - }); - to_bn + fn to_bigint(&self) -> BigInt { + let repr = self.fe.into_repr(); + let mut bytes = vec![]; + repr.write_be(&mut bytes).unwrap(); + BigInt::from_bytes(&bytes) } - fn add(&self, other: &SK) -> FieldScalar { - let mut add_fe = FieldScalar { - purpose: "other add", - fe: *other, - }; - add_fe.fe.add_assign(&self.fe); + fn add(&self, other: &Self) -> FieldScalar { + let mut result = self.fe.clone(); + result.add_assign(&other.fe); FieldScalar { purpose: "add", - fe: add_fe.fe, + fe: result, } } - fn mul(&self, other: &SK) -> FieldScalar { - let mut mul_fe = FieldScalar { - purpose: "other mul", - fe: *other, - }; - mul_fe.fe.mul_assign(&self.fe); + fn mul(&self, other: &Self) -> FieldScalar { + let mut result = self.fe.clone(); + result.mul_assign(&other.fe); FieldScalar { purpose: "mul", - fe: mul_fe.fe, + fe: result, } } - fn sub(&self, other: &SK) -> FieldScalar { - let mut other_neg = *other; - other_neg.negate(); - let sub_fe = FieldScalar { - purpose: "other sub", - fe: other_neg, - }; - self.add(&sub_fe.get_element()) + fn sub(&self, other: &Self) -> FieldScalar { + let mut result = self.fe.clone(); + result.sub_assign(&other.fe); + FieldScalar { + purpose: "sub", + fe: result, + } } - fn invert(&self) -> FieldScalar { - let sc = self.fe; - let inv_sc = sc.inverse().unwrap(); //TODO - + fn neg(&self) -> FieldScalar { + let mut result = self.fe.clone(); + result.negate(); FieldScalar { - purpose: "inverse", - fe: inv_sc, + purpose: "neg", + fe: result, } } -} -impl Debug for FieldScalar { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Point {{ purpose: {:?}, bytes: {:?} }}", - self.purpose, self.fe, - ) + fn invert(&self) -> Option { + Some(FieldScalar { + purpose: "invert", + fe: Zeroizing::new(self.fe.inverse()?), + }) } -} -impl PartialEq for FieldScalar { - fn eq(&self, other: &FieldScalar) -> bool { - self.get_element() == other.get_element() + fn add_assign(&mut self, other: &Self) { + self.fe.add_assign(&other.fe); } -} - -impl Mul for FieldScalar { - type Output = FieldScalar; - fn mul(self, other: FieldScalar) -> FieldScalar { - (&self).mul(&other.get_element()) + fn mul_assign(&mut self, other: &Self) { + self.fe.mul_assign(&other.fe); } -} - -impl<'o> Mul<&'o FieldScalar> for FieldScalar { - type Output = FieldScalar; - fn mul(self, other: &'o FieldScalar) -> FieldScalar { - (&self).mul(&other.get_element()) + fn sub_assign(&mut self, other: &Self) { + self.fe.sub_assign(&other.fe); } -} - -impl Add for FieldScalar { - type Output = FieldScalar; - fn add(self, other: FieldScalar) -> FieldScalar { - (&self).add(&other.get_element()) + fn neg_assign(&mut self) { + self.fe.negate(); } -} -impl<'o> Add<&'o FieldScalar> for FieldScalar { - type Output = FieldScalar; - fn add(self, other: &'o FieldScalar) -> FieldScalar { - (&self).add(&other.get_element()) + fn group_order() -> &'static BigInt { + &GROUP_ORDER } -} - -impl Serialize for FieldScalar { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_big_int().to_hex()) - } -} -impl<'de> Deserialize<'de> for FieldScalar { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(BLS12_381ScalarVisitor) + fn underlying_ref(&self) -> &Self::Underlying { + &self.fe } -} - -struct BLS12_381ScalarVisitor; - -impl<'de> Visitor<'de> for BLS12_381ScalarVisitor { - type Value = FieldScalar; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("bls12_381") + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.fe } - - fn visit_str(self, s: &str) -> Result { - let v = BigInt::from_hex(s).map_err(E::custom)?; - Ok(ECScalar::from(&v)) + fn from_underlying(fe: Self::Underlying) -> FieldScalar { + FieldScalar { + purpose: "from_underlying", + fe: fe.into(), + } } } -impl Debug for G1Point { +impl fmt::Debug for FieldScalar { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "Point {{ purpose: {:?}, bytes: {:?} }}", - self.purpose, - self.bytes_compressed_to_big_int().to_hex() + self.purpose, self.fe, ) } } -impl PartialEq for G1Point { - fn eq(&self, other: &G1Point) -> bool { - self.get_element() == other.get_element() - } -} - -impl Zeroize for G1Point { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, GE::generator()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); +impl PartialEq for FieldScalar { + fn eq(&self, other: &FieldScalar) -> bool { + self.fe == other.fe } } impl ECPoint for G1Point { - type SecretKey = SK; - type PublicKey = PK; type Scalar = FieldScalar; + type Underlying = PK; - fn base_point2() -> G1Point { - const BASE_POINT2: [u8; 96] = [ - 10, 18, 122, 36, 178, 251, 236, 31, 139, 88, 242, 163, 21, 198, 168, 208, 122, 195, - 135, 122, 7, 153, 197, 255, 160, 0, 89, 138, 39, 245, 105, 108, 99, 113, 78, 70, 130, - 172, 183, 57, 170, 180, 39, 32, 173, 29, 238, 62, 13, 166, 109, 90, 181, 17, 76, 247, - 26, 155, 130, 211, 18, 42, 235, 137, 225, 184, 210, 140, 54, 83, 233, 228, 226, 70, - 194, 50, 55, 116, 229, 2, 115, 227, 223, 31, 165, 39, 191, 209, 49, 127, 106, 196, 123, - 71, 70, 243, - ]; - let mut point = G1Uncompressed::empty(); - point.as_mut().copy_from_slice(&BASE_POINT2); - G1Point { - purpose: "base_ge2", - ge: point.into_affine().expect("invalid base_point"), - } - } - - fn generator() -> G1Point { + fn zero() -> G1Point { G1Point { - purpose: "base_fe", - ge: PK::one(), + purpose: "zero", + ge: PK::zero(), } } - fn get_element(&self) -> PK { - self.ge + fn is_zero(&self) -> bool { + self.ge.is_zero() } - fn x_coor(&self) -> Option { - let tmp = G1Uncompressed::from_affine(self.ge); - let bytes = tmp.as_ref(); - let x_coor = &bytes[0..COMPRESSED_SIZE]; - let bn = BigInt::from_bytes(x_coor); - Some(bn) + fn generator() -> &'static G1Point { + &GENERATOR } - fn y_coor(&self) -> Option { - let tmp = G1Uncompressed::from_affine(self.ge); - let bytes = tmp.as_ref(); - let y_coor = &bytes[COMPRESSED_SIZE..COMPRESSED_SIZE * 2]; - let bn = BigInt::from_bytes(y_coor); - Some(bn) + fn base_point2() -> &'static G1Point { + &BASE_POINT2 } - fn bytes_compressed_to_big_int(&self) -> BigInt { - let tmp = G1Compressed::from_affine(self.ge); - let bytes = tmp.as_ref(); - BigInt::from_bytes(bytes) - } + fn from_coords(x: &BigInt, y: &BigInt) -> Result { + let x = x.to_bytes(); + let y = y.to_bytes(); - fn from_bytes(bytes: &[u8]) -> Result { - let mut bytes_array_comp = [0u8; COMPRESSED_SIZE]; - match bytes.len() { - 0..=COMPRESSED_SIZE => { - (&mut bytes_array_comp[COMPRESSED_SIZE - bytes.len()..]).copy_from_slice(bytes); - } - _ => { - bytes_array_comp.copy_from_slice(&bytes[..COMPRESSED_SIZE]); - } + let mut uncompressed = [0u8; COMPRESSED_SIZE * 2]; + if x.len() <= COMPRESSED_SIZE { + uncompressed[COMPRESSED_SIZE - x.len()..COMPRESSED_SIZE].copy_from_slice(&x) + } else { + return Err(NotOnCurve); } - let g1_comp = G1::deserialize(&mut bytes_array_comp[..].as_ref(), true).unwrap(); - let pk = G1Point { - purpose: "from_bytes", - ge: g1_comp.into_affine(), //TODO: handle error - }; + if y.len() <= COMPRESSED_SIZE { + uncompressed[2 * COMPRESSED_SIZE - y.len()..2 * COMPRESSED_SIZE].copy_from_slice(&y) + } else { + return Err(NotOnCurve); + } - Ok(pk) + let mut point = G1Uncompressed::empty(); + point.as_mut().copy_from_slice(&uncompressed); + + Ok(G1Point { + purpose: "from_coords", + ge: point.into_affine().map_err(|_| NotOnCurve)?, + }) + } + + fn x_coord(&self) -> Option { + if self.is_zero() { + None + } else { + let uncompressed = G1Uncompressed::from_affine(self.ge); + let x_coord = &uncompressed.as_ref()[0..COMPRESSED_SIZE]; + let bn = BigInt::from_bytes(x_coord); + Some(bn) + } } - // in this case the opposite of from_bytes: takes compressed pk to COMPRESSED_SIZE bytes. - fn pk_to_key_slice(&self) -> Vec { - let mut compressed_vec = vec![]; - PK::serialize(&self.ge, &mut compressed_vec, true) - .expect("serializing into vec should always succeed"); - compressed_vec + fn y_coord(&self) -> Option { + if self.is_zero() { + None + } else { + let uncompressed = G1Uncompressed::from_affine(self.ge); + let y_coord = &uncompressed.as_ref()[COMPRESSED_SIZE..COMPRESSED_SIZE * 2]; + let bn = BigInt::from_bytes(y_coord); + Some(bn) + } } - fn scalar_mul(&self, fe: &SK) -> G1Point { - let mut ge_proj: G1 = self.ge.into(); - ge_proj.mul_assign(fe.into_repr()); - G1Point { - purpose: "scalar_point_mul", - ge: ge_proj.into_affine(), + fn coords(&self) -> Option { + if self.is_zero() { + None + } else { + let uncompressed = G1Uncompressed::from_affine(self.ge); + let x = &uncompressed.as_ref()[0..COMPRESSED_SIZE]; + let y = &uncompressed.as_ref()[COMPRESSED_SIZE..COMPRESSED_SIZE * 2]; + let x = BigInt::from_bytes(x); + let y = BigInt::from_bytes(y); + Some(PointCoords { x, y }) } } - fn add_point(&self, other: &PK) -> G1Point { - let mut ge_proj: G1 = self.ge.into(); - ge_proj.add_assign_mixed(other); - G1Point { - purpose: "combine", - ge: ge_proj.into_affine(), + fn serialize(&self, compressed: bool) -> Option> { + if self.is_zero() { + None + } else if compressed { + Some(G1Compressed::from_affine(self.ge).as_ref().to_vec()) + } else { + Some(G1Uncompressed::from_affine(self.ge).as_ref().to_vec()) } } - fn sub_point(&self, other: &PK) -> G1Point { - let mut ge_proj: G1 = self.ge.into(); - ge_proj.sub_assign_mixed(other); - G1Point { - purpose: "sub", - ge: ge_proj.into_affine(), + fn deserialize(bytes: &[u8]) -> Result { + if bytes.len() == COMPRESSED_SIZE { + let mut compressed = G1Compressed::empty(); + compressed.as_mut().copy_from_slice(bytes); + Ok(G1Point { + purpose: "deserialize", + ge: compressed.into_affine().map_err(|_| DeserializationError)?, + }) + } else if bytes.len() == 2 * COMPRESSED_SIZE { + let mut uncompressed = G1Uncompressed::empty(); + uncompressed.as_mut().copy_from_slice(bytes); + Ok(G1Point { + purpose: "deserialize", + ge: uncompressed + .into_affine() + .map_err(|_| DeserializationError)?, + }) + } else { + Err(DeserializationError) } } - fn from_coor(_x: &BigInt, _y: &BigInt) -> G1Point { - // TODO - unimplemented!(); + fn check_point_order_equals_group_order(&self) -> bool { + !self.is_zero() && self.ge.in_subgroup() } -} -impl From for G1Point { - fn from(point: PK) -> Self { + fn scalar_mul(&self, scalar: &Self::Scalar) -> G1Point { + let result = self.ge.mul(scalar.fe.into_repr()); G1Point { - purpose: "from_point", - ge: point, + purpose: "scalar_mul", + ge: result.into_affine(), } } -} - -impl Mul for G1Point { - type Output = G1Point; - fn mul(self, other: FieldScalar) -> G1Point { - self.scalar_mul(&other.get_element()) - } -} -impl<'o> Mul<&'o FieldScalar> for G1Point { - type Output = G1Point; - fn mul(self, other: &'o FieldScalar) -> G1Point { - self.scalar_mul(&other.get_element()) - } -} - -impl<'o> Mul<&'o FieldScalar> for &'o G1Point { - type Output = G1Point; - fn mul(self, other: &'o FieldScalar) -> G1Point { - self.scalar_mul(&other.get_element()) - } -} - -impl Add for G1Point { - type Output = G1Point; - fn add(self, other: G1Point) -> G1Point { - self.add_point(&other.get_element()) + fn add_point(&self, other: &Self) -> G1Point { + let mut result = G1::from(self.ge); + result.add_assign_mixed(&other.ge); + G1Point { + purpose: "add_point", + ge: result.into_affine(), + } } -} -impl<'o> Add<&'o G1Point> for G1Point { - type Output = G1Point; - fn add(self, other: &'o G1Point) -> G1Point { - self.add_point(&other.get_element()) + fn sub_point(&self, other: &Self) -> G1Point { + let mut result = G1::from(self.ge); + result.sub_assign_mixed(&other.ge); + G1Point { + purpose: "sub_point", + ge: result.into_affine(), + } } -} -impl<'o> Add<&'o G1Point> for &'o G1Point { - type Output = G1Point; - fn add(self, other: &'o G1Point) -> G1Point { - self.add_point(&other.get_element()) + fn neg_point(&self) -> Self { + let mut result = self.ge; + result.negate(); + G1Point { + purpose: "neg", + ge: result, + } } -} -impl Neg for G1Point { - type Output = Self; - fn neg(mut self) -> Self { + fn neg_point_assign(&mut self) { self.ge.negate(); - self.purpose = "negated"; - self } -} -#[cfg(feature = "merkle")] -impl Hashable for G1Point { - fn update_context(&self, context: &mut Sha3) { - let bytes: Vec = self.pk_to_key_slice(); - context.input(&bytes[..]); + fn underlying_ref(&self) -> &Self::Underlying { + &self.ge } -} - -impl Serialize for G1Point { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let bytes = self.pk_to_key_slice(); - let bytes_as_bn = BigInt::from_bytes(&bytes[..]); - let mut state = serializer.serialize_struct("Bls12381G1Point", 1)?; - state.serialize_field("bytes_str", &bytes_as_bn.to_hex())?; - state.end() + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.ge } -} - -impl<'de> Deserialize<'de> for G1Point { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - const FIELDS: &[&str] = &["bytes_str"]; - deserializer.deserialize_struct("Bls12381G1Point", FIELDS, Bls12381G1PointVisitor) - } -} - -struct Bls12381G1PointVisitor; - -impl<'de> Visitor<'de> for Bls12381G1PointVisitor { - type Value = G1Point; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Bls12381G1Point") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let bytes_str = seq - .next_element()? - .ok_or_else(|| V::Error::invalid_length(0, &"a single element"))?; - let bytes_bn = BigInt::from_hex(bytes_str).map_err(V::Error::custom)?; - let bytes = BigInt::to_bytes(&bytes_bn); - G1Point::from_bytes(&bytes[..]).map_err(|_| V::Error::custom("failed to parse g1 point")) - } - - fn visit_map>(self, mut map: E) -> Result { - let mut bytes_str: String = "".to_string(); - - while let Some(key) = map.next_key::<&'de str>()? { - let v = map.next_value::<&'de str>()?; - match key { - "bytes_str" => { - bytes_str = String::from(v); - } - _ => return Err(E::Error::unknown_field(key, &["bytes_str"])), - } + fn from_underlying(ge: Self::Underlying) -> G1Point { + G1Point { + purpose: "from_underlying", + ge, } - let bytes_bn = BigInt::from_hex(&bytes_str).map_err(E::Error::custom)?; - let bytes = BigInt::to_bytes(&bytes_bn); - - G1Point::from_bytes(&bytes[..]).map_err(|_| E::Error::custom("failed to parse g1 point")) } } @@ -549,6 +410,31 @@ impl G1Point { } } +impl fmt::Debug for G1Point { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "Point {{ purpose: {:?}, uncompressed: {:?} }}", + self.purpose, + self.serialize(false) + .map(hex::encode) + .unwrap_or_else(|| "infinity".to_string()) + ) + } +} + +impl PartialEq for G1Point { + fn eq(&self, other: &G1Point) -> bool { + self.ge == other.ge + } +} + +impl Zeroize for G1Point { + fn zeroize(&mut self) { + self.ge.zeroize() + } +} + #[cfg(test)] mod tests { use pairing_plus::bls12_381::{G1Uncompressed, G1}; @@ -557,155 +443,7 @@ mod tests { use pairing_plus::{CurveProjective, SubgroupCheck}; use sha2::Sha256; - use super::G1Point; - use crate::arithmetic::traits::*; - use crate::elliptic::curves::bls12_381::g1::{FE, GE}; - use crate::elliptic::curves::traits::ECPoint; - use crate::elliptic::curves::traits::ECScalar; - use crate::BigInt; - - #[test] - fn test_serdes_pk() { - let pk = GE::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); - - let pk = GE::base_point2(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); - } - - #[test] - fn bincode_pk() { - let pk = GE::generator(); - let bin = bincode::serialize(&pk).unwrap(); - let decoded: G1Point = bincode::deserialize(bin.as_slice()).unwrap(); - assert_eq!(decoded, pk); - } - - #[test] - #[should_panic] - #[allow(clippy::op_ref)] // Enables type inference. - fn test_serdes_bad_pk() { - let pk = GE::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - // we make sure that the string encodes invalid point: - let s: String = s.replace("30", "20"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - let eight = ECScalar::from(&BigInt::from(8)); - assert_eq!(des_pk, pk * &eight); - } - - #[test] - fn test_from_mpz() { - let rand_scalar: FE = ECScalar::new_random(); - let rand_bn = rand_scalar.to_big_int(); - let rand_scalar2: FE = ECScalar::from(&rand_bn); - assert_eq!(rand_scalar, rand_scalar2); - } - - #[test] - fn test_minus_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let a_minus_b_fe: FE = a.sub(&b.get_element()); - let base: GE = ECPoint::generator(); - - let point_ab1 = base * a_minus_b_fe; - let point_a = base * a; - let point_b = base * b; - let point_ab2 = point_a.sub_point(&point_b.get_element()); - println!( - "point ab1: {:?}", - point_ab1.bytes_compressed_to_big_int().to_hex() - ); - println!( - "point ab2: {:?}", - point_ab2.bytes_compressed_to_big_int().to_hex() - ); - - assert_eq!(point_ab1, point_ab2); - } - - #[test] - fn test_add_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let a_plus_b_fe = a + b; - let base: GE = ECPoint::generator(); - let point_ab1 = base * a_plus_b_fe; - let point_a = base * a; - let point_b = base * b; - let point_ab2 = point_a.add_point(&point_b.get_element()); - - assert_eq!(point_ab1, point_ab2); - } - - #[test] - fn test_add_scalar() { - let a: FE = ECScalar::new_random(); - let zero: FE = FE::zero(); - let a_plus_zero: FE = a + zero; - - assert_eq!(a_plus_zero, a); - } - - #[test] - fn test_mul_scalar() { - let a = [ - 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 10, 10, 10, - ]; - - let a_bn = BigInt::from_bytes(&a[..]); - let a_fe: FE = ECScalar::from(&a_bn); - - let five = BigInt::from(5); - let five_fe: FE = ECScalar::from(&five); - println!("five_fe: {:?}", five_fe.clone()); - let five_a_bn = BigInt::mod_mul(&a_bn, &five, &FE::q()); - let five_a_fe = five_fe * a_fe; - let five_a_fe_2: FE = ECScalar::from(&five_a_bn); - - assert_eq!(five_a_fe, five_a_fe_2); - } - - #[test] - fn test_mul_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let a_mul_b_fe = a * b; - let base: GE = ECPoint::generator(); - let point_ab1 = base * a_mul_b_fe; - let point_a = base * a; - let point_ab2 = point_a.scalar_mul(&b.get_element()); - - assert_eq!(point_ab1, point_ab2); - } - - #[test] - fn test_invert() { - let a: FE = ECScalar::new_random(); - - let a_bn = a.to_big_int(); - - let a_inv = a.invert(); - let a_inv_bn_1 = BigInt::mod_inv(&a_bn, &FE::q()).unwrap(); - let a_inv_bn_2 = a_inv.to_big_int(); - - assert_eq!(a_inv_bn_1, a_inv_bn_2); - } - - #[test] - fn test_scalar_mul_multiply_by_1() { - let g: GE = ECPoint::generator(); - - let fe: FE = ECScalar::from(&BigInt::from(1)); - let b_tag = g * fe; - assert_eq!(b_tag, g); - } + use super::{ECPoint, GE1}; #[test] fn base_point2_nothing_up_my_sleeve() { @@ -721,7 +459,7 @@ mod tests { println!("Uncompressed base_point2: {:?}", point_uncompressed); // Check that ECPoint::base_point2() returns generated point - let base_point2: GE = ECPoint::base_point2(); + let base_point2: &GE1 = ECPoint::base_point2(); assert_eq!(point, base_point2.ge); } } diff --git a/src/elliptic/curves/bls12_381/mod.rs b/src/elliptic/curves/bls12_381/mod.rs index b410c7f3..42e86a1c 100644 --- a/src/elliptic/curves/bls12_381/mod.rs +++ b/src/elliptic/curves/bls12_381/mod.rs @@ -1,84 +1,86 @@ pub mod g1; -pub mod g2; +// pub mod g2; -use crate::elliptic::curves::bls12_381::g1::GE as GE1; -use crate::elliptic::curves::bls12_381::g2::GE as GE2; -use crate::elliptic::curves::traits::ECPoint; +pub use self::g1::Bls12_381_1; -use ff_zeroize::Field; -use pairing_plus::bls12_381::{Bls12, Fq12}; -use pairing_plus::{CurveAffine, Engine}; +// use crate::elliptic::curves::bls12_381::g1::GE as GE1; +// use crate::elliptic::curves::bls12_381::g2::GE as GE2; +// use crate::elliptic::curves::traits::ECPoint; +// +// use ff_zeroize::Field; +// use pairing_plus::bls12_381::{Bls12, Fq12}; +// use pairing_plus::{CurveAffine, Engine}; -#[derive(Clone, Copy, PartialEq, Debug)] -pub struct Pair { - pub e: Fq12, -} - -impl Pair { - pub fn compute_pairing(g1_ge: &GE1, g2_ge: &GE2) -> Self { - Pair { - e: g1_ge.get_element().pairing_with(&g2_ge.get_element()), - } - } - - /// Efficiently computes product of pairings. - /// - /// Computes `e(g1,g2) * e(g3,g4)` with a single final exponentiation. - /// - /// ## Panic - /// Method panics if miller_loop of product is equal to zero. - pub fn efficient_pairing_mul(g1: &GE1, g2: &GE2, g3: &GE1, g4: &GE2) -> Self { - Pair { - e: Bls12::final_exponentiation(&Bls12::miller_loop( - [ - (&(g1.get_element().prepare()), &(g2.get_element().prepare())), - (&(g3.get_element().prepare()), &(g4.get_element().prepare())), - ] - .iter(), - )) - .unwrap(), - } - } - - pub fn add_pair(&self, other: &Pair) -> Self { - let mut res = *self; - res.e.mul_assign(&other.e); - Pair { e: res.e } - } -} - -#[cfg(test)] -mod tests { - use super::Pair; - use crate::elliptic::curves::bls12_381::g1::FE; - use crate::elliptic::curves::bls12_381::g1::GE as GE1; - use crate::elliptic::curves::bls12_381::g2::GE as GE2; - use crate::elliptic::curves::traits::ECPoint; - use crate::elliptic::curves::traits::ECScalar; - - #[test] - fn powers_of_g1_and_g2() { - let a: GE1 = ECPoint::generator(); - let b: GE2 = ECPoint::generator(); - let scalar_factor: FE = ECScalar::new_random(); - let res_mul_a = a.scalar_mul(&scalar_factor.get_element()); - let res_mul_b = b.scalar_mul(&scalar_factor.get_element()); - let res_a_power = Pair::compute_pairing(&res_mul_a, &b); - let res_b_power = Pair::compute_pairing(&a, &res_mul_b); - assert_eq!(res_a_power, res_b_power); - } - - // e(P,Q)e(P,R) = e(P, Q+ R) - #[test] - fn pairing() { - let p: GE1 = ECPoint::generator(); - let q: GE2 = ECPoint::generator(); - let r: GE2 = ECPoint::base_point2(); - let q_plus_r = q + r; - let e_p_q = Pair::compute_pairing(&p, &q); - let e_p_r = Pair::compute_pairing(&p, &r); - let e_p_q_r = Pair::compute_pairing(&p, &q_plus_r); - let e_p_q_add_e_p_r = e_p_q.add_pair(&e_p_r); - assert_eq!(e_p_q_add_e_p_r, e_p_q_r); - } -} +// #[derive(Clone, Copy, PartialEq, Debug)] +// pub struct Pair { +// pub e: Fq12, +// } +// +// impl Pair { +// pub fn compute_pairing(g1_ge: &GE1, g2_ge: &GE2) -> Self { +// Pair { +// e: g1_ge.get_element().pairing_with(&g2_ge.get_element()), +// } +// } +// +// /// Efficiently computes product of pairings. +// /// +// /// Computes `e(g1,g2) * e(g3,g4)` with a single final exponentiation. +// /// +// /// ## Panic +// /// Method panics if miller_loop of product is equal to zero. +// pub fn efficient_pairing_mul(g1: &GE1, g2: &GE2, g3: &GE1, g4: &GE2) -> Self { +// Pair { +// e: Bls12::final_exponentiation(&Bls12::miller_loop( +// [ +// (&(g1.get_element().prepare()), &(g2.get_element().prepare())), +// (&(g3.get_element().prepare()), &(g4.get_element().prepare())), +// ] +// .iter(), +// )) +// .unwrap(), +// } +// } +// +// pub fn add_pair(&self, other: &Pair) -> Self { +// let mut res = *self; +// res.e.mul_assign(&other.e); +// Pair { e: res.e } +// } +// } +// +// #[cfg(test)] +// mod tests { +// use super::Pair; +// use crate::elliptic::curves::bls12_381::g1::FE; +// use crate::elliptic::curves::bls12_381::g1::GE as GE1; +// use crate::elliptic::curves::bls12_381::g2::GE as GE2; +// use crate::elliptic::curves::traits::ECPoint; +// use crate::elliptic::curves::traits::ECScalar; +// +// #[test] +// fn powers_of_g1_and_g2() { +// let a: GE1 = ECPoint::generator(); +// let b: GE2 = ECPoint::generator(); +// let scalar_factor: FE = ECScalar::new_random(); +// let res_mul_a = a.scalar_mul(&scalar_factor.get_element()); +// let res_mul_b = b.scalar_mul(&scalar_factor.get_element()); +// let res_a_power = Pair::compute_pairing(&res_mul_a, &b); +// let res_b_power = Pair::compute_pairing(&a, &res_mul_b); +// assert_eq!(res_a_power, res_b_power); +// } +// +// // e(P,Q)e(P,R) = e(P, Q+ R) +// #[test] +// fn pairing() { +// let p: GE1 = ECPoint::generator(); +// let q: GE2 = ECPoint::generator(); +// let r: GE2 = ECPoint::base_point2(); +// let q_plus_r = q + r; +// let e_p_q = Pair::compute_pairing(&p, &q); +// let e_p_r = Pair::compute_pairing(&p, &r); +// let e_p_q_r = Pair::compute_pairing(&p, &q_plus_r); +// let e_p_q_add_e_p_r = e_p_q.add_pair(&e_p_r); +// assert_eq!(e_p_q_add_e_p_r, e_p_q_r); +// } +// } diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index e1a29eea..765fdaf1 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -1,4 +1,4 @@ -// pub mod bls12_381; +pub mod bls12_381; pub mod curve_ristretto; pub mod ed25519; pub mod p256; @@ -10,7 +10,8 @@ mod traits; mod wrappers; pub use self::{ - curve_ristretto::Ristretto, ed25519::Ed25519, p256::Secp256r1, secp256_k1::Secp256k1, + bls12_381::Bls12_381_1, curve_ristretto::Ristretto, ed25519::Ed25519, p256::Secp256r1, + secp256_k1::Secp256k1, }; pub use self::{ traits::{Curve, ECPoint, ECScalar, PointCoords}, diff --git a/src/lib.rs b/src/lib.rs index 6635e297..330a51c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,6 +54,11 @@ macro_rules! test_for_all_curves { fn [<$fn _ristretto>]() { $fn::() } + #[test] + $($attrs)* + fn [<$fn _bls12_381>]() { + $fn::() + } // #[test] // $($attrs)* // fn [<$fn _bls12_381>]() { From f389d72614e6677f72e4b60623af355d6d8c829b Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 15 Jul 2021 23:47:13 +0300 Subject: [PATCH 58/93] Default implementation for ECPoint::is_zero method --- src/elliptic/curves/traits.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 0beac311..4f1cb5a7 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -126,7 +126,9 @@ pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug + 'static { fn zero() -> Self; /// Returns `true` if point is a neutral element - fn is_zero(&self) -> bool; + fn is_zero(&self) -> bool { + self == &Self::zero() + } /// Curve generator /// From 8be8d7f1be48cbd665f57055ba12a044b7a561af Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 15 Jul 2021 23:47:31 +0300 Subject: [PATCH 59/93] Add tests, fix ed25519 negation --- src/elliptic/curves/ed25519.rs | 2 +- src/elliptic/curves/test.rs | 153 +++++++++++++++++++++++++++------ 2 files changed, 130 insertions(+), 25 deletions(-) diff --git a/src/elliptic/curves/ed25519.rs b/src/elliptic/curves/ed25519.rs index f59415df..e478d170 100644 --- a/src/elliptic/curves/ed25519.rs +++ b/src/elliptic/curves/ed25519.rs @@ -201,7 +201,7 @@ impl ECScalar for Ed25519Scalar { fn neg(&self) -> Self { Ed25519Scalar { purpose: "neg", - fe: Self::from_bigint(&BigInt::mod_add( + fe: Self::from_bigint(&BigInt::mod_sub( &Self::zero().to_bigint(), &self.to_bigint(), Self::group_order(), diff --git a/src/elliptic/curves/test.rs b/src/elliptic/curves/test.rs index a83b091c..010ce2b7 100644 --- a/src/elliptic/curves/test.rs +++ b/src/elliptic/curves/test.rs @@ -9,6 +9,15 @@ use crate::test_for_all_curves; use super::traits::*; +fn random_nonzero_scalar() -> S { + loop { + let s = S::random(); + if !s.is_zero() { + break s; + } + } +} + test_for_all_curves!(valid_zero_point); fn valid_zero_point() { let zero = E::Scalar::zero(); @@ -19,7 +28,7 @@ fn valid_zero_point() { test_for_all_curves!(zero_point_arithmetic); fn zero_point_arithmetic() { let zero_point = E::Point::zero(); - let point = E::Point::generator().scalar_mul(&E::Scalar::random()); + let point = E::Point::generator().scalar_mul(&random_nonzero_scalar()); assert_eq!(zero_point.add_point(&point), point, "O + P = P"); assert_eq!(point.add_point(&zero_point), point, "P + O = P"); @@ -30,7 +39,7 @@ fn zero_point_arithmetic() { let zero_scalar = E::Scalar::zero(); assert!(point.scalar_mul(&zero_scalar).is_zero(), "P * 0 = O"); - let scalar = E::Scalar::random(); + let scalar = random_nonzero_scalar(); assert!(zero_point.scalar_mul(&scalar).is_zero(), "O * s = O") } @@ -46,7 +55,7 @@ fn scalar_modulo_curve_order() { test_for_all_curves!(zero_scalar_arithmetic); fn zero_scalar_arithmetic() { - let s = E::Scalar::random(); + let s: E::Scalar = random_nonzero_scalar(); let z = E::Scalar::zero(); assert!(s.mul(&z).is_zero()); assert!(z.mul(&s).is_zero()); @@ -56,7 +65,7 @@ fn zero_scalar_arithmetic() { test_for_all_curves!(point_addition_multiplication); fn point_addition_multiplication() { - let point = E::Point::generator().scalar_mul(&E::Scalar::random()); + let point = E::Point::generator().scalar_mul(&random_nonzero_scalar()); assert!(!point.is_zero(), "G * s != O"); let addition = iter::successors(Some(point.clone()), |p| Some(p.add_point(&point))) @@ -71,7 +80,7 @@ fn point_addition_multiplication() { test_for_all_curves!(serialize_deserialize); fn serialize_deserialize() { - let point = ::generator().scalar_mul(&E::Scalar::random()); + let point = ::generator().scalar_mul(&random_nonzero_scalar()); let bytes = point .serialize(true) .expect("point has coordinates => must be serializable"); @@ -124,23 +133,33 @@ fn scalar_behaves_the_same_as_bigint() { } else { let n_was = n.clone(); let k = BigInt::sample_below(&(q * 2)); + let k_s: E::Scalar = ECScalar::from_bigint(&k); let op; match operation { 1 => { op = "+"; n = BigInt::mod_add(&n, &k, q); - s.add_assign(&E::Scalar::from_bigint(&k)); + + let s_no_assign = s.add(&k_s); + s.add_assign(&k_s); + assert_eq!(s, s_no_assign); } 2 => { op = "*"; n = BigInt::mod_mul(&n, &k, q); - s.mul_assign(&E::Scalar::from_bigint(&k)); + + let s_no_assign = s.mul(&k_s); + s.mul_assign(&k_s); + assert_eq!(s, s_no_assign); } 3 => { op = "-"; n = BigInt::mod_sub(&n, &k, q); - s.sub_assign(&E::Scalar::from_bigint(&k)); + + let s_no_assign = s.sub(&k_s); + s.sub_assign(&k_s); + assert_eq!(s, s_no_assign); } _ => unreachable!(), } @@ -161,20 +180,19 @@ fn scalar_behaves_the_same_as_bigint() { test_for_all_curves!(from_coords_produces_the_same_point); fn from_coords_produces_the_same_point() { - let s: E::Scalar = ECScalar::random(); + let s: E::Scalar = random_nonzero_scalar(); println!("s={}", s.to_bigint()); let p: E::Point = ::generator().scalar_mul(&s); - if let Some(coords) = p.coords() { - let p2: E::Point = ECPoint::from_coords(&coords.x, &coords.y).unwrap(); - assert_eq!(p, p2); - } + let coords = p.coords().unwrap(); + let p2: E::Point = ECPoint::from_coords(&coords.x, &coords.y).unwrap(); + assert_eq!(p, p2); } test_for_all_curves!(test_point_addition); fn test_point_addition() { - let a: E::Scalar = ECScalar::random(); - let b: E::Scalar = ECScalar::random(); + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); let aG: E::Point = ECPoint::generator_mul(&a); let bG: E::Point = ECPoint::generator_mul(&b); @@ -184,10 +202,28 @@ fn test_point_addition() { assert_eq!(aG.add_point(&bG), a_plus_b_G); } +test_for_all_curves!(test_point_assign_addition); +fn test_point_assign_addition() { + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); + + let aG: E::Point = ECPoint::generator_mul(&a); + let bG: E::Point = ECPoint::generator_mul(&b); + + let a_plus_b_G_1 = aG.add_point(&bG); + let a_plus_b_G_2 = { + let mut aG = aG; + aG.add_point_assign(&bG); + aG + }; + + assert_eq!(a_plus_b_G_1, a_plus_b_G_2); +} + test_for_all_curves!(test_point_subtraction); fn test_point_subtraction() { - let a: E::Scalar = ECScalar::random(); - let b: E::Scalar = ECScalar::random(); + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); let aG: E::Point = ECPoint::generator_mul(&a); let bG: E::Point = ECPoint::generator_mul(&b); @@ -197,10 +233,28 @@ fn test_point_subtraction() { assert_eq!(aG.sub_point(&bG), a_minus_b_G); } +test_for_all_curves!(test_point_assign_subtraction); +fn test_point_assign_subtraction() { + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); + + let aG: E::Point = ECPoint::generator_mul(&a); + let bG: E::Point = ECPoint::generator_mul(&b); + + let a_minus_b_G_1: E::Point = aG.sub_point(&bG); + let a_minus_b_G_2 = { + let mut aG = aG; + aG.sub_point_assign(&bG); + aG + }; + + assert_eq!(a_minus_b_G_1, a_minus_b_G_2); +} + test_for_all_curves!(test_multiplication_point_at_scalar); fn test_multiplication_point_at_scalar() { - let a: E::Scalar = ECScalar::random(); - let b: E::Scalar = ECScalar::random(); + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); let aG: E::Point = ECPoint::generator_mul(&a); let abG: E::Point = aG.scalar_mul(&b); @@ -210,13 +264,26 @@ fn test_multiplication_point_at_scalar() { assert_eq!(abG, a_mul_b_G); } +test_for_all_curves!(test_assign_multiplication_point_at_scalar); +fn test_assign_multiplication_point_at_scalar() { + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); + + let aG: E::Point = ECPoint::generator_mul(&a); + + let abG_1: E::Point = aG.scalar_mul(&b); + let abG_2 = { + let mut aG = aG; + aG.scalar_mul_assign(&b); + aG + }; + + assert_eq!(abG_1, abG_2); +} + test_for_all_curves!(scalar_invert); fn scalar_invert() { - let n: E::Scalar = ECScalar::random(); - if n.is_zero() { - // Scalar is zero => restart the test - scalar_invert::() - } + let n: E::Scalar = random_nonzero_scalar(); let n_inv = n.invert().unwrap(); assert_eq!(n.mul(&n_inv), ECScalar::from_bigint(&BigInt::one())) @@ -228,3 +295,41 @@ fn zero_scalar_invert() { let n_inv = n.invert(); assert!(n_inv.is_none()) } + +test_for_all_curves!(point_negation); +fn point_negation() { + let p1 = ::generator_mul(&random_nonzero_scalar()); + let p2 = p1.neg_point(); + assert_eq!(p1.add_point(&p2), ECPoint::zero()); +} + +test_for_all_curves!(point_assign_negation); +fn point_assign_negation() { + let p = ::generator_mul(&random_nonzero_scalar()); + let p_neg_1 = p.neg_point(); + let p_neg_2 = { + let mut p = p; + p.neg_point_assign(); + p + }; + assert_eq!(p_neg_1, p_neg_2); +} + +test_for_all_curves!(scalar_negation); +fn scalar_negation() { + let s1: E::Scalar = random_nonzero_scalar(); + let s2 = s1.neg(); + assert_eq!(s1.add(&s2), E::Scalar::zero()); +} + +test_for_all_curves!(scalar_assign_negation); +fn scalar_assign_negation() { + let s: E::Scalar = random_nonzero_scalar(); + let s_neg_1 = s.neg(); + let s_neg_2 = { + let mut s = s; + s.neg_assign(); + s + }; + assert_eq!(s_neg_1, s_neg_2); +} From 14dbcb7f76dbd55617e318815b1fb6c885c8c4e2 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 15 Jul 2021 23:47:54 +0300 Subject: [PATCH 60/93] Uncomment proofs of base_point2 picked randomly --- src/elliptic/curves/curve_ristretto.rs | 4 +- src/elliptic/curves/p256.rs | 54 ++++++++++++++----------- src/elliptic/curves/secp256_k1.rs | 55 +++++++++++++++----------- 3 files changed, 62 insertions(+), 51 deletions(-) diff --git a/src/elliptic/curves/curve_ristretto.rs b/src/elliptic/curves/curve_ristretto.rs index 3729f986..8a880abb 100644 --- a/src/elliptic/curves/curve_ristretto.rs +++ b/src/elliptic/curves/curve_ristretto.rs @@ -34,9 +34,7 @@ lazy_static::lazy_static! { static ref BASE_POINT2: RistrettoPoint = { let g = RistrettoPoint::generator(); - let hash = Sha256::new() - .chain(g.serialize(true).unwrap()) - .result(); + let hash = Sha256::digest(&g.serialize(true).unwrap()); RistrettoPoint { purpose: "base_point2", ge: RistrettoPoint::deserialize(&hash).unwrap().ge, diff --git a/src/elliptic/curves/p256.rs b/src/elliptic/curves/p256.rs index 5cb9094e..a89d07ba 100644 --- a/src/elliptic/curves/p256.rs +++ b/src/elliptic/curves/p256.rs @@ -363,28 +363,34 @@ impl PartialEq for Secp256r1Point { #[cfg(test)] mod tests { - // #[test] - // fn test_base_point2() { - // /* Show that base_point2() is returning a point of unknown discrete logarithm. - // It is done by using SHA256 repeatedly as a pseudo-random function, with the generator - // as the initial input, until receiving a valid Secp256r1 point. */ - // - // let base_point2 = Secp256r1Point::base_point2(); - // - // let g = Secp256r1Point::generator(); - // let mut hash = HSha256::create_hash(&[&g.bytes_compressed_to_big_int()]); - // hash = HSha256::create_hash(&[&hash]); - // - // assert_eq!(hash, base_point2.x_coor().unwrap(),); - // - // // check that base_point2 is indeed on the curve (from_coor() will fail otherwise) - // assert_eq!( - // Secp256r1Point::from_coor( - // &base_point2.x_coor().unwrap(), - // &base_point2.y_coor().unwrap() - // ) - // .get_element(), - // base_point2.get_element() - // ); - // } + use sha2::{Digest, Sha256}; + + use crate::arithmetic::*; + + use super::{ECPoint, GE}; + + #[test] + fn test_base_point2() { + /* Show that base_point2() is returning a point of unknown discrete logarithm. + It is done by using SHA256 repeatedly as a pseudo-random function, with the generator + as the initial input, until receiving a valid Secp256r1 point. */ + + let base_point2 = GE::base_point2(); + + let g = GE::generator(); + let hash = Sha256::digest(&g.serialize(true).unwrap()); + let hash = Sha256::digest(&hash); + + assert_eq!(BigInt::from_bytes(&hash), base_point2.x_coord().unwrap()); + + // check that base_point2 is indeed on the curve (from_coords() will fail otherwise) + assert_eq!( + &GE::from_coords( + &base_point2.x_coord().unwrap(), + &base_point2.y_coord().unwrap() + ) + .unwrap(), + base_point2 + ); + } } diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 1ac85360..71c63425 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -592,28 +592,35 @@ impl Zeroize for Secp256k1Point { #[cfg(test)] mod test { - // #[test] - // fn test_base_point2() { - // /* Show that base_point2() is returning a point of unknown discrete logarithm. - // It is done by using SHA256 repeatedly as a pseudo-random function, with the generator - // as the initial input, until receiving a valid Secp256k1 point. */ - // - // let base_point2 = GE::base_point2(); - // - // let g = GE::generator(); - // let mut hash = HSha256::create_hash(&[&g.bytes_compressed_to_big_int()]); - // hash = HSha256::create_hash(&[&hash]); - // hash = HSha256::create_hash(&[&hash]); - // - // assert_eq!(hash, base_point2.x_coor().unwrap(),); - // - // // check that base_point2 is indeed on the curve (from_coor() will fail otherwise) - // assert_eq!( - // Secp256k1Point::from_coor( - // &base_point2.x_coor().unwrap(), - // &base_point2.y_coor().unwrap() - // ), - // base_point2 - // ); - // } + use sha2::{Digest, Sha256}; + + use crate::arithmetic::*; + + use super::{ECPoint, GE}; + + #[test] + fn test_base_point2() { + /* Show that base_point2() is returning a point of unknown discrete logarithm. + It is done by using SHA256 repeatedly as a pseudo-random function, with the generator + as the initial input, until receiving a valid Secp256k1 point. */ + + let base_point2 = GE::base_point2(); + + let g = GE::generator(); + let hash = Sha256::digest(&g.serialize(true).unwrap()); + let hash = Sha256::digest(&hash); + let hash = Sha256::digest(&hash); + + assert_eq!(BigInt::from_bytes(&hash), base_point2.x_coord().unwrap()); + + // check that base_point2 is indeed on the curve (from_coor() will fail otherwise) + assert_eq!( + &GE::from_coords( + &base_point2.x_coord().unwrap(), + &base_point2.y_coord().unwrap() + ) + .unwrap(), + base_point2 + ); + } } From f0177da0391ca56aea2da6c82486cdd650e906f3 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 16 Jul 2021 13:28:35 +0300 Subject: [PATCH 61/93] Add the second BLS curve --- src/elliptic/curves/bls12_381/g1.rs | 169 +---- src/elliptic/curves/bls12_381/g2.rs | 792 ++++++------------------ src/elliptic/curves/bls12_381/mod.rs | 5 +- src/elliptic/curves/bls12_381/scalar.rs | 169 +++++ src/elliptic/curves/mod.rs | 5 +- src/lib.rs | 12 +- 6 files changed, 376 insertions(+), 776 deletions(-) create mode 100644 src/elliptic/curves/bls12_381/scalar.rs diff --git a/src/elliptic/curves/bls12_381/g1.rs b/src/elliptic/curves/bls12_381/g1.rs index dc5afe8c..74ef03bd 100644 --- a/src/elliptic/curves/bls12_381/g1.rs +++ b/src/elliptic/curves/bls12_381/g1.rs @@ -6,37 +6,23 @@ */ use std::fmt; -use std::io::Cursor; -use ff_zeroize::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; -use pairing_plus::bls12_381::{Fr, G1Compressed, G1Uncompressed, G1}; +use ff_zeroize::PrimeField; +use pairing_plus::bls12_381::{G1Compressed, G1Uncompressed, G1}; use pairing_plus::hash_to_curve::HashToCurve; use pairing_plus::hash_to_field::ExpandMsgXmd; use pairing_plus::{CurveAffine, CurveProjective, Engine}; use pairing_plus::{EncodedPoint, SubgroupCheck}; -use rand::rngs::OsRng; use sha2::Sha256; -use zeroize::{Zeroize, Zeroizing}; +use zeroize::Zeroize; use crate::arithmetic::traits::*; use crate::elliptic::curves::traits::*; use crate::BigInt; -lazy_static::lazy_static! { - static ref GROUP_ORDER: BigInt = { - let q_u64: [u64; 4] = [ - 0xffffffff00000001, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ]; - let to_bn = q_u64.iter().rev().fold(BigInt::zero(), |acc, x| { - let element_bn = BigInt::from(*x); - element_bn + (acc << 64) - }); - to_bn - }; +use super::scalar::FieldScalar; +lazy_static::lazy_static! { static ref GENERATOR: G1Point = G1Point { purpose: "generator", ge: PK::one(), @@ -63,164 +49,25 @@ lazy_static::lazy_static! { pub const SECRET_KEY_SIZE: usize = 32; pub const COMPRESSED_SIZE: usize = 48; -pub type SK = ::Fr; pub type PK = ::G1Affine; #[derive(Debug, PartialEq, Clone)] pub enum Bls12_381_1 {} -#[derive(Clone)] -pub struct FieldScalar { - purpose: &'static str, - fe: Zeroizing, -} #[derive(Clone, Copy)] pub struct G1Point { purpose: &'static str, ge: PK, } pub type GE1 = G1Point; -pub type FE1 = FieldScalar; impl Curve for Bls12_381_1 { type Point = GE1; - type Scalar = FE1; + type Scalar = FieldScalar; const CURVE_NAME: &'static str = "bls12_381_1"; } -impl ECScalar for FieldScalar { - type Underlying = SK; - - fn random() -> FieldScalar { - FieldScalar { - purpose: "random", - fe: Zeroizing::new(Field::random(&mut OsRng)), - } - } - - fn zero() -> FieldScalar { - FieldScalar { - purpose: "zero", - fe: Zeroizing::new(Field::zero()), - } - } - - fn from_bigint(n: &BigInt) -> FieldScalar { - let n_mod = BigInt::modulus(n, &FE1::group_order()); - let n_mod = n_mod.to_bytes(); - let mut bytes_array = [0u8; SECRET_KEY_SIZE]; - if n_mod.len() < SECRET_KEY_SIZE { - bytes_array[SECRET_KEY_SIZE - n_mod.len()..].copy_from_slice(&n_mod) - } else { - bytes_array.copy_from_slice(&n_mod[..SECRET_KEY_SIZE]) - } - - let mut repr = SK::default().into_repr(); - repr.read_be(Cursor::new(&bytes_array[..])).unwrap(); - FieldScalar { - purpose: "from_bigint", - fe: Fr::from_repr(repr).unwrap().into(), - } - } - - fn to_bigint(&self) -> BigInt { - let repr = self.fe.into_repr(); - let mut bytes = vec![]; - repr.write_be(&mut bytes).unwrap(); - BigInt::from_bytes(&bytes) - } - - fn add(&self, other: &Self) -> FieldScalar { - let mut result = self.fe.clone(); - result.add_assign(&other.fe); - FieldScalar { - purpose: "add", - fe: result, - } - } - - fn mul(&self, other: &Self) -> FieldScalar { - let mut result = self.fe.clone(); - result.mul_assign(&other.fe); - FieldScalar { - purpose: "mul", - fe: result, - } - } - - fn sub(&self, other: &Self) -> FieldScalar { - let mut result = self.fe.clone(); - result.sub_assign(&other.fe); - FieldScalar { - purpose: "sub", - fe: result, - } - } - - fn neg(&self) -> FieldScalar { - let mut result = self.fe.clone(); - result.negate(); - FieldScalar { - purpose: "neg", - fe: result, - } - } - - fn invert(&self) -> Option { - Some(FieldScalar { - purpose: "invert", - fe: Zeroizing::new(self.fe.inverse()?), - }) - } - - fn add_assign(&mut self, other: &Self) { - self.fe.add_assign(&other.fe); - } - fn mul_assign(&mut self, other: &Self) { - self.fe.mul_assign(&other.fe); - } - fn sub_assign(&mut self, other: &Self) { - self.fe.sub_assign(&other.fe); - } - fn neg_assign(&mut self) { - self.fe.negate(); - } - - fn group_order() -> &'static BigInt { - &GROUP_ORDER - } - - fn underlying_ref(&self) -> &Self::Underlying { - &self.fe - } - fn underlying_mut(&mut self) -> &mut Self::Underlying { - &mut self.fe - } - fn from_underlying(fe: Self::Underlying) -> FieldScalar { - FieldScalar { - purpose: "from_underlying", - fe: fe.into(), - } - } -} - -impl fmt::Debug for FieldScalar { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Point {{ purpose: {:?}, bytes: {:?} }}", - self.purpose, self.fe, - ) - } -} - -impl PartialEq for FieldScalar { - fn eq(&self, other: &FieldScalar) -> bool { - self.fe == other.fe - } -} - impl ECPoint for G1Point { type Scalar = FieldScalar; type Underlying = PK; @@ -342,7 +189,7 @@ impl ECPoint for G1Point { } fn scalar_mul(&self, scalar: &Self::Scalar) -> G1Point { - let result = self.ge.mul(scalar.fe.into_repr()); + let result = self.ge.mul(scalar.underlying_ref().into_repr()); G1Point { purpose: "scalar_mul", ge: result.into_affine(), @@ -418,7 +265,7 @@ impl fmt::Debug for G1Point { self.purpose, self.serialize(false) .map(hex::encode) - .unwrap_or_else(|| "infinity".to_string()) + .unwrap_or_else(|| "infinity".to_string()), ) } } diff --git a/src/elliptic/curves/bls12_381/g2.rs b/src/elliptic/curves/bls12_381/g2.rs index 0aa7b8ea..48ff8204 100644 --- a/src/elliptic/curves/bls12_381/g2.rs +++ b/src/elliptic/curves/bls12_381/g2.rs @@ -5,295 +5,31 @@ License MIT: */ -pub const SECRET_KEY_SIZE: usize = 32; -pub const COMPRESSED_SIZE: usize = 96; - use std::fmt; -use std::fmt::Debug; -use std::ops::{Add, Mul, Neg}; -use std::str; -use ff_zeroize::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; -use pairing_plus::bls12_381::Fr; +use ff_zeroize::{PrimeField, ScalarEngine}; use pairing_plus::bls12_381::G2Compressed; use pairing_plus::bls12_381::G2Uncompressed; use pairing_plus::bls12_381::G2; use pairing_plus::hash_to_curve::HashToCurve; use pairing_plus::hash_to_field::ExpandMsgXmd; -use pairing_plus::serdes::SerDes; -use pairing_plus::EncodedPoint; use pairing_plus::{CurveAffine, CurveProjective, Engine}; +use pairing_plus::{EncodedPoint, SubgroupCheck}; use sha2::Sha256; - -use serde::de::{self, Error, MapAccess, SeqAccess, Visitor}; -use serde::ser::SerializeStruct; -use serde::ser::{Serialize, Serializer}; -use serde::{Deserialize, Deserializer}; - -pub type SK = ::Fr; -pub type PK = ::G2Affine; - -use crate::arithmetic::traits::*; -use crate::BigInt; -use crate::ErrorKey::{self}; - -use std::ptr; -use std::sync::atomic; use zeroize::Zeroize; -use crate::elliptic::curves::traits::ECPoint; -use crate::elliptic::curves::traits::ECScalar; -#[cfg(feature = "merkle")] -use crypto::digest::Digest; -#[cfg(feature = "merkle")] -use crypto::sha3::Sha3; -#[cfg(feature = "merkle")] -use merkle::Hashable; -use std::io::Cursor; - -#[derive(Clone, Copy)] -pub struct FieldScalar { - purpose: &'static str, - fe: SK, -} -#[derive(Clone, Copy)] -pub struct G2Point { - purpose: &'static str, - ge: PK, -} -pub type GE = G2Point; -pub type FE = FieldScalar; - -impl Zeroize for FieldScalar { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, FE::zero()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); - } -} - -impl ECScalar for FieldScalar { - type SecretKey = SK; - - fn new_random() -> FieldScalar { - let rnd_bn = BigInt::sample_below(&FE::q()); - ECScalar::from(&rnd_bn) - } - - fn zero() -> FieldScalar { - FieldScalar { - purpose: "zero", - fe: SK::default(), - } - } - - fn get_element(&self) -> SK { - self.fe - } - fn set_element(&mut self, element: SK) { - self.fe = element - } - - fn from(n: &BigInt) -> FieldScalar { - let n_mod = BigInt::modulus(n, &FE::q()); - let mut v = BigInt::to_bytes(&n_mod); - let mut bytes_array: [u8; SECRET_KEY_SIZE]; - if v.len() < SECRET_KEY_SIZE { - let mut template = vec![0; SECRET_KEY_SIZE - v.len()]; - template.extend_from_slice(&v); - v = template; - } - bytes_array = [0; SECRET_KEY_SIZE]; - let bytes = &v[..SECRET_KEY_SIZE]; - bytes_array.copy_from_slice(&bytes); - - // bytes_array.reverse(); +use crate::arithmetic::*; +use crate::elliptic::curves::traits::*; - let mut repr = SK::default().into_repr(); - repr.read_be(Cursor::new(&bytes_array[..])).unwrap(); - FieldScalar { - purpose: "from_big_int", - fe: Fr::from_repr(repr).unwrap(), - } - } +use super::scalar::FieldScalar; - fn to_big_int(&self) -> BigInt { - let tmp = self.fe.into_repr(); - let scalar_u64 = tmp.as_ref(); +lazy_static::lazy_static! { + static ref GENERATOR: G2Point = G2Point { + purpose: "generator", + ge: PK::one(), + }; - let to_bn = scalar_u64.iter().rev().fold(BigInt::zero(), |acc, x| { - let element_bn = BigInt::from(*x); - element_bn + (acc << 64) - }); - to_bn - } - - fn q() -> BigInt { - let q_u64: [u64; 4] = [ - 0xffffffff00000001, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ]; - let to_bn = q_u64.iter().rev().fold(BigInt::zero(), |acc, x| { - let element_bn = BigInt::from(*x); - element_bn + (acc << 64) - }); - to_bn - } - - fn add(&self, other: &SK) -> FieldScalar { - let mut add_fe = FieldScalar { - purpose: "other add", - fe: *other, - }; - add_fe.fe.add_assign(&self.fe); - FieldScalar { - purpose: "add", - fe: add_fe.fe, - } - } - - fn mul(&self, other: &SK) -> FieldScalar { - let mut mul_fe = FieldScalar { - purpose: "other mul", - fe: *other, - }; - mul_fe.fe.mul_assign(&self.fe); - FieldScalar { - purpose: "mul", - fe: mul_fe.fe, - } - } - - fn sub(&self, other: &SK) -> FieldScalar { - let mut other_neg = *other; - other_neg.negate(); - let sub_fe = FieldScalar { - purpose: "other sub", - fe: other_neg, - }; - self.add(&sub_fe.get_element()) - } - - fn invert(&self) -> FieldScalar { - let sc = self.fe; - let inv_sc = sc.inverse().unwrap(); //TODO - FieldScalar { - purpose: "inverse", - fe: inv_sc, - } - } -} - -impl Debug for FieldScalar { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Point {{ purpose: {:?}, bytes: {:?} }}", - self.purpose, self.fe, - ) - } -} - -impl PartialEq for FieldScalar { - fn eq(&self, other: &FieldScalar) -> bool { - self.get_element() == other.get_element() - } -} - -impl Mul for FieldScalar { - type Output = FieldScalar; - fn mul(self, other: FieldScalar) -> FieldScalar { - (&self).mul(&other.get_element()) - } -} - -impl<'o> Mul<&'o FieldScalar> for FieldScalar { - type Output = FieldScalar; - fn mul(self, other: &'o FieldScalar) -> FieldScalar { - (&self).mul(&other.get_element()) - } -} - -impl Add for FieldScalar { - type Output = FieldScalar; - fn add(self, other: FieldScalar) -> FieldScalar { - (&self).add(&other.get_element()) - } -} - -impl<'o> Add<&'o FieldScalar> for FieldScalar { - type Output = FieldScalar; - fn add(self, other: &'o FieldScalar) -> FieldScalar { - (&self).add(&other.get_element()) - } -} - -impl Serialize for FieldScalar { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_big_int().to_hex()) - } -} - -impl<'de> Deserialize<'de> for FieldScalar { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(BLS12_381ScalarVisitor) - } -} - -struct BLS12_381ScalarVisitor; - -impl<'de> Visitor<'de> for BLS12_381ScalarVisitor { - type Value = FieldScalar; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("bls12_381") - } - - fn visit_str(self, s: &str) -> Result { - let v = BigInt::from_hex(s).map_err(E::custom)?; - Ok(ECScalar::from(&v)) - } -} - -impl Debug for G2Point { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Point {{ purpose: {:?}, bytes: {:?} }}", - self.purpose, - self.bytes_compressed_to_big_int().to_hex() - ) - } -} - -impl PartialEq for G2Point { - fn eq(&self, other: &G2Point) -> bool { - self.get_element() == other.get_element() - } -} - -impl Zeroize for G2Point { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(self, GE::generator()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); - } -} - -impl ECPoint for G2Point { - type SecretKey = SK; - type PublicKey = PK; - type Scalar = FieldScalar; - - fn base_point2() -> G2Point { + static ref BASE_POINT2: G2Point = { const BASE_POINT2: [u8; 192] = [ 0, 204, 165, 72, 21, 96, 36, 119, 117, 242, 58, 55, 105, 140, 136, 76, 180, 140, 92, 212, 55, 3, 146, 72, 120, 181, 37, 205, 165, 221, 144, 86, 57, 124, 16, 19, 160, 215, @@ -311,234 +47,206 @@ impl ECPoint for G2Point { let mut point = G2Uncompressed::empty(); point.as_mut().copy_from_slice(&BASE_POINT2); G2Point { - purpose: "base_ge2", + purpose: "base_point2", ge: point.into_affine().expect("invalid base_point"), } - } + }; +} - fn generator() -> G2Point { - G2Point { - purpose: "base_fe", - ge: PK::one(), - } - } +pub const SECRET_KEY_SIZE: usize = 32; +pub const COMPRESSED_SIZE: usize = 96; - fn get_element(&self) -> PK { - self.ge - } +pub type SK = ::Fr; +pub type PK = ::G2Affine; - fn x_coor(&self) -> Option { - let tmp = G2Uncompressed::from_affine(self.ge); - let bytes = tmp.as_ref(); - let x_coor = &bytes[0..COMPRESSED_SIZE]; - let bn = BigInt::from_bytes(x_coor); - Some(bn) - } +#[derive(PartialEq, Debug, Clone)] +pub enum Bls12_381_2 {} - fn y_coor(&self) -> Option { - let tmp = G2Uncompressed::from_affine(self.ge); - let bytes = tmp.as_ref(); - let y_coor = &bytes[COMPRESSED_SIZE..2 * COMPRESSED_SIZE]; - let bn = BigInt::from_bytes(y_coor); - Some(bn) - } +#[derive(Clone, Copy)] +pub struct G2Point { + purpose: &'static str, + ge: PK, +} - fn bytes_compressed_to_big_int(&self) -> BigInt { - let tmp = G2Compressed::from_affine(self.ge); - let bytes = tmp.as_ref(); - BigInt::from_bytes(bytes) - } +pub type GE2 = G2Point; - fn from_bytes(bytes: &[u8]) -> Result { - let mut bytes_array_comp = [0u8; COMPRESSED_SIZE]; - match bytes.len() { - 0..=COMPRESSED_SIZE => { - (&mut bytes_array_comp[COMPRESSED_SIZE - bytes.len()..]).copy_from_slice(bytes); - } - _ => { - bytes_array_comp.copy_from_slice(&bytes[..COMPRESSED_SIZE]); - } - } +impl Curve for Bls12_381_2 { + type Point = GE2; + type Scalar = FieldScalar; - let g2_comp = G2::deserialize(&mut bytes_array_comp[..].as_ref(), true).unwrap(); + const CURVE_NAME: &'static str = "bls12_381_1"; +} - let pk = G2Point { - purpose: "from_bytes", - ge: g2_comp.into_affine(), //TODO: handle error - }; +impl ECPoint for G2Point { + type Scalar = FieldScalar; + type Underlying = PK; - Ok(pk) + fn zero() -> G2Point { + G2Point { + purpose: "zero", + ge: PK::zero(), + } } - // in this case the opposite of from_bytes: takes compressed pk to COMPRESSED_SIZE bytes. - fn pk_to_key_slice(&self) -> Vec { - let mut compressed_vec = vec![]; - PK::serialize(&self.ge, &mut compressed_vec, true) - .expect("serializing into vec should always succeed"); - compressed_vec + fn is_zero(&self) -> bool { + self.ge.is_zero() } - fn scalar_mul(&self, fe: &SK) -> G2Point { - let mut ge_proj: G2 = self.ge.into(); - ge_proj.mul_assign(fe.into_repr()); - G2Point { - purpose: "scalar_point_mul", - ge: ge_proj.into_affine(), - } + fn generator() -> &'static G2Point { + &GENERATOR } - fn add_point(&self, other: &PK) -> G2Point { - let mut ge_proj: G2 = self.ge.into(); - ge_proj.add_assign_mixed(other); - G2Point { - purpose: "combine", - ge: ge_proj.into_affine(), - } + fn base_point2() -> &'static G2Point { + &BASE_POINT2 } - fn sub_point(&self, other: &PK) -> G2Point { - let mut ge_proj: G2 = self.ge.into(); - ge_proj.sub_assign_mixed(other); - G2Point { - purpose: "sub", - ge: ge_proj.into_affine(), + fn from_coords(x: &BigInt, y: &BigInt) -> Result { + let x = x.to_bytes(); + let y = y.to_bytes(); + + let mut uncompressed = [0u8; COMPRESSED_SIZE * 2]; + if x.len() <= COMPRESSED_SIZE { + uncompressed[COMPRESSED_SIZE - x.len()..COMPRESSED_SIZE].copy_from_slice(&x) + } else { + return Err(NotOnCurve); } - } - fn from_coor(_x: &BigInt, _y: &BigInt) -> G2Point { - // TODO - unimplemented!(); - } -} + if y.len() <= COMPRESSED_SIZE { + uncompressed[2 * COMPRESSED_SIZE - y.len()..2 * COMPRESSED_SIZE].copy_from_slice(&y) + } else { + return Err(NotOnCurve); + } -impl From for G2Point { - fn from(point: PK) -> Self { - G2Point { - purpose: "from_point", - ge: point, + let mut point = G2Uncompressed::empty(); + point.as_mut().copy_from_slice(&uncompressed); + + Ok(G2Point { + purpose: "from_coords", + ge: point.into_affine().map_err(|_| NotOnCurve)?, + }) + } + + fn x_coord(&self) -> Option { + if self.is_zero() { + None + } else { + let uncompressed = G2Uncompressed::from_affine(self.ge); + let x_coord = &uncompressed.as_ref()[0..COMPRESSED_SIZE]; + let bn = BigInt::from_bytes(x_coord); + Some(bn) } } -} -impl Mul for G2Point { - type Output = G2Point; - fn mul(self, other: FieldScalar) -> G2Point { - self.scalar_mul(&other.get_element()) + fn y_coord(&self) -> Option { + if self.is_zero() { + None + } else { + let uncompressed = G2Uncompressed::from_affine(self.ge); + let y_coord = &uncompressed.as_ref()[COMPRESSED_SIZE..COMPRESSED_SIZE * 2]; + let bn = BigInt::from_bytes(y_coord); + Some(bn) + } } -} -impl<'o> Mul<&'o FieldScalar> for G2Point { - type Output = G2Point; - fn mul(self, other: &'o FieldScalar) -> G2Point { - self.scalar_mul(&other.get_element()) + fn coords(&self) -> Option { + if self.is_zero() { + None + } else { + let uncompressed = G2Uncompressed::from_affine(self.ge); + let x = &uncompressed.as_ref()[0..COMPRESSED_SIZE]; + let y = &uncompressed.as_ref()[COMPRESSED_SIZE..COMPRESSED_SIZE * 2]; + let x = BigInt::from_bytes(x); + let y = BigInt::from_bytes(y); + Some(PointCoords { x, y }) + } } -} -impl<'o> Mul<&'o FieldScalar> for &'o G2Point { - type Output = G2Point; - fn mul(self, other: &'o FieldScalar) -> G2Point { - self.scalar_mul(&other.get_element()) + fn serialize(&self, compressed: bool) -> Option> { + if self.is_zero() { + None + } else if compressed { + Some(G2Compressed::from_affine(self.ge).as_ref().to_vec()) + } else { + Some(G2Uncompressed::from_affine(self.ge).as_ref().to_vec()) + } } -} -impl Add for G2Point { - type Output = G2Point; - fn add(self, other: G2Point) -> G2Point { - self.add_point(&other.get_element()) + fn deserialize(bytes: &[u8]) -> Result { + if bytes.len() == COMPRESSED_SIZE { + let mut compressed = G2Compressed::empty(); + compressed.as_mut().copy_from_slice(bytes); + Ok(G2Point { + purpose: "deserialize", + ge: compressed.into_affine().map_err(|_| DeserializationError)?, + }) + } else if bytes.len() == 2 * COMPRESSED_SIZE { + let mut uncompressed = G2Uncompressed::empty(); + uncompressed.as_mut().copy_from_slice(bytes); + Ok(G2Point { + purpose: "deserialize", + ge: uncompressed + .into_affine() + .map_err(|_| DeserializationError)?, + }) + } else { + Err(DeserializationError) + } } -} -impl<'o> Add<&'o G2Point> for G2Point { - type Output = G2Point; - fn add(self, other: &'o G2Point) -> G2Point { - self.add_point(&other.get_element()) + fn check_point_order_equals_group_order(&self) -> bool { + !self.is_zero() && self.ge.in_subgroup() } -} -impl<'o> Add<&'o G2Point> for &'o G2Point { - type Output = G2Point; - fn add(self, other: &'o G2Point) -> G2Point { - self.add_point(&other.get_element()) + fn scalar_mul(&self, scalar: &Self::Scalar) -> G2Point { + let result = self.ge.mul(scalar.underlying_ref().into_repr()); + G2Point { + purpose: "scalar_mul", + ge: result.into_affine(), + } } -} -impl Neg for G2Point { - type Output = Self; - fn neg(mut self) -> Self { - self.ge.negate(); - self.purpose = "negated"; - self + fn add_point(&self, other: &Self) -> G2Point { + let mut result = G2::from(self.ge); + result.add_assign_mixed(&other.ge); + G2Point { + purpose: "add_point", + ge: result.into_affine(), + } } -} -#[cfg(feature = "merkle")] -impl Hashable for G2Point { - fn update_context(&self, context: &mut Sha3) { - let bytes: Vec = self.pk_to_key_slice(); - context.input(&bytes[..]); + fn sub_point(&self, other: &Self) -> G2Point { + let mut result = G2::from(self.ge); + result.sub_assign_mixed(&other.ge); + G2Point { + purpose: "sub_point", + ge: result.into_affine(), + } } -} -impl Serialize for G2Point { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let bytes = self.pk_to_key_slice(); - let bytes_as_bn = BigInt::from_bytes(&bytes[..]); - let mut state = serializer.serialize_struct("Bls12381G2Point", 1)?; - state.serialize_field("bytes_str", &bytes_as_bn.to_hex())?; - state.end() + fn neg_point(&self) -> Self { + let mut result = self.ge; + result.negate(); + G2Point { + purpose: "neg", + ge: result, + } } -} -impl<'de> Deserialize<'de> for G2Point { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - const FIELDS: &[&str] = &["bytes_str"]; - deserializer.deserialize_struct("Bls12381G2Point", FIELDS, Bls12381G2PointVisitor) + fn neg_point_assign(&mut self) { + self.ge.negate(); } -} -struct Bls12381G2PointVisitor; - -impl<'de> Visitor<'de> for Bls12381G2PointVisitor { - type Value = G2Point; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Bls12381G2Point") + fn underlying_ref(&self) -> &Self::Underlying { + &self.ge } - - fn visit_seq(self, mut seq: V) -> Result - where - V: SeqAccess<'de>, - { - let bytes_str = seq - .next_element()? - .ok_or_else(|| V::Error::invalid_length(0, &"a single element"))?; - let bytes_bn = BigInt::from_hex(bytes_str).map_err(V::Error::custom)?; - let bytes = BigInt::to_bytes(&bytes_bn); - G2Point::from_bytes(&bytes[..]).map_err(|_| V::Error::custom("failed to parse g2 point")) + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.ge } - - fn visit_map>(self, mut map: E) -> Result { - let mut bytes_str: String = "".to_string(); - - while let Some(key) = map.next_key::<&'de str>()? { - let v = map.next_value::<&'de str>()?; - match key { - "bytes_str" => { - bytes_str = String::from(v); - } - _ => return Err(E::Error::unknown_field(key, &["bytes_str"])), - } + fn from_underlying(ge: Self::Underlying) -> G2Point { + G2Point { + purpose: "from_underlying", + ge, } - let bytes_bn = BigInt::from_hex(&bytes_str).map_err(E::Error::custom)?; - let bytes = BigInt::to_bytes(&bytes_bn); - - G2Point::from_bytes(&bytes[..]).map_err(|_| E::Error::custom("failed to parse g2 point")) } } @@ -558,162 +266,34 @@ impl G2Point { } } -#[cfg(test)] -mod tests { - use pairing_plus::bls12_381::{G2Uncompressed, G2}; - use pairing_plus::hash_to_curve::HashToCurve; - use pairing_plus::hash_to_field::ExpandMsgXmd; - use pairing_plus::{CurveProjective, SubgroupCheck}; - use sha2::Sha256; - - use super::G2Point; - use crate::arithmetic::traits::*; - use crate::elliptic::curves::bls12_381::g2::{FE, GE}; - use crate::elliptic::curves::traits::ECPoint; - use crate::elliptic::curves::traits::ECScalar; - use crate::BigInt; - - #[test] - fn test_serdes_pk() { - let pk = GE::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); - - let pk = GE::base_point2(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - assert_eq!(des_pk, pk); - } - - #[test] - fn bincode_pk() { - let pk = GE::generator(); - let bin = bincode::serialize(&pk).unwrap(); - let decoded: G2Point = bincode::deserialize(bin.as_slice()).unwrap(); - assert_eq!(decoded, pk); - } - - #[test] - #[should_panic] - #[allow(clippy::op_ref)] // Enables type inference. - fn test_serdes_bad_pk() { - let pk = GE::generator(); - let s = serde_json::to_string(&pk).expect("Failed in serialization"); - // we make sure that the string encodes invalid point: - let s: String = s.replace("30", "20"); - let des_pk: GE = serde_json::from_str(&s).expect("Failed in deserialization"); - let eight = ECScalar::from(&BigInt::from(8)); - assert_eq!(des_pk, pk * &eight); - } - - #[test] - fn test_from_mpz() { - let rand_scalar: FE = ECScalar::new_random(); - let rand_bn = rand_scalar.to_big_int(); - let rand_scalar2: FE = ECScalar::from(&rand_bn); - assert_eq!(rand_scalar, rand_scalar2); - } - - #[test] - fn test_minus_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let a_minus_b_fe: FE = a.sub(&b.get_element()); - let base: GE = ECPoint::generator(); - - let point_ab1 = base * a_minus_b_fe; - let point_a = base * a; - let point_b = base * b; - let point_ab2 = point_a.sub_point(&point_b.get_element()); - println!( - "point ab1: {:?}", - point_ab1.bytes_compressed_to_big_int().to_hex() - ); - println!( - "point ab2: {:?}", - point_ab2.bytes_compressed_to_big_int().to_hex() - ); - - assert_eq!(point_ab1, point_ab2); - } - - #[test] - fn test_add_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let a_plus_b_fe = a + b; - let base: GE = ECPoint::generator(); - let point_ab1 = base * a_plus_b_fe; - let point_a = base * a; - let point_b = base * b; - let point_ab2 = point_a.add_point(&point_b.get_element()); - - assert_eq!(point_ab1, point_ab2); - } - - #[test] - fn test_add_scalar() { - let a: FE = ECScalar::new_random(); - let zero: FE = FE::zero(); - let a_plus_zero: FE = a + zero; - - assert_eq!(a_plus_zero, a); - } - - #[test] - fn test_mul_scalar() { - let a = [ - 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 10, 10, 10, - ]; - - let a_bn = BigInt::from_bytes(&a[..]); - let a_fe: FE = ECScalar::from(&a_bn); - - let five = BigInt::from(5); - let five_fe: FE = ECScalar::from(&five); - println!("five_fe: {:?}", five_fe.clone()); - let five_a_bn = BigInt::mod_mul(&a_bn, &five, &FE::q()); - let five_a_fe = five_fe * a_fe; - let five_a_fe_2: FE = ECScalar::from(&five_a_bn); - - assert_eq!(five_a_fe, five_a_fe_2); +impl fmt::Debug for G2Point { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "Point {{ purpose: {:?}, uncompressed: {:?} }}", + self.purpose, + self.serialize(false) + .map(hex::encode) + .unwrap_or_else(|| "infinity".to_string()), + ) } +} - #[test] - fn test_mul_point() { - let a: FE = ECScalar::new_random(); - let b: FE = ECScalar::new_random(); - let a_mul_b_fe = a * b; - let base: GE = ECPoint::generator(); - let point_ab1 = base * a_mul_b_fe; - let point_a = base * a; - let point_ab2 = point_a.scalar_mul(&b.get_element()); - - assert_eq!(point_ab1, point_ab2); +impl PartialEq for G2Point { + fn eq(&self, other: &G2Point) -> bool { + self.ge == other.ge } +} - #[test] - fn test_invert() { - let a: FE = ECScalar::new_random(); - - let a_bn = a.to_big_int(); - - let a_inv = a.invert(); - let a_inv_bn_1 = BigInt::mod_inv(&a_bn, &FE::q()).unwrap(); - let a_inv_bn_2 = a_inv.to_big_int(); - - assert_eq!(a_inv_bn_1, a_inv_bn_2); +impl Zeroize for G2Point { + fn zeroize(&mut self) { + self.ge.zeroize() } - #[test] - fn test_scalar_mul_multiply_by_1() { - let g: GE = ECPoint::generator(); +} - let fe: FE = ECScalar::from(&BigInt::from(1)); - let b_tag = g * fe; - assert_eq!(b_tag, g); - } +#[cfg(test)] +mod tests { + use super::*; #[test] fn base_point2_nothing_up_my_sleeve() { @@ -729,7 +309,7 @@ mod tests { println!("Uncompressed base_point2: {:?}", point_uncompressed); // Check that ECPoint::base_point2() returns generated point - let base_point2: GE = ECPoint::base_point2(); + let base_point2: &G2Point = ECPoint::base_point2(); assert_eq!(point, base_point2.ge); } } diff --git a/src/elliptic/curves/bls12_381/mod.rs b/src/elliptic/curves/bls12_381/mod.rs index 42e86a1c..e384abf1 100644 --- a/src/elliptic/curves/bls12_381/mod.rs +++ b/src/elliptic/curves/bls12_381/mod.rs @@ -1,7 +1,8 @@ pub mod g1; -// pub mod g2; +pub mod g2; +pub mod scalar; -pub use self::g1::Bls12_381_1; +pub use self::{g1::Bls12_381_1, g2::Bls12_381_2}; // use crate::elliptic::curves::bls12_381::g1::GE as GE1; // use crate::elliptic::curves::bls12_381::g2::GE as GE2; diff --git a/src/elliptic/curves/bls12_381/scalar.rs b/src/elliptic/curves/bls12_381/scalar.rs new file mode 100644 index 00000000..6392a893 --- /dev/null +++ b/src/elliptic/curves/bls12_381/scalar.rs @@ -0,0 +1,169 @@ +use std::fmt; +use std::io::Cursor; + +use ff_zeroize::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; +use pairing_plus::bls12_381::Fr; +use rand::rngs::OsRng; +use zeroize::Zeroizing; + +use crate::arithmetic::*; +use crate::elliptic::curves::traits::*; + +lazy_static::lazy_static! { + static ref GROUP_ORDER: BigInt = { + let q_u64: [u64; 4] = [ + 0xffffffff00000001, + 0x53bda402fffe5bfe, + 0x3339d80809a1d805, + 0x73eda753299d7d48, + ]; + let to_bn = q_u64.iter().rev().fold(BigInt::zero(), |acc, x| { + let element_bn = BigInt::from(*x); + element_bn + (acc << 64) + }); + to_bn + }; +} + +const SECRET_KEY_SIZE: usize = 32; + +pub type FE = FieldScalar; +pub type SK = ::Fr; + +#[derive(Clone)] +pub struct FieldScalar { + purpose: &'static str, + fe: Zeroizing, +} + +impl ECScalar for FieldScalar { + type Underlying = SK; + + fn random() -> FieldScalar { + FieldScalar { + purpose: "random", + fe: Zeroizing::new(Field::random(&mut OsRng)), + } + } + + fn zero() -> FieldScalar { + FieldScalar { + purpose: "zero", + fe: Zeroizing::new(Field::zero()), + } + } + + fn from_bigint(n: &BigInt) -> FieldScalar { + let n_mod = BigInt::modulus(n, &FieldScalar::group_order()); + let n_mod = n_mod.to_bytes(); + let mut bytes_array = [0u8; SECRET_KEY_SIZE]; + if n_mod.len() < SECRET_KEY_SIZE { + bytes_array[SECRET_KEY_SIZE - n_mod.len()..].copy_from_slice(&n_mod) + } else { + bytes_array.copy_from_slice(&n_mod[..SECRET_KEY_SIZE]) + } + + let mut repr = SK::default().into_repr(); + repr.read_be(Cursor::new(&bytes_array[..])).unwrap(); + FieldScalar { + purpose: "from_bigint", + fe: Fr::from_repr(repr).unwrap().into(), + } + } + + fn to_bigint(&self) -> BigInt { + let repr = self.fe.into_repr(); + let mut bytes = vec![]; + repr.write_be(&mut bytes).unwrap(); + BigInt::from_bytes(&bytes) + } + + fn add(&self, other: &Self) -> FieldScalar { + let mut result = self.fe.clone(); + result.add_assign(&other.fe); + FieldScalar { + purpose: "add", + fe: result, + } + } + + fn mul(&self, other: &Self) -> FieldScalar { + let mut result = self.fe.clone(); + result.mul_assign(&other.fe); + FieldScalar { + purpose: "mul", + fe: result, + } + } + + fn sub(&self, other: &Self) -> FieldScalar { + let mut result = self.fe.clone(); + result.sub_assign(&other.fe); + FieldScalar { + purpose: "sub", + fe: result, + } + } + + fn neg(&self) -> FieldScalar { + let mut result = self.fe.clone(); + result.negate(); + FieldScalar { + purpose: "neg", + fe: result, + } + } + + fn invert(&self) -> Option { + Some(FieldScalar { + purpose: "invert", + fe: Zeroizing::new(self.fe.inverse()?), + }) + } + + fn add_assign(&mut self, other: &Self) { + self.fe.add_assign(&other.fe); + } + fn mul_assign(&mut self, other: &Self) { + self.fe.mul_assign(&other.fe); + } + fn sub_assign(&mut self, other: &Self) { + self.fe.sub_assign(&other.fe); + } + fn neg_assign(&mut self) { + self.fe.negate(); + } + + fn group_order() -> &'static BigInt { + &GROUP_ORDER + } + + fn underlying_ref(&self) -> &Self::Underlying { + &self.fe + } + fn underlying_mut(&mut self) -> &mut Self::Underlying { + &mut self.fe + } + fn from_underlying(fe: Self::Underlying) -> FieldScalar { + FieldScalar { + purpose: "from_underlying", + fe: fe.into(), + } + } +} + +impl fmt::Debug for FieldScalar { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "Point {{ purpose: {:?}, bytes: {:?} }}", + self.purpose, self.fe, + ) + } +} + +impl PartialEq for FieldScalar { + fn eq(&self, other: &FieldScalar) -> bool { + self.fe == other.fe + } +} diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index 765fdaf1..cb114345 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -10,7 +10,10 @@ mod traits; mod wrappers; pub use self::{ - bls12_381::Bls12_381_1, curve_ristretto::Ristretto, ed25519::Ed25519, p256::Secp256r1, + bls12_381::{Bls12_381_1, Bls12_381_2}, + curve_ristretto::Ristretto, + ed25519::Ed25519, + p256::Secp256r1, secp256_k1::Secp256k1, }; pub use self::{ diff --git a/src/lib.rs b/src/lib.rs index 330a51c0..ef59c4f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,14 +56,14 @@ macro_rules! test_for_all_curves { } #[test] $($attrs)* - fn [<$fn _bls12_381>]() { + fn [<$fn _bls12_381_1>]() { $fn::() } - // #[test] - // $($attrs)* - // fn [<$fn _bls12_381>]() { - // $fn::() - // } + #[test] + $($attrs)* + fn [<$fn _bls12_381_2>]() { + $fn::() + } } }; } From 10e6e2daf4c1d0e8aae48941ef0f077344dc0015 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 16 Jul 2021 15:11:11 +0300 Subject: [PATCH 62/93] Write doc --- src/elliptic/curves/mod.rs | 79 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index cb114345..3bb0316e 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -1,3 +1,82 @@ +//! # General purpose elliptic curve cryptography +//! +//! Here we define generic elliptic curve cryptography and provide implementation of several curves. +//! +//! ## Usage +//! +//! Elliptic curve cryptography operates on points and scalars. We provide according structures +//! [Point\](Point), [Scalar\](Scalar) (and [PointZ\](PointZ), [ScalarZ\](ScalarZ) +//! — for points and scalars that might be zero), where generic `E` stands for choice of elliptic +//! curve, e.g. [Secp256k1] (`Point`, `Scalar`, etc.). +//! +//! Various methods and traits are defined for points and scalars which basically empowers you to do +//! anything you can do in elliptic curve cryptography. +//! +//! ## Examples +//! +//! ### Public point/private scalar generation +//! ```rust +//! use curv::elliptic::curves::{Point, Scalar, Secp256k1}; +//! +//! // Samples a random nonzero scalar (mod group order) +//! let secret = Scalar::::random(); +//! // Multiplies generator at secret, retrieving a public point +//! let public = Point::generator() * secret; +//! ``` +//! +//! ### Diffie-Hellman +//! +//! Function below is a final step of the Diffie-Hellman key exchange protocol when both parties +//! have exchanged their ephemeral public keys. Giving it here just for an example, the `curv` library +//! includes implementation of this protocol (see [dh_key_exchange], or its more involved version: +//! [dh_key_exchange_variant_with_pok_comm]). +//! +//! [dh_key_exchange]: crate::cryptographic_primitives::twoparty::dh_key_exchange +//! [dh_key_exchange_variant_with_pok_comm]: crate::cryptographic_primitives::twoparty::dh_key_exchange_variant_with_pok_comm +//! +//! ```rust +//! use curv::elliptic::curves::{Point, Scalar, Secp256k1}; +//! +//! fn diffie_hellman( +//! my_secret: &Scalar, +//! counterparty_point: &Point +//! ) -> Point { +//! my_secret * counterparty_point +//! } +//! ``` +//! +//! You may have noticed that this function lacks of subgroup check (whether counterparty +//! point has order=group_order), and is vulnerable to [small subgroup attack][subgroup-attack]. +//! Actually, **it isn't**! Any `Point` instance is guaranteed to have large prime order, +//! so you can be sure that subgroup check was performed. See [guarantees section] to learn more. +//! +//! [subgroup-attack]: http://safecurves.cr.yp.to/twist.html +//! [Guarantees section]: Point#guarantees +//! +//! The function above performs DH only on secp256k1 curve, which is disappointing as the code will +//! look the same for any curve. Luckily we can make it generic over choice of curve: +//! +//! ```rust +//! use curv::elliptic::curves::{Curve, Point, Scalar}; +//! +//! fn diffie_hellman( +//! my_secret: &Scalar, +//! counterparty_point: &Point +//! ) -> Point { +//! my_secret * counterparty_point +//! } +//! ``` +//! +//! `Point` (for generic `E: Curve`) implements many traits you might need (e.g. Serialize, PartialEq, +//! Debug, etc.) without specifying additional bounds. The same apllies to other structures (PointZ, Scalar, ...). +//! +//! ## Implementing your own curve +//! +//! Downstream crates can define their own curves just by implementing [Curve], [ECPoint], [ECScalar] +//! traits, no additional work is required. Note that these traits are intended not to be used directly. +//! Point, Scalar structures wrap ECPoint / ECScalar implementation, and provide a lot of convenient +//! methods, implement arithmetic traits, etc. + pub mod bls12_381; pub mod curve_ristretto; pub mod ed25519; From 6725dfa8aa634f731293347cbc3b86b268fd855e Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 16 Jul 2021 15:45:55 +0300 Subject: [PATCH 63/93] Add pairing, update docs --- src/elliptic/curves/bls12_381/mod.rs | 85 +-------------------- src/elliptic/curves/bls12_381/pairing.rs | 97 ++++++++++++++++++++++++ src/elliptic/curves/mod.rs | 8 +- src/elliptic/curves/traits.rs | 1 + 4 files changed, 104 insertions(+), 87 deletions(-) create mode 100644 src/elliptic/curves/bls12_381/pairing.rs diff --git a/src/elliptic/curves/bls12_381/mod.rs b/src/elliptic/curves/bls12_381/mod.rs index e384abf1..ecb3164a 100644 --- a/src/elliptic/curves/bls12_381/mod.rs +++ b/src/elliptic/curves/bls12_381/mod.rs @@ -1,87 +1,6 @@ pub mod g1; pub mod g2; +mod pairing; pub mod scalar; -pub use self::{g1::Bls12_381_1, g2::Bls12_381_2}; - -// use crate::elliptic::curves::bls12_381::g1::GE as GE1; -// use crate::elliptic::curves::bls12_381::g2::GE as GE2; -// use crate::elliptic::curves::traits::ECPoint; -// -// use ff_zeroize::Field; -// use pairing_plus::bls12_381::{Bls12, Fq12}; -// use pairing_plus::{CurveAffine, Engine}; - -// #[derive(Clone, Copy, PartialEq, Debug)] -// pub struct Pair { -// pub e: Fq12, -// } -// -// impl Pair { -// pub fn compute_pairing(g1_ge: &GE1, g2_ge: &GE2) -> Self { -// Pair { -// e: g1_ge.get_element().pairing_with(&g2_ge.get_element()), -// } -// } -// -// /// Efficiently computes product of pairings. -// /// -// /// Computes `e(g1,g2) * e(g3,g4)` with a single final exponentiation. -// /// -// /// ## Panic -// /// Method panics if miller_loop of product is equal to zero. -// pub fn efficient_pairing_mul(g1: &GE1, g2: &GE2, g3: &GE1, g4: &GE2) -> Self { -// Pair { -// e: Bls12::final_exponentiation(&Bls12::miller_loop( -// [ -// (&(g1.get_element().prepare()), &(g2.get_element().prepare())), -// (&(g3.get_element().prepare()), &(g4.get_element().prepare())), -// ] -// .iter(), -// )) -// .unwrap(), -// } -// } -// -// pub fn add_pair(&self, other: &Pair) -> Self { -// let mut res = *self; -// res.e.mul_assign(&other.e); -// Pair { e: res.e } -// } -// } -// -// #[cfg(test)] -// mod tests { -// use super::Pair; -// use crate::elliptic::curves::bls12_381::g1::FE; -// use crate::elliptic::curves::bls12_381::g1::GE as GE1; -// use crate::elliptic::curves::bls12_381::g2::GE as GE2; -// use crate::elliptic::curves::traits::ECPoint; -// use crate::elliptic::curves::traits::ECScalar; -// -// #[test] -// fn powers_of_g1_and_g2() { -// let a: GE1 = ECPoint::generator(); -// let b: GE2 = ECPoint::generator(); -// let scalar_factor: FE = ECScalar::new_random(); -// let res_mul_a = a.scalar_mul(&scalar_factor.get_element()); -// let res_mul_b = b.scalar_mul(&scalar_factor.get_element()); -// let res_a_power = Pair::compute_pairing(&res_mul_a, &b); -// let res_b_power = Pair::compute_pairing(&a, &res_mul_b); -// assert_eq!(res_a_power, res_b_power); -// } -// -// // e(P,Q)e(P,R) = e(P, Q+ R) -// #[test] -// fn pairing() { -// let p: GE1 = ECPoint::generator(); -// let q: GE2 = ECPoint::generator(); -// let r: GE2 = ECPoint::base_point2(); -// let q_plus_r = q + r; -// let e_p_q = Pair::compute_pairing(&p, &q); -// let e_p_r = Pair::compute_pairing(&p, &r); -// let e_p_q_r = Pair::compute_pairing(&p, &q_plus_r); -// let e_p_q_add_e_p_r = e_p_q.add_pair(&e_p_r); -// assert_eq!(e_p_q_add_e_p_r, e_p_q_r); -// } -// } +pub use self::{g1::Bls12_381_1, g2::Bls12_381_2, pairing::Pair}; diff --git a/src/elliptic/curves/bls12_381/pairing.rs b/src/elliptic/curves/bls12_381/pairing.rs new file mode 100644 index 00000000..3c9d85c0 --- /dev/null +++ b/src/elliptic/curves/bls12_381/pairing.rs @@ -0,0 +1,97 @@ +use ff_zeroize::Field; +use pairing_plus::bls12_381::{Bls12, Fq12}; +use pairing_plus::{CurveAffine, Engine}; + +use crate::elliptic::curves::bls12_381::{Bls12_381_1, Bls12_381_2}; +use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::Point; + +/// Bilinear pairing function +/// +/// _Note_: pairing function support is experimental and subject to change +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct Pair { + pub e: Fq12, +} + +impl Pair { + /// Computes pairing `e(p1, p2)` + pub fn compute_pairing(p1: &Point, p2: &Point) -> Self { + Pair { + e: p1 + .as_raw() + .underlying_ref() + .pairing_with(p2.as_raw().underlying_ref()), + } + } + + /// Efficiently computes product of pairings + /// + /// Computes `e(g1,g2) * e(g3,g4)` with a single final exponentiation. + /// + /// ## Panic + /// Method panics if miller_loop of product is equal to zero. + pub fn efficient_pairing_mul( + p1: &Point, + p2: &Point, + p3: &Point, + p4: &Point, + ) -> Self { + Pair { + e: Bls12::final_exponentiation(&Bls12::miller_loop( + [ + ( + &(p1.as_raw().underlying_ref().prepare()), + &(p2.as_raw().underlying_ref().prepare()), + ), + ( + &(p3.as_raw().underlying_ref().prepare()), + &(p4.as_raw().underlying_ref().prepare()), + ), + ] + .iter(), + )) + .unwrap(), + } + } + + pub fn add_pair(&self, other: &Pair) -> Self { + let mut res = *self; + res.e.mul_assign(&other.e); + Pair { e: res.e } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::elliptic::curves::Scalar; + + #[test] + fn powers_of_g1_and_g2() { + let a = Point::::generator().to_point(); + let b = Point::::generator().to_point(); + let scalar_factor_1 = Scalar::::random(); + let scalar_factor_2 = + Scalar::::from_raw(scalar_factor_1.as_raw().clone()).unwrap(); + let res_mul_a = &a * &scalar_factor_1; + let res_mul_b = &b * &scalar_factor_2; + let res_a_power = Pair::compute_pairing(&res_mul_a, &b); + let res_b_power = Pair::compute_pairing(&a, &res_mul_b); + assert_eq!(res_a_power, res_b_power); + } + + // e(P,Q)e(P,R) = e(P, Q+ R) + #[test] + fn pairing() { + let p = Point::::generator().to_point(); + let q = Point::::generator().to_point(); + let r = Point::::base_point2().to_point(); + let q_plus_r = (&q + &r).ensure_nonzero().unwrap(); + let e_p_q = Pair::compute_pairing(&p, &q); + let e_p_r = Pair::compute_pairing(&p, &r); + let e_p_q_r = Pair::compute_pairing(&p, &q_plus_r); + let e_p_q_add_e_p_r = e_p_q.add_pair(&e_p_r); + assert_eq!(e_p_q_add_e_p_r, e_p_q_r); + } +} diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index 3bb0316e..79d4f668 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -28,8 +28,8 @@ //! //! Function below is a final step of the Diffie-Hellman key exchange protocol when both parties //! have exchanged their ephemeral public keys. Giving it here just for an example, the `curv` library -//! includes implementation of this protocol (see [dh_key_exchange], or its more involved version: -//! [dh_key_exchange_variant_with_pok_comm]). +//! is equipped with an implementation of this protocol (see [dh_key_exchange], or its more involved +//! version: [dh_key_exchange_variant_with_pok_comm]). //! //! [dh_key_exchange]: crate::cryptographic_primitives::twoparty::dh_key_exchange //! [dh_key_exchange_variant_with_pok_comm]: crate::cryptographic_primitives::twoparty::dh_key_exchange_variant_with_pok_comm @@ -53,8 +53,8 @@ //! [subgroup-attack]: http://safecurves.cr.yp.to/twist.html //! [Guarantees section]: Point#guarantees //! -//! The function above performs DH only on secp256k1 curve, which is disappointing as the code will -//! look the same for any curve. Luckily we can make it generic over choice of curve: +//! The function above performs DH only on secp256k1 curve, which is disappointing — the code will +//! look the same for any curve. Luckily, we can make it generic over choice of curve: //! //! ```rust //! use curv::elliptic::curves::{Curve, Point, Scalar}; diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 4f1cb5a7..a7c2f98b 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -223,6 +223,7 @@ pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug + 'static { fn from_underlying(u: Self::Underlying) -> Self; } +/// Affine coordinates of a point #[derive(Serialize, Deserialize)] pub struct PointCoords { pub x: BigInt, From 38f724c2fd01734e9bf6387c92092e7dd9a179cd Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 16 Jul 2021 15:57:05 +0300 Subject: [PATCH 64/93] Rename package --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6cf14142..d00d15df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "curv" +name = "curv-kzen" version = "0.8.0-rc1" edition = "2018" authors = ["Omer Shlomovits"] @@ -8,6 +8,7 @@ description = "Curv contains an extremly simple interface to onboard new ellipti repository = "https://github.com/ZenGo-X/curv" [lib] +name = "curv" crate-type = ["lib"] [dependencies] From a5a0c5ec46389eba12c1916d72cd15d2c36d9593 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 16 Jul 2021 16:01:10 +0300 Subject: [PATCH 65/93] Update readme --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 039e0ac3..a19b7c71 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,19 @@ The library has a built in support for some useful operations/primitives such as schemes, zero knowledge proofs, and simple two party protocols such as ECDH and coin flip. The library comes with serialize/deserialize support to be used in higher level code to implement networking. +### Usage + +To use `curv` crate, add the following to your Cargo.toml: +```toml +[dependencies] +curv-kzen = "0.8" +``` + +The crate will be available under `curv` name, e.g.: +```rust +use curv::elliptic::curves::*; +``` + ### Currently Supported Elliptic Curves | Curve | low level library | curve description | @@ -44,8 +57,7 @@ You can choose any one which you prefer by specifying a feature: * **num-bigint**, Rust's pure implementation of big integer. In order to use it, put in Cargo.toml: ```toml [dependencies.curv] - git = "https://github.com/ZenGo-X/curv" - tag = "v0.6.0" + version = "0.8" default-features = false features = ["num-bigint"] ``` From 22186305be3b2830673e824f09dafb10404e5d9a Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 18 Jul 2021 01:45:30 +0300 Subject: [PATCH 66/93] Add changelog --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..ded8ef82 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +## v0.8.0-rc1 +* Elliptic curve API has been significantly changed [#120] + + In particular: ECPoint, ECScalar traits were redesigned. They remain, + but are not supposed to be used directly anymore. In replacement, + we introduce structures Point, Scalar, PointZ, ScalarZ representing + elliptic point and scalar. See curv::elliptic::curves module-level + documentation to learn more. +* Add low degree exponent interpolation proof [#119] + +[#119]: https://github.com/ZenGo-X/curv/pull/119 +[#120]: https://github.com/ZenGo-X/curv/pull/120 From 8ea5d956637c62b2b78509b6ab226f267ea94f97 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 19 Jul 2021 18:43:09 +0300 Subject: [PATCH 67/93] Merge Point&PointZ, Scalar&ScalarZ --- CHANGELOG.md | 6 +- examples/verifiable_secret_sharing.rs | 2 +- .../commitments/pedersen_commitment.rs | 12 +- .../hashing/blake2b512.rs | 30 +- src/cryptographic_primitives/hashing/ext.rs | 29 +- .../hashing/hash_sha256.rs | 17 +- .../hashing/hash_sha512.rs | 17 +- .../hashing/merkle_tree.rs | 22 +- .../hashing/traits.rs | 5 +- .../low_degree_exponent_interpolation.rs | 52 +-- .../sigma_correct_homomorphic_elgamal_enc.rs | 46 +- ..._homomorphic_elgamal_encryption_of_dlog.rs | 30 +- .../proofs/sigma_dlog.rs | 4 +- .../proofs/sigma_ec_ddh.rs | 4 +- .../proofs/sigma_valid_pedersen.rs | 36 +- .../proofs/sigma_valid_pedersen_blind.rs | 18 +- .../secret_sharing/feldman_vss.rs | 72 ++-- .../secret_sharing/polynomial.rs | 137 ++---- .../twoparty/coin_flip_optimal_rounds.rs | 12 +- .../dh_key_exchange_variant_with_pok_comm.rs | 40 +- src/elliptic/curves/bls12_381/pairing.rs | 5 +- src/elliptic/curves/mod.rs | 11 +- src/elliptic/curves/traits.rs | 12 +- src/elliptic/curves/wrappers/arithmetic.rs | 396 ++++-------------- src/elliptic/curves/wrappers/error.rs | 46 +- src/elliptic/curves/wrappers/format.rs | 80 +--- src/elliptic/curves/wrappers/generator.rs | 26 +- src/elliptic/curves/wrappers/mod.rs | 7 +- src/elliptic/curves/wrappers/point.rs | 224 +++++----- src/elliptic/curves/wrappers/point_ref.rs | 83 ++-- src/elliptic/curves/wrappers/point_z.rs | 226 ---------- src/elliptic/curves/wrappers/scalar.rs | 178 ++++---- src/elliptic/curves/wrappers/scalar_z.rs | 186 -------- 33 files changed, 626 insertions(+), 1445 deletions(-) delete mode 100644 src/elliptic/curves/wrappers/point_z.rs delete mode 100644 src/elliptic/curves/wrappers/scalar_z.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index ded8ef82..d0312c3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,9 @@ In particular: ECPoint, ECScalar traits were redesigned. They remain, but are not supposed to be used directly anymore. In replacement, - we introduce structures Point, Scalar, PointZ, ScalarZ representing - elliptic point and scalar. See curv::elliptic::curves module-level - documentation to learn more. + we introduce structures Point, Scalar representing elliptic point and + scalar. See curv::elliptic::curves module-level documentation to learn + more. * Add low degree exponent interpolation proof [#119] [#119]: https://github.com/ZenGo-X/curv/pull/119 diff --git a/examples/verifiable_secret_sharing.rs b/examples/verifiable_secret_sharing.rs index 86ced47e..29566239 100644 --- a/examples/verifiable_secret_sharing.rs +++ b/examples/verifiable_secret_sharing.rs @@ -14,7 +14,7 @@ use curv::elliptic::curves::*; pub fn secret_sharing_3_out_of_5() { use curv::cryptographic_primitives::secret_sharing::feldman_vss::VerifiableSS; - let secret = ScalarZ::random(); + let secret = Scalar::random(); let (vss_scheme, secret_shares) = VerifiableSS::::share(3, 5, &secret); diff --git a/src/cryptographic_primitives/commitments/pedersen_commitment.rs b/src/cryptographic_primitives/commitments/pedersen_commitment.rs index c44cb21e..35ce96ff 100644 --- a/src/cryptographic_primitives/commitments/pedersen_commitment.rs +++ b/src/cryptographic_primitives/commitments/pedersen_commitment.rs @@ -11,7 +11,7 @@ use super::traits::Commitment; use super::SECURITY_BITS; use crate::arithmetic::traits::*; -use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use crate::BigInt; /// compute c = mG + rH @@ -20,21 +20,21 @@ use crate::BigInt; /// pub struct PedersenCommitment(PhantomData); -impl Commitment> for PedersenCommitment { +impl Commitment> for PedersenCommitment { fn create_commitment_with_user_defined_randomness( message: &BigInt, blinding_factor: &BigInt, - ) -> PointZ { + ) -> Point { let g = Point::generator(); let h = Point::base_point2(); - let message_scalar: ScalarZ = ScalarZ::from(message); - let blinding_scalar: ScalarZ = ScalarZ::from(blinding_factor); + let message_scalar: Scalar = Scalar::from(message); + let blinding_scalar: Scalar = Scalar::from(blinding_factor); let mg = g * message_scalar; let rh = h * blinding_scalar; mg + rh } - fn create_commitment(message: &BigInt) -> (PointZ, BigInt) { + fn create_commitment(message: &BigInt) -> (Point, BigInt) { let blinding_factor = BigInt::sample(SECURITY_BITS); let com = PedersenCommitment::create_commitment_with_user_defined_randomness( message, diff --git a/src/cryptographic_primitives/hashing/blake2b512.rs b/src/cryptographic_primitives/hashing/blake2b512.rs index aac77b2d..0da5064e 100644 --- a/src/cryptographic_primitives/hashing/blake2b512.rs +++ b/src/cryptographic_primitives/hashing/blake2b512.rs @@ -7,7 +7,7 @@ use blake2b_simd::{Params, State}; use crate::arithmetic::traits::*; -use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use crate::BigInt; /// Wrapper over [blake2b_simd](blake2b_simd::State) exposing facilities to hash bigints, elliptic points, @@ -29,11 +29,6 @@ impl Blake { } pub fn chain_point(&mut self, point: &Point) -> &mut Self { - self.state.update(&point.to_bytes(false)); - self - } - - pub fn chain_pointz(&mut self, point: &PointZ) -> &mut Self { match point.to_bytes(false) { Some(bytes) => self.state.update(&bytes), None => self.state.update(b"point at infinity"), @@ -47,8 +42,7 @@ impl Blake { pub fn result_scalar(&self) -> Scalar { let n = self.result_bigint(); - let m = Scalar::::group_order() - 1; - Scalar::from_bigint(&(n.modulus(&m) + 1)).expect("scalar is guaranteed to be nonzero") + Scalar::from_bigint(&n) } #[deprecated( @@ -68,23 +62,7 @@ impl Blake { since = "0.8.0", note = "Blake API has been changed, this method is outdated" )] - pub fn create_hash_from_ge(ge_vec: &[&Point], persona: &[u8]) -> ScalarZ { - let mut digest = Params::new().hash_length(64).personal(persona).to_state(); - // let mut digest = Blake2b::with_params(64, &[], &[], persona); - - for value in ge_vec { - digest.update(&value.to_bytes(false)); - } - - let result = BigInt::from_bytes(digest.finalize().as_ref()); - ScalarZ::from(&result) - } - - #[deprecated( - since = "0.8.0", - note = "Blake API has been changed, this method is outdated" - )] - pub fn create_hash_from_ge_z(ge_vec: &[&PointZ], persona: &[u8]) -> ScalarZ { + pub fn create_hash_from_ge(ge_vec: &[&Point], persona: &[u8]) -> Scalar { let mut digest = Params::new().hash_length(64).personal(persona).to_state(); // let mut digest = Blake2b::with_params(64, &[], &[], persona); @@ -96,7 +74,7 @@ impl Blake { } let result = BigInt::from_bytes(digest.finalize().as_ref()); - ScalarZ::from(&result) + Scalar::from(&result) } } diff --git a/src/cryptographic_primitives/hashing/ext.rs b/src/cryptographic_primitives/hashing/ext.rs index 3cbe6423..751d6db6 100644 --- a/src/cryptographic_primitives/hashing/ext.rs +++ b/src/cryptographic_primitives/hashing/ext.rs @@ -3,7 +3,7 @@ use hmac::crypto_mac::MacError; use hmac::{Hmac, Mac}; use crate::arithmetic::*; -use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; /// [Digest] extension allowing to hash elliptic points, scalars, and bigints /// @@ -29,9 +29,7 @@ use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; pub trait DigestExt { fn input_bigint(&mut self, n: &BigInt); fn input_point(&mut self, point: &Point); - fn input_pointz(&mut self, point: &PointZ); fn input_scalar(&mut self, scalar: &Scalar); - fn input_scalarz(&mut self, scalar: &ScalarZ); fn chain_bigint(mut self, n: &BigInt) -> Self where @@ -47,11 +45,13 @@ pub trait DigestExt { self.input_point(point); self } - fn chain_pointz(mut self, point: &PointZ) -> Self + fn chain_points<'p, E: Curve>(mut self, points: impl IntoIterator>) -> Self where Self: Sized, { - self.input_pointz(point); + for point in points { + self.input_point(point) + } self } fn chain_scalar(mut self, scalar: &Scalar) -> Self @@ -61,11 +61,16 @@ pub trait DigestExt { self.input_scalar(scalar); self } - fn chain_scalarz(mut self, scalar: &ScalarZ) -> Self + fn chain_scalars<'s, E: Curve>( + mut self, + scalars: impl IntoIterator>, + ) -> Self where Self: Sized, { - self.input_scalarz(scalar); + for scalar in scalars { + self.input_scalar(scalar) + } self } @@ -84,10 +89,6 @@ where } fn input_point(&mut self, point: &Point) { - self.input(&point.to_bytes(false)) - } - - fn input_pointz(&mut self, point: &PointZ) { match point.to_bytes(false) { Some(bytes) => self.input(&bytes), None => self.input(b"point at infinity"), @@ -97,9 +98,6 @@ where fn input_scalar(&mut self, scalar: &Scalar) { self.input(&scalar.to_bigint().to_bytes()) } - fn input_scalarz(&mut self, scalar: &ScalarZ) { - self.input(&scalar.to_bigint().to_bytes()) - } fn result_bigint(self) -> BigInt { let result = self.result(); @@ -108,8 +106,7 @@ where fn result_scalar(self) -> Scalar { let n = self.result_bigint(); - let m = Scalar::::group_order() - 1; - Scalar::from_bigint(&(n.modulus(&m) + 1)).expect("scalar is guaranteed to be nonzero") + Scalar::from_bigint(&n) } fn digest_bigint(bytes: &[u8]) -> BigInt { diff --git a/src/cryptographic_primitives/hashing/hash_sha256.rs b/src/cryptographic_primitives/hashing/hash_sha256.rs index a6664168..a3e7f49d 100644 --- a/src/cryptographic_primitives/hashing/hash_sha256.rs +++ b/src/cryptographic_primitives/hashing/hash_sha256.rs @@ -9,7 +9,7 @@ use super::traits::Hash; use crate::arithmetic::traits::*; -use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use digest::Digest; use sha2::Sha256; @@ -31,18 +31,7 @@ impl Hash for HSha256 { BigInt::from_bytes(&result_hex[..]) } - fn create_hash_from_ge(ge_vec: &[&Point]) -> ScalarZ { - let mut hasher = Sha256::new(); - for value in ge_vec { - hasher.input(&value.to_bytes(false)); - } - - let result_hex = hasher.result(); - let result = BigInt::from_bytes(&result_hex[..]); - ScalarZ::from(&result) - } - - fn create_hash_from_ge_z(ge_vec: &[&PointZ]) -> ScalarZ { + fn create_hash_from_ge(ge_vec: &[&Point]) -> Scalar { let mut hasher = Sha256::new(); for value in ge_vec { match value.to_bytes(false) { @@ -53,7 +42,7 @@ impl Hash for HSha256 { let result_hex = hasher.result(); let result = BigInt::from_bytes(&result_hex[..]); - ScalarZ::from(&result) + Scalar::from(&result) } fn create_hash_from_slice(byte_slice: &[u8]) -> BigInt { diff --git a/src/cryptographic_primitives/hashing/hash_sha512.rs b/src/cryptographic_primitives/hashing/hash_sha512.rs index 314d41d2..6eeb653e 100644 --- a/src/cryptographic_primitives/hashing/hash_sha512.rs +++ b/src/cryptographic_primitives/hashing/hash_sha512.rs @@ -9,7 +9,7 @@ use super::traits::Hash; use crate::arithmetic::traits::*; -use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use digest::Digest; use sha2::Sha512; @@ -31,18 +31,7 @@ impl Hash for HSha512 { BigInt::from_bytes(&result_hex[..]) } - fn create_hash_from_ge(ge_vec: &[&Point]) -> ScalarZ { - let mut hasher = Sha512::new(); - for value in ge_vec { - hasher.input(&value.to_bytes(false)); - } - - let result_hex = hasher.result(); - let result = BigInt::from_bytes(&result_hex[..]); - ScalarZ::from(&result) - } - - fn create_hash_from_ge_z(ge_vec: &[&PointZ]) -> ScalarZ { + fn create_hash_from_ge(ge_vec: &[&Point]) -> Scalar { let mut hasher = Sha512::new(); for value in ge_vec { match value.to_bytes(false) { @@ -53,7 +42,7 @@ impl Hash for HSha512 { let result_hex = hasher.result(); let result = BigInt::from_bytes(&result_hex[..]); - ScalarZ::from(&result) + Scalar::from(&result) } fn create_hash_from_slice(byte_slice: &[u8]) -> BigInt { diff --git a/src/cryptographic_primitives/hashing/merkle_tree.rs b/src/cryptographic_primitives/hashing/merkle_tree.rs index 1e00ee72..87d62aa6 100644 --- a/src/cryptographic_primitives/hashing/merkle_tree.rs +++ b/src/cryptographic_primitives/hashing/merkle_tree.rs @@ -12,7 +12,7 @@ use std::marker::PhantomData; use crypto::sha3::Sha3; use merkle::{MerkleTree, Proof}; -use crate::elliptic::curves::{Curve, PointZ}; +use crate::elliptic::curves::{Curve, Point}; /* pub struct MT256<'a> { tree: MerkleTree, @@ -26,7 +26,7 @@ pub struct MT256 { //impl <'a> MT256<'a>{ impl MT256 { - pub fn create_tree(vec: &[PointZ]) -> MT256 { + pub fn create_tree(vec: &[Point]) -> MT256 { let digest = Sha3::keccak256(); let vec_bytes = (0..vec.len()) .map(|i| { @@ -46,7 +46,7 @@ impl MT256 { } } - pub fn gen_proof_for_ge(&self, value: &PointZ) -> Proof<[u8; 32]> { + pub fn gen_proof_for_ge(&self, value: &Point) -> Proof<[u8; 32]> { let mut array = [0u8; 32]; let pk_slice = value .to_bytes(false) @@ -72,17 +72,17 @@ impl MT256 { #[cfg(test)] mod tests { use super::MT256; - use crate::elliptic::curves::{Curve, Point, PointZ}; + use crate::elliptic::curves::{Curve, Point}; use crate::test_for_all_curves; test_for_all_curves!(test_mt_functionality_four_leaves); fn test_mt_functionality_four_leaves() { - let ge1: PointZ = Point::generator().to_point().into(); - let ge2: PointZ = ge1.clone(); - let ge3: PointZ = &ge1 + &ge2; - let ge4: PointZ = &ge1 + &ge3; + let ge1: Point = Point::generator().to_point().into(); + let ge2: Point = ge1.clone(); + let ge3: Point = &ge1 + &ge2; + let ge4: Point = &ge1 + &ge3; let ge_vec = vec![ge1.clone(), ge2, ge3, ge4]; let mt256 = MT256::create_tree(&ge_vec); let proof1 = mt256.gen_proof_for_ge(&ge1); @@ -94,9 +94,9 @@ mod tests { test_for_all_curves!(test_mt_functionality_three_leaves); fn test_mt_functionality_three_leaves() { - let ge1: PointZ = Point::generator().to_point().into(); - let ge2: PointZ = ge1.clone(); - let ge3: PointZ = &ge1 + &ge2; + let ge1: Point = Point::generator().to_point().into(); + let ge2: Point = ge1.clone(); + let ge3: Point = &ge1 + &ge2; let ge_vec = vec![ge1.clone(), ge2, ge3]; let mt256 = MT256::create_tree(&ge_vec); diff --git a/src/cryptographic_primitives/hashing/traits.rs b/src/cryptographic_primitives/hashing/traits.rs index 125a881d..8892ee96 100644 --- a/src/cryptographic_primitives/hashing/traits.rs +++ b/src/cryptographic_primitives/hashing/traits.rs @@ -5,15 +5,14 @@ License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE */ -use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use crate::BigInt; #[deprecated(since = "0.8.0", note = "use DigestExt instead")] pub trait Hash { fn create_hash(big_ints: &[&BigInt]) -> BigInt; fn create_hash_from_slice(byte_slice: &[u8]) -> BigInt; - fn create_hash_from_ge(ge_vec: &[&Point]) -> ScalarZ; - fn create_hash_from_ge_z(ge_vec: &[&PointZ]) -> ScalarZ; + fn create_hash_from_ge(ge_vec: &[&Point]) -> Scalar; } #[deprecated(since = "0.8.0", note = "use HmacExt instead")] diff --git a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs index aaf66e17..b7a0193f 100644 --- a/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs +++ b/src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs @@ -5,7 +5,7 @@ use thiserror::Error; use crate::cryptographic_primitives::hashing::DigestExt; use crate::cryptographic_primitives::proofs::ProofError; use crate::cryptographic_primitives::secret_sharing::Polynomial; -use crate::elliptic::curves::{Curve, Point, PointZ, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; /// The prover private polynomial #[derive(Clone, Debug)] @@ -17,9 +17,9 @@ pub struct LdeiWitness { /// `forall i. x[i] = g[i] * alpha[i]` (and the prover knows `w(x)`) #[derive(Clone, Debug)] pub struct LdeiStatement { - pub alpha: Vec>, + pub alpha: Vec>, pub g: Vec>, - pub x: Vec>, + pub x: Vec>, pub d: u16, } @@ -29,7 +29,7 @@ impl LdeiStatement { /// and list `x` such as `x_i = g_i * w(alpha_i)` pub fn new( witness: &LdeiWitness, - alpha: Vec>, + alpha: Vec>, g: Vec>, d: u16, ) -> Result { @@ -56,8 +56,8 @@ impl LdeiStatement { #[derive(Clone, Debug)] pub struct LdeiProof { - pub a: Vec>, - pub e: ScalarZ, + pub a: Vec>, + pub e: Scalar, pub z: Polynomial, } @@ -87,7 +87,7 @@ impl LdeiProof { return Err(InvalidLdeiStatement::AlphaNotPairwiseDistinct); } - let x_expected: Vec> = statement + let x_expected: Vec> = statement .g .iter() .zip(&statement.alpha) @@ -97,25 +97,19 @@ impl LdeiProof { return Err(InvalidLdeiStatement::ListOfXDoesntMatchExpectedValue); } - let u = Polynomial::::sample(statement.d); - let a: Vec> = statement + let u = Polynomial::::sample_exact(statement.d); + let a: Vec> = statement .g .iter() .zip(&statement.alpha) .map(|(g, a)| g * u.evaluate(a)) .collect(); - let mut h = H::new(); - for gi in &statement.g { - h.input_point(gi) - } - for xi in &statement.x { - h.input_pointz(xi) - } - for ai in &a { - h.input_pointz(ai) - } - let e = ScalarZ::from(h.result_scalar()); + let e = H::new() + .chain_points(&statement.g) + .chain_points(&statement.x) + .chain_points(&a) + .result_scalar(); let z = &u - &(&witness.w * &e); @@ -133,17 +127,11 @@ impl LdeiProof { where H: Digest, { - let mut h = H::new(); - for gi in &statement.g { - h.input_point(gi) - } - for xi in &statement.x { - h.input_pointz(xi) - } - for ai in &self.a { - h.input_pointz(ai) - } - let e = ScalarZ::from(h.result_scalar()); + let e = H::new() + .chain_points(&statement.g) + .chain_points(&statement.x) + .chain_points(&self.a) + .result_scalar(); if e != self.e { return Err(ProofError); @@ -209,7 +197,7 @@ mod tests { let poly = Polynomial::::sample_exact(5); let witness = LdeiWitness { w: poly }; - let alpha: Vec> = (1..=10).map(|i| ScalarZ::from(i)).collect(); + let alpha: Vec> = (1..=10).map(|i| Scalar::from(i)).collect(); let g: Vec> = iter::repeat_with(Scalar::random) .map(|x| Point::generator() * x) .take(10) diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs index e31d9717..556757c0 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs @@ -12,7 +12,7 @@ use digest::Digest; use sha2::Sha256; use crate::cryptographic_primitives::hashing::DigestExt; -use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use super::ProofError; @@ -25,17 +25,17 @@ use super::ProofError; #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] #[serde(bound = "")] pub struct HomoELGamalProof { - pub T: PointZ, + pub T: Point, pub A3: Point, - pub z1: ScalarZ, - pub z2: ScalarZ, + pub z1: Scalar, + pub z2: Scalar, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] #[serde(bound = "")] pub struct HomoElGamalWitness { - pub r: ScalarZ, - pub x: ScalarZ, + pub r: Scalar, + pub x: Scalar, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] @@ -44,8 +44,8 @@ pub struct HomoElGamalStatement { pub G: Point, pub H: Point, pub Y: Point, - pub D: PointZ, - pub E: PointZ, + pub D: Point, + pub E: Point, } impl HomoELGamalProof { @@ -60,32 +60,28 @@ impl HomoELGamalProof { let A3 = &delta.G * &s2; let T = A1 + A2; let e = Sha256::new() - .chain_pointz(&T) + .chain_point(&T) .chain_point(&A3) .chain_point(&delta.G) .chain_point(&delta.H) .chain_point(&delta.Y) - .chain_pointz(&delta.D) - .chain_pointz(&delta.E) + .chain_point(&delta.D) + .chain_point(&delta.E) .result_scalar(); // dealing with zero field element - let z1 = if !w.x.is_zero() { - &s1 + &w.x * &e - } else { - ScalarZ::from(s1) - }; + let z1 = &s1 + &w.x * &e; let z2 = s2 + &w.r * e; HomoELGamalProof { T, A3, z1, z2 } } pub fn verify(&self, delta: &HomoElGamalStatement) -> Result<(), ProofError> { let e = Sha256::new() - .chain_pointz(&self.T) + .chain_point(&self.T) .chain_point(&self.A3) .chain_point(&delta.G) .chain_point(&delta.H) .chain_point(&delta.Y) - .chain_pointz(&delta.D) - .chain_pointz(&delta.E) + .chain_point(&delta.D) + .chain_point(&delta.E) .result_scalar(); let z1H_plus_z2Y = &delta.H * &self.z1 + &delta.Y * &self.z2; let T_plus_eD = &self.T + &delta.D * &e; @@ -107,8 +103,8 @@ mod tests { test_for_all_curves!(test_correct_general_homo_elgamal); fn test_correct_general_homo_elgamal() { let witness = HomoElGamalWitness:: { - r: ScalarZ::random(), - x: ScalarZ::random(), + r: Scalar::random(), + x: Scalar::random(), }; let G = Point::::generator(); let h = Scalar::random(); @@ -131,8 +127,8 @@ mod tests { test_for_all_curves!(test_correct_homo_elgamal); fn test_correct_homo_elgamal() { let witness = HomoElGamalWitness { - r: ScalarZ::random(), - x: ScalarZ::random(), + r: Scalar::random(), + x: Scalar::random(), }; let G = Point::::generator(); let y = Scalar::random(); @@ -154,8 +150,8 @@ mod tests { fn test_wrong_homo_elgamal() { // test for E = (r+1)G let witness = HomoElGamalWitness:: { - r: ScalarZ::random(), - x: ScalarZ::random(), + r: Scalar::random(), + x: Scalar::random(), }; let G = Point::::generator(); let h = Scalar::random(); diff --git a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs index 29990b35..a4333523 100644 --- a/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs @@ -11,7 +11,7 @@ use sha2::Sha256; use super::ProofError; use crate::cryptographic_primitives::hashing::{Digest, DigestExt}; -use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; /// This is a proof of knowledge that a pair of group elements {D, E} /// form a valid homomorphic ElGamal encryption (”in the exponent”) using public key Y . @@ -25,8 +25,8 @@ pub struct HomoELGamalDlogProof { pub A1: Point, pub A2: Point, pub A3: Point, - pub z1: ScalarZ, - pub z2: ScalarZ, + pub z1: Scalar, + pub z2: Scalar, } #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] @@ -42,7 +42,7 @@ pub struct HomoElGamalDlogStatement { pub G: Point, pub Y: Point, pub Q: Point, - pub D: PointZ, + pub D: Point, pub E: Point, } @@ -57,13 +57,7 @@ impl HomoELGamalDlogProof { let A2 = &delta.Y * &s2; let A3 = &delta.G * &s2; let e = Sha256::new() - .chain_point(&A1) - .chain_point(&A2) - .chain_point(&A3) - .chain_point(&delta.G) - .chain_point(&delta.Y) - .chain_pointz(&delta.D) - .chain_point(&delta.E) + .chain_points([&A1, &A2, &A3, &delta.G, &delta.Y, &delta.D, &delta.E]) .result_scalar(); let z1 = &s1 + &e * &w.x; let z2 = &s2 + e * &w.r; @@ -72,13 +66,9 @@ impl HomoELGamalDlogProof { pub fn verify(&self, delta: &HomoElGamalDlogStatement) -> Result<(), ProofError> { let e = Sha256::new() - .chain_point(&self.A1) - .chain_point(&self.A2) - .chain_point(&self.A3) - .chain_point(&delta.G) - .chain_point(&delta.Y) - .chain_pointz(&delta.D) - .chain_point(&delta.E) + .chain_points([ + &self.A1, &self.A2, &self.A3, &delta.G, &delta.Y, &delta.D, &delta.E, + ]) .result_scalar(); let z1G = &delta.G * &self.z1; let z2Y = &delta.Y * &self.z2; @@ -134,8 +124,8 @@ mod tests { let G = Point::::generator(); let Y = G * Scalar::random(); let D = G * &witness.x + &Y * &witness.r; - let E = (G * &witness.r + G).ensure_nonzero().unwrap(); - let Q = (G * &witness.x + G).ensure_nonzero().unwrap(); + let E = G * &witness.r + G; + let Q = G * &witness.x + G; let delta = HomoElGamalDlogStatement { G: G.to_point(), Y, diff --git a/src/cryptographic_primitives/proofs/sigma_dlog.rs b/src/cryptographic_primitives/proofs/sigma_dlog.rs index 2b32264e..5909f62c 100644 --- a/src/cryptographic_primitives/proofs/sigma_dlog.rs +++ b/src/cryptographic_primitives/proofs/sigma_dlog.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use sha2::Sha256; use crate::cryptographic_primitives::hashing::{Digest, DigestExt}; -use crate::elliptic::curves::{Curve, Point, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use super::ProofError; @@ -28,7 +28,7 @@ use super::ProofError; pub struct DLogProof { pub pk: Point, pub pk_t_rand_commitment: Point, - pub challenge_response: ScalarZ, + pub challenge_response: Scalar, } impl DLogProof { diff --git a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs index 131305e2..77b9838e 100644 --- a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs +++ b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use sha2::Sha256; use crate::cryptographic_primitives::hashing::{Digest, DigestExt}; -use crate::elliptic::curves::{Curve, Point, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use super::ProofError; @@ -30,7 +30,7 @@ use super::ProofError; pub struct ECDDHProof { pub a1: Point, pub a2: Point, - pub z: ScalarZ, + pub z: Scalar, } #[derive(Clone, PartialEq, Debug)] diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs index 7fd3ce1c..0dfa8bfb 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs @@ -11,7 +11,7 @@ use sha2::Sha256; use crate::cryptographic_primitives::commitments::pedersen_commitment::PedersenCommitment; use crate::cryptographic_primitives::commitments::traits::Commitment; use crate::cryptographic_primitives::hashing::{Digest, DigestExt}; -use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use super::ProofError; @@ -30,9 +30,9 @@ pub struct PedersenProof { e: Scalar, a1: Point, a2: Point, - pub com: PointZ, - z1: ScalarZ, - z2: ScalarZ, + pub com: Point, + z1: Scalar, + z2: Scalar, } impl PedersenProof { @@ -44,17 +44,13 @@ impl PedersenProof { let s2 = Scalar::random(); let a1 = g * &s1; let a2 = h * &s2; - let com: PointZ = PedersenCommitment::create_commitment_with_user_defined_randomness( + let com: Point = PedersenCommitment::create_commitment_with_user_defined_randomness( &m.to_bigint(), &r.to_bigint(), ); let e = Sha256::new() - .chain_point(&g.to_point()) - .chain_point(&h.to_point()) - .chain_pointz(&com) - .chain_point(&a1) - .chain_point(&a2) + .chain_points([&g.to_point(), &h.to_point(), &com, &a1, &a2]) .result_scalar(); let em = &e * m; @@ -75,12 +71,22 @@ impl PedersenProof { pub fn verify(proof: &PedersenProof) -> Result<(), ProofError> { let g = Point::::generator(); let h = Point::::base_point2(); + // let e = Sha256::new() + // .chain_point(&g.to_point()) + // .chain_point(&h.to_point()) + // .chain_pointz(&proof.com) + // .chain_point(&proof.a1) + // .chain_point(&proof.a2) + // .result_scalar(); + let e = Sha256::new() - .chain_point(&g.to_point()) - .chain_point(&h.to_point()) - .chain_pointz(&proof.com) - .chain_point(&proof.a1) - .chain_point(&proof.a2) + .chain_points([ + &g.to_point(), + &h.to_point(), + &proof.com, + &proof.a1, + &proof.a2, + ]) .result_scalar(); let z1g = g * &proof.z1; diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs index c615bfd9..cc4d3f82 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs @@ -11,7 +11,7 @@ use sha2::Sha256; use crate::cryptographic_primitives::commitments::pedersen_commitment::PedersenCommitment; use crate::cryptographic_primitives::commitments::traits::Commitment; use crate::cryptographic_primitives::hashing::{Digest, DigestExt}; -use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use super::ProofError; @@ -29,8 +29,8 @@ pub struct PedersenBlindingProof { e: Scalar, pub m: Scalar, a: Point, - pub com: PointZ, - z: ScalarZ, + pub com: Point, + z: Scalar, } impl PedersenBlindingProof { @@ -40,16 +40,13 @@ impl PedersenBlindingProof { let h = Point::::base_point2(); let s = Scalar::::random(); let a = h * &s; - let com: PointZ = PedersenCommitment::create_commitment_with_user_defined_randomness( + let com: Point = PedersenCommitment::create_commitment_with_user_defined_randomness( &m.to_bigint(), &r.to_bigint(), ); let g = Point::::generator(); let e = Sha256::new() - .chain_point(&g.to_point()) - .chain_point(&h.to_point()) - .chain_pointz(&com) - .chain_point(&a) + .chain_points([&g.to_point(), &h.to_point(), &com, &a]) .chain_scalar(&m) .result_scalar(); @@ -68,10 +65,7 @@ impl PedersenBlindingProof { let g = Point::::generator(); let h = Point::::base_point2(); let e = Sha256::new() - .chain_point(&g.to_point()) - .chain_point(&h.to_point()) - .chain_pointz(&proof.com) - .chain_point(&proof.a) + .chain_points([&g.to_point(), &h.to_point(), &proof.com, &proof.a]) .chain_scalar(&proof.m) .result_scalar(); diff --git a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs index 74e3e8d2..fb70d25b 100644 --- a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs +++ b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs @@ -11,7 +11,7 @@ use std::convert::{TryFrom, TryInto}; use serde::{Deserialize, Serialize}; use crate::cryptographic_primitives::secret_sharing::Polynomial; -use crate::elliptic::curves::{Curve, Point, PointZ, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; use crate::ErrorSS::{self, VerifyShareError}; #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] @@ -29,7 +29,7 @@ pub struct ShamirSecretSharing { #[serde(bound = "")] pub struct VerifiableSS { pub parameters: ShamirSecretSharing, - pub commitments: Vec>, + pub commitments: Vec>, } impl VerifiableSS { @@ -39,12 +39,12 @@ impl VerifiableSS { // TODO: share should accept u16 rather than usize // generate VerifiableSS from a secret - pub fn share(t: usize, n: usize, secret: &ScalarZ) -> (VerifiableSS, Vec>) { + pub fn share(t: usize, n: usize, secret: &Scalar) -> (VerifiableSS, Vec>) { assert!(t < n); let t = u16::try_from(t).unwrap(); let n = u16::try_from(n).unwrap(); - let poly = Polynomial::::sample_with_fixed_const_term(t, secret.clone()); + let poly = Polynomial::::sample_exact_with_fixed_const_term(t, secret.clone()); let secret_shares = poly.evaluate_many_bigint(1..=n).collect(); let g = Point::::generator(); @@ -66,13 +66,13 @@ impl VerifiableSS { } // takes given VSS and generates a new VSS for the same secret and a secret shares vector to match the new commitments - pub fn reshare(&self) -> (VerifiableSS, Vec>) { + pub fn reshare(&self) -> (VerifiableSS, Vec>) { // TODO: ShamirSecretSharing::{threshold, share_count} should be u16 rather than usize let t = u16::try_from(self.parameters.threshold).unwrap(); let n = u16::try_from(self.parameters.share_count).unwrap(); - let one = ScalarZ::::from(1); - let poly = Polynomial::::sample_with_fixed_const_term(t, one.clone()); + let one = Scalar::::from(1); + let poly = Polynomial::::sample_exact_with_fixed_const_term(t, one.clone()); let secret_shares_biased: Vec<_> = poly.evaluate_many_bigint(1..=n).collect(); let secret_shares: Vec<_> = (0..secret_shares_biased.len()) .map(|i| &secret_shares_biased[i] - &one) @@ -95,16 +95,16 @@ impl VerifiableSS { pub fn share_at_indices( t: usize, n: usize, - secret: &ScalarZ, + secret: &Scalar, index_vec: &[usize], - ) -> (VerifiableSS, Vec>) { + ) -> (VerifiableSS, Vec>) { assert_eq!(n, index_vec.len()); // TODO: share_at_indices should accept u16 rather than usize (t, n, index_vec) let t = u16::try_from(t).unwrap(); let n = u16::try_from(n).unwrap(); let index_vec = index_vec.iter().map(|&i| u16::try_from(i).unwrap()); - let poly = Polynomial::::sample_with_fixed_const_term(t, secret.clone()); + let poly = Polynomial::::sample_exact_with_fixed_const_term(t, secret.clone()); let secret_shares = poly.evaluate_many_bigint(index_vec).collect(); let g = Point::::generator(); @@ -112,7 +112,7 @@ impl VerifiableSS { .coefficients() .iter() .map(|coef| g * coef) - .collect::>>(); + .collect::>>(); ( VerifiableSS { parameters: ShamirSecretSharing { @@ -127,8 +127,8 @@ impl VerifiableSS { // returns vector of coefficients #[deprecated(since = "0.7.1", note = "please use Polynomial::sample instead")] - pub fn sample_polynomial(t: usize, coef0: &ScalarZ) -> Vec> { - Polynomial::::sample_with_fixed_const_term(t.try_into().unwrap(), coef0.clone()) + pub fn sample_polynomial(t: usize, coef0: &Scalar) -> Vec> { + Polynomial::::sample_exact_with_fixed_const_term(t.try_into().unwrap(), coef0.clone()) .coefficients() .to_vec() } @@ -137,27 +137,24 @@ impl VerifiableSS { since = "0.7.1", note = "please use Polynomial::evaluate_many_bigint instead" )] - pub fn evaluate_polynomial( - coefficients: &[ScalarZ], - index_vec: &[usize], - ) -> Vec> { + pub fn evaluate_polynomial(coefficients: &[Scalar], index_vec: &[usize]) -> Vec> { Polynomial::::from_coefficients(coefficients.to_vec()) .evaluate_many_bigint(index_vec.iter().map(|&i| u64::try_from(i).unwrap())) .collect() } #[deprecated(since = "0.7.1", note = "please use Polynomial::evaluate instead")] - pub fn mod_evaluate_polynomial(coefficients: &[ScalarZ], point: ScalarZ) -> ScalarZ { + pub fn mod_evaluate_polynomial(coefficients: &[Scalar], point: Scalar) -> Scalar { Polynomial::::from_coefficients(coefficients.to_vec()).evaluate(&point) } - pub fn reconstruct(&self, indices: &[usize], shares: &[ScalarZ]) -> ScalarZ { + pub fn reconstruct(&self, indices: &[usize], shares: &[Scalar]) -> Scalar { assert_eq!(shares.len(), indices.len()); assert!(shares.len() >= self.reconstruct_limit()); // add one to indices to get points let points = indices .iter() - .map(|i| ScalarZ::from(*i as u32 + 1)) + .map(|i| Scalar::from(*i as u32 + 1)) .collect::>(); VerifiableSS::::lagrange_interpolation_at_zero(&points, &shares) } @@ -172,10 +169,7 @@ impl VerifiableSS { // This is obviously less general than `newton_interpolation_general` as we // only get a single value, but it is much faster. - pub fn lagrange_interpolation_at_zero( - points: &[ScalarZ], - values: &[ScalarZ], - ) -> ScalarZ { + pub fn lagrange_interpolation_at_zero(points: &[Scalar], values: &[Scalar]) -> Scalar { let vec_len = values.len(); assert_eq!(points.len(), vec_len); @@ -186,8 +180,8 @@ impl VerifiableSS { .map(|i| { let xi = &points[i]; let yi = &values[i]; - let num = ScalarZ::from(1); - let denum = ScalarZ::from(1); + let num = Scalar::from(1); + let denum = Scalar::from(1); let num = points.iter().zip(0..vec_len).fold(num, |acc, x| { if i != x.1 { acc * x.0 @@ -213,13 +207,13 @@ impl VerifiableSS { tail.fold(head.clone(), |acc, x| acc + x) } - pub fn validate_share(&self, secret_share: &ScalarZ, index: usize) -> Result<(), ErrorSS> { + pub fn validate_share(&self, secret_share: &Scalar, index: usize) -> Result<(), ErrorSS> { let g = Point::generator(); let ss_point = g * secret_share; self.validate_share_public(&ss_point, index) } - pub fn validate_share_public(&self, ss_point: &PointZ, index: usize) -> Result<(), ErrorSS> { + pub fn validate_share_public(&self, ss_point: &Point, index: usize) -> Result<(), ErrorSS> { let comm_to_point = self.get_point_commitment(index); if *ss_point == comm_to_point { Ok(()) @@ -228,8 +222,8 @@ impl VerifiableSS { } } - pub fn get_point_commitment(&self, index: usize) -> PointZ { - let index_fe = ScalarZ::from(index as u32); + pub fn get_point_commitment(&self, index: usize) -> Point { + let index_fe = Scalar::from(index as u32); let mut comm_iterator = self.commitments.iter().rev(); let head = comm_iterator.next().unwrap(); let tail = comm_iterator; @@ -242,7 +236,7 @@ impl VerifiableSS { params: &ShamirSecretSharing, index: usize, s: &[usize], - ) -> ScalarZ { + ) -> Scalar { let s_len = s.len(); // assert!(s_len > self.reconstruct_limit()); // add one to indices to get points @@ -251,8 +245,8 @@ impl VerifiableSS { .collect(); let xi = &points[index]; - let num = ScalarZ::from(1); - let denum = ScalarZ::from(1); + let num = Scalar::from(1); + let denum = Scalar::from(1); let num = (0..s_len).fold(num, |acc, i| { if s[i] != index { acc * &points[s[i]] @@ -281,7 +275,7 @@ mod tests { test_for_all_curves!(test_secret_sharing_3_out_of_5_at_indices); fn test_secret_sharing_3_out_of_5_at_indices() { - let secret = ScalarZ::random(); + let secret = Scalar::random(); let parties = [1, 2, 4, 5, 6]; let (vss_scheme, secret_shares) = VerifiableSS::::share_at_indices(3, 5, &secret, &parties); @@ -302,7 +296,7 @@ mod tests { test_for_all_curves!(test_secret_sharing_3_out_of_5); fn test_secret_sharing_3_out_of_5() { - let secret = ScalarZ::random(); + let secret = Scalar::random(); let (vss_scheme, secret_shares) = VerifiableSS::::share(3, 5, &secret); @@ -347,7 +341,7 @@ mod tests { test_for_all_curves!(test_secret_sharing_3_out_of_7); fn test_secret_sharing_3_out_of_7() { - let secret = ScalarZ::random(); + let secret = Scalar::random(); let (vss_scheme, secret_shares) = VerifiableSS::::share(3, 7, &secret); @@ -387,7 +381,7 @@ mod tests { test_for_all_curves!(test_secret_sharing_1_out_of_2); fn test_secret_sharing_1_out_of_2() { - let secret = ScalarZ::random(); + let secret = Scalar::random(); let (vss_scheme, secret_shares) = VerifiableSS::::share(1, 2, &secret); @@ -414,7 +408,7 @@ mod tests { test_for_all_curves!(test_secret_sharing_1_out_of_3); fn test_secret_sharing_1_out_of_3() { - let secret = ScalarZ::random(); + let secret = Scalar::random(); let (vss_scheme, secret_shares) = VerifiableSS::::share(1, 3, &secret); @@ -455,7 +449,7 @@ mod tests { test_for_all_curves!(test_secret_resharing); fn test_secret_resharing() { - let secret = ScalarZ::random(); + let secret = Scalar::random(); let (vss_scheme, secret_shares) = VerifiableSS::::share(1, 3, &secret); let (new_vss_scheme, zero_secret_shares) = vss_scheme.reshare(); diff --git a/src/cryptographic_primitives/secret_sharing/polynomial.rs b/src/cryptographic_primitives/secret_sharing/polynomial.rs index 2faf1c07..96da82ed 100644 --- a/src/cryptographic_primitives/secret_sharing/polynomial.rs +++ b/src/cryptographic_primitives/secret_sharing/polynomial.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use std::{iter, ops}; -use crate::elliptic::curves::{Curve, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Scalar}; /// Polynomial of some degree `n` /// @@ -11,7 +11,7 @@ use crate::elliptic::curves::{Curve, Scalar, ScalarZ}; /// ie. their type is `ECScalar` implementor. #[derive(Clone, Debug)] pub struct Polynomial { - coefficients: Vec>, + coefficients: Vec>, } impl Polynomial { @@ -31,14 +31,14 @@ impl Polynomial { /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// use curv::elliptic::curves::{ScalarZ, PointZ, Secp256k1}; + /// use curv::elliptic::curves::{Scalar, Point, Secp256k1}; /// - /// let coefs = vec![ScalarZ::random(), ScalarZ::random()]; + /// let coefs = vec![Scalar::random(), Scalar::random()]; /// let poly = Polynomial::::from_coefficients(coefs.clone()); /// /// assert_eq!(coefs, poly.coefficients()); /// ``` - pub fn from_coefficients(coefficients: Vec>) -> Self { + pub fn from_coefficients(coefficients: Vec>) -> Self { Self { coefficients } } @@ -53,16 +53,11 @@ impl Polynomial { /// assert_eq!(polynomial.degree(), 3); /// ``` pub fn sample_exact(degree: u16) -> Self { - if degree == 0 { - Self::from_coefficients(vec![ScalarZ::random()]) - } else { - Self::from_coefficients( - iter::repeat_with(ScalarZ::random) - .take(usize::from(degree)) - .chain(iter::once(ScalarZ::from(Scalar::random()))) - .collect(), - ) - } + Self::from_coefficients( + iter::repeat_with(Scalar::random) + .take(usize::from(degree + 1)) + .collect(), + ) } /// Samples random polynomial of degree `n` with fixed constant term (ie. `a_0 = constant_term`) @@ -70,20 +65,18 @@ impl Polynomial { /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; + /// use curv::elliptic::curves::{Secp256k1, Scalar}; /// - /// let const_term = ScalarZ::::random(); + /// let const_term = Scalar::::random(); /// let polynomial = Polynomial::::sample_exact_with_fixed_const_term(3, const_term.clone()); /// assert_eq!(polynomial.degree(), 3); - /// assert_eq!(polynomial.evaluate(&ScalarZ::zero()), const_term); + /// assert_eq!(polynomial.evaluate(&Scalar::zero()), const_term); /// ``` - pub fn sample_exact_with_fixed_const_term(n: u16, const_term: ScalarZ) -> Self { + pub fn sample_exact_with_fixed_const_term(n: u16, const_term: Scalar) -> Self { if n == 0 { Self::from_coefficients(vec![const_term]) } else { - let random_coefficients = iter::repeat_with(ScalarZ::random) - .take(usize::from(n - 1)) - .chain(iter::once(ScalarZ::from(Scalar::random()))); + let random_coefficients = iter::repeat_with(Scalar::random).take(usize::from(n)); Self::from_coefficients(iter::once(const_term).chain(random_coefficients).collect()) } } @@ -92,15 +85,15 @@ impl Polynomial { /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; + /// use curv::elliptic::curves::{Secp256k1, Scalar}; /// /// let polynomial = Polynomial::::from_coefficients(vec![ - /// ScalarZ::from(1), ScalarZ::from(2), + /// Scalar::from(1), Scalar::from(2), /// ]); /// assert_eq!(polynomial.degree(), 1); /// /// let polynomial = Polynomial::::from_coefficients(vec![ - /// ScalarZ::from(1), ScalarZ::zero(), + /// Scalar::from(1), Scalar::zero(), /// ]); /// assert_eq!(polynomial.degree(), 0); /// ``` @@ -116,60 +109,22 @@ impl Polynomial { u16::try_from(i).expect("polynomial degree guaranteed to fit into u16") } - /// Samples a random polynomial of degree less or equal to given degree - /// - /// ## Example - /// ```rust - /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// use curv::elliptic::curves::Secp256k1; - /// - /// let polynomial = Polynomial::::sample(3); - /// assert!(polynomial.degree() <= 3); - /// ``` - pub fn sample(degree: u16) -> Self { - Polynomial::from_coefficients( - iter::repeat_with(ScalarZ::random) - .take(usize::from(degree + 1)) - .collect(), - ) - } - - /// Samples a random polynomial of degree less or equal to given degree with fixed constant term - /// (ie. `a_0 = const_term`) - /// - /// ## Example - /// ```rust - /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; - /// - /// let const_term = ScalarZ::random(); - /// let polynomial = Polynomial::::sample_with_fixed_const_term(3, const_term.clone()); - /// assert!(polynomial.degree() <= 3); - /// assert_eq!(polynomial.evaluate(&ScalarZ::zero()), const_term); - /// ``` - pub fn sample_with_fixed_const_term(degree: u16, const_term: ScalarZ) -> Self { - let random_coefficients = iter::repeat_with(ScalarZ::random).take(usize::from(degree)); - Polynomial { - coefficients: iter::once(const_term).chain(random_coefficients).collect(), - } - } - /// Takes scalar `x` and evaluates `f(x)` /// /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; + /// use curv::elliptic::curves::{Secp256k1, Scalar}; /// /// let polynomial = Polynomial::::sample_exact(2); /// - /// let x = ScalarZ::from(10); + /// let x = Scalar::from(10); /// let y = polynomial.evaluate(&x); /// /// let a = polynomial.coefficients(); /// assert_eq!(y, &a[0] + &a[1] * &x + &a[2] * &x*&x); /// ``` - pub fn evaluate(&self, point_x: &ScalarZ) -> ScalarZ { + pub fn evaluate(&self, point_x: &Scalar) -> Scalar { let mut reversed_coefficients = self.coefficients.iter().rev(); let head = reversed_coefficients .next() @@ -186,22 +141,22 @@ impl Polynomial { /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; + /// use curv::elliptic::curves::{Secp256k1, Scalar}; /// /// let polynomial = Polynomial::::sample_exact(2); /// /// let x: u16 = 10; - /// let y: ScalarZ = polynomial.evaluate_bigint(x); + /// let y: Scalar = polynomial.evaluate_bigint(x); /// /// let a = polynomial.coefficients(); - /// let x = ScalarZ::from(x); + /// let x = Scalar::from(x); /// assert_eq!(y, &a[0] + &a[1] * &x + &a[2] * &x*&x); /// ``` - pub fn evaluate_bigint(&self, point_x: B) -> ScalarZ + pub fn evaluate_bigint(&self, point_x: B) -> Scalar where - ScalarZ: From, + Scalar: From, { - self.evaluate(&ScalarZ::from(point_x)) + self.evaluate(&Scalar::from(point_x)) } /// Takes list of points `xs` and returns iterator over `f(xs[i])` @@ -209,11 +164,11 @@ impl Polynomial { /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; + /// use curv::elliptic::curves::{Secp256k1, Scalar}; /// /// let polynomial = Polynomial::::sample_exact(2); /// - /// let xs = &[ScalarZ::from(10), ScalarZ::from(11)]; + /// let xs = &[Scalar::from(10), Scalar::from(11)]; /// let ys = polynomial.evaluate_many(xs); /// /// let a = polynomial.coefficients(); @@ -221,9 +176,9 @@ impl Polynomial { /// assert_eq!(y, &a[0] + &a[1] * x + &a[2] * x*x); /// } /// ``` - pub fn evaluate_many<'i, I>(&'i self, points_x: I) -> impl Iterator> + 'i + pub fn evaluate_many<'i, I>(&'i self, points_x: I) -> impl Iterator> + 'i where - I: IntoIterator> + 'i, + I: IntoIterator> + 'i, { points_x.into_iter().map(move |x| self.evaluate(x)) } @@ -234,7 +189,7 @@ impl Polynomial { /// ## Example /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; + /// use curv::elliptic::curves::{Secp256k1, Scalar}; /// /// let polynomial = Polynomial::::sample_exact(2); /// @@ -243,17 +198,17 @@ impl Polynomial { /// /// let a = polynomial.coefficients(); /// for (y, x) in ys.zip(xs) { - /// let x = ScalarZ::from(*x); + /// let x = Scalar::from(*x); /// assert_eq!(y, &a[0] + &a[1] * &x + &a[2] * &x*&x); /// } /// ``` pub fn evaluate_many_bigint<'i, B, I>( &'i self, points_x: I, - ) -> impl Iterator> + 'i + ) -> impl Iterator> + 'i where I: IntoIterator + 'i, - ScalarZ: From, + Scalar: From, { points_x.into_iter().map(move |x| self.evaluate_bigint(x)) } @@ -265,14 +220,14 @@ impl Polynomial { /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; - /// use curv::elliptic::curves::{Secp256k1, ScalarZ}; + /// use curv::elliptic::curves::{Secp256k1, Scalar}; /// /// let polynomial = Polynomial::::sample_exact(3); /// let a = polynomial.coefficients(); - /// let x = ScalarZ::::random(); + /// let x = Scalar::::random(); /// assert_eq!(polynomial.evaluate(&x), &a[0] + &a[1] * &x + &a[2] * &x*&x + &a[3] * &x*&x*&x); /// ``` - pub fn coefficients(&self) -> &[ScalarZ] { + pub fn coefficients(&self) -> &[Scalar] { &self.coefficients } } @@ -283,20 +238,20 @@ impl Polynomial { /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; -/// use curv::elliptic::curves::{Secp256k1, ScalarZ}; +/// use curv::elliptic::curves::{Secp256k1, Scalar}; /// /// let f = Polynomial::::sample_exact(3); /// -/// let s = ScalarZ::::random(); +/// let s = Scalar::::random(); /// let g = &f * &s; /// /// for (f_coef, g_coef) in f.coefficients().iter().zip(g.coefficients()) { /// assert_eq!(&(f_coef * &s), g_coef); /// } /// ``` -impl ops::Mul<&ScalarZ> for &Polynomial { +impl ops::Mul<&Scalar> for &Polynomial { type Output = Polynomial; - fn mul(self, scalar: &ScalarZ) -> Self::Output { + fn mul(self, scalar: &Scalar) -> Self::Output { let coefficients = self.coefficients.iter().map(|c| c * scalar).collect(); Polynomial::from_coefficients(coefficients) } @@ -308,13 +263,13 @@ impl ops::Mul<&ScalarZ> for &Polynomial { /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; -/// use curv::elliptic::curves::{Secp256k1, ScalarZ}; +/// use curv::elliptic::curves::{Secp256k1, Scalar}; /// /// let f = Polynomial::::sample_exact(2); /// let g = Polynomial::::sample_exact(3); /// let h = &f + &g; /// -/// let x = ScalarZ::::from(10); +/// let x = Scalar::::from(10); /// assert_eq!(h.evaluate(&x), f.evaluate(&x) + g.evaluate(&x)); /// ``` impl ops::Add for &Polynomial { @@ -344,13 +299,13 @@ impl ops::Add for &Polynomial { /// /// ```rust /// # use curv::cryptographic_primitives::secret_sharing::Polynomial; -/// use curv::elliptic::curves::{Secp256k1, ScalarZ}; +/// use curv::elliptic::curves::{Secp256k1, Scalar}; /// /// let f = Polynomial::::sample_exact(2); /// let g = Polynomial::::sample_exact(3); /// let h = &f - &g; /// -/// let x = ScalarZ::::from(10); +/// let x = Scalar::::from(10); /// assert_eq!(h.evaluate(&x), f.evaluate(&x) - &g.evaluate(&x)); /// ``` impl ops::Sub for &Polynomial { diff --git a/src/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs b/src/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs index 795919a4..749b9f0b 100644 --- a/src/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs +++ b/src/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use crate::cryptographic_primitives::proofs::sigma_valid_pedersen::PedersenProof; use crate::cryptographic_primitives::proofs::sigma_valid_pedersen_blind::PedersenBlindingProof; -use crate::elliptic::curves::{Curve, PointZ, Scalar, ScalarZ}; +use crate::elliptic::curves::{Curve, Point, Scalar}; /// based on How To Simulate It – A Tutorial on the Simulation /// Proof Technique. protocol 7.3: Multiple coin tossing. which provide simulatble constant round @@ -53,7 +53,7 @@ impl Party1SecondMessage { party2seed: &Scalar, party1seed: &Scalar, party1blinding: &Scalar, - ) -> (Party1SecondMessage, ScalarZ) { + ) -> (Party1SecondMessage, Scalar) { let proof = PedersenBlindingProof::::prove(&party1seed, &party1blinding); let coin_flip_result = &party1seed.to_bigint() ^ &party2seed.to_bigint(); ( @@ -61,7 +61,7 @@ impl Party1SecondMessage { proof, seed: party1seed.clone(), }, - ScalarZ::from(&coin_flip_result), + Scalar::from(&coin_flip_result), ) } } @@ -70,12 +70,12 @@ impl Party1SecondMessage { pub fn finalize( proof: &PedersenBlindingProof, party2seed: &Scalar, - party1comm: &PointZ, -) -> ScalarZ { + party1comm: &Point, +) -> Scalar { PedersenBlindingProof::::verify(&proof).expect("{r,(m,c)} proof failed"); assert_eq!(&proof.com, party1comm); let coin_flip_result = &proof.m.to_bigint() ^ &party2seed.to_bigint(); - ScalarZ::from(&coin_flip_result) + Scalar::from(&coin_flip_result) } #[cfg(test)] diff --git a/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs b/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs index 63e9ff58..396e0480 100644 --- a/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs +++ b/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs @@ -77,13 +77,22 @@ impl Party1FirstMessage { // we use hash based commitment let pk_commitment_blind_factor = BigInt::sample(SECURITY_BITS); let pk_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&public_share.to_bytes(true)), + &BigInt::from_bytes( + &public_share + .to_bytes(true) + .expect("public_share guaranteed to be nonzero"), + ), &pk_commitment_blind_factor, ); let zk_pok_blind_factor = BigInt::sample(SECURITY_BITS); let zk_pok_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&d_log_proof.pk_t_rand_commitment.to_bytes(true)), + &BigInt::from_bytes( + &d_log_proof + .pk_t_rand_commitment + .to_bytes(true) + .unwrap_or_else(|| vec![0]), + ), &zk_pok_blind_factor, ); let ec_key_pair = EcKeyPair { @@ -115,13 +124,22 @@ impl Party1FirstMessage { let pk_commitment_blind_factor = BigInt::sample(SECURITY_BITS); let pk_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&public_share.to_bytes(true)), + &BigInt::from_bytes( + &public_share + .to_bytes(true) + .expect("public_share guaranteed to be nonzero"), + ), &pk_commitment_blind_factor, ); let zk_pok_blind_factor = BigInt::sample(SECURITY_BITS); let zk_pok_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&d_log_proof.pk_t_rand_commitment.to_bytes(true)), + &BigInt::from_bytes( + &d_log_proof + .pk_t_rand_commitment + .to_bytes(true) + .unwrap_or_else(|| vec![0]), + ), &zk_pok_blind_factor, ); @@ -203,6 +221,9 @@ impl Party2SecondMessage { let party_one_zk_pok_blind_factor = &party_one_second_message.comm_witness.zk_pok_blind_factor; let party_one_public_share = &party_one_second_message.comm_witness.public_share; + if party_one_public_share.is_zero() { + return Err(ProofError); + } let party_one_pk_commitment_blind_factor = &party_one_second_message .comm_witness .pk_commitment_blind_factor; @@ -211,7 +232,9 @@ impl Party2SecondMessage { let mut flag = true; if party_one_pk_commitment != &HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&party_one_public_share.to_bytes(true)), + &BigInt::from_bytes(&party_one_public_share.to_bytes(true).expect( + "party_one_public_share guaranteed to be nonzero by if statement above", + )), &party_one_pk_commitment_blind_factor, ) { @@ -220,7 +243,12 @@ impl Party2SecondMessage { if party_one_zk_pok_commitment != &HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&party_one_d_log_proof.pk_t_rand_commitment.to_bytes(true)), + &BigInt::from_bytes( + &party_one_d_log_proof + .pk_t_rand_commitment + .to_bytes(true) + .unwrap_or_else(|| vec![0]), + ), &party_one_zk_pok_blind_factor, ) { diff --git a/src/elliptic/curves/bls12_381/pairing.rs b/src/elliptic/curves/bls12_381/pairing.rs index 3c9d85c0..bec1912a 100644 --- a/src/elliptic/curves/bls12_381/pairing.rs +++ b/src/elliptic/curves/bls12_381/pairing.rs @@ -72,8 +72,7 @@ mod tests { let a = Point::::generator().to_point(); let b = Point::::generator().to_point(); let scalar_factor_1 = Scalar::::random(); - let scalar_factor_2 = - Scalar::::from_raw(scalar_factor_1.as_raw().clone()).unwrap(); + let scalar_factor_2 = Scalar::::from_raw(scalar_factor_1.as_raw().clone()); let res_mul_a = &a * &scalar_factor_1; let res_mul_b = &b * &scalar_factor_2; let res_a_power = Pair::compute_pairing(&res_mul_a, &b); @@ -87,7 +86,7 @@ mod tests { let p = Point::::generator().to_point(); let q = Point::::generator().to_point(); let r = Point::::base_point2().to_point(); - let q_plus_r = (&q + &r).ensure_nonzero().unwrap(); + let q_plus_r = &q + &r; let e_p_q = Pair::compute_pairing(&p, &q); let e_p_r = Pair::compute_pairing(&p, &r); let e_p_q_r = Pair::compute_pairing(&p, &q_plus_r); diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index 79d4f668..b45f400d 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -4,10 +4,9 @@ //! //! ## Usage //! -//! Elliptic curve cryptography operates on points and scalars. We provide according structures -//! [Point\](Point), [Scalar\](Scalar) (and [PointZ\](PointZ), [ScalarZ\](ScalarZ) -//! — for points and scalars that might be zero), where generic `E` stands for choice of elliptic -//! curve, e.g. [Secp256k1] (`Point`, `Scalar`, etc.). +//! Elliptic curve cryptography operates on points and scalars. We provide respective structures +//! [Point\](Point), [Scalar\](Scalar), where generic `E` stands for choice of elliptic +//! curve, e.g. [Secp256k1] (`Point`, `Scalar`). //! //! Various methods and traits are defined for points and scalars which basically empowers you to do //! anything you can do in elliptic curve cryptography. @@ -68,7 +67,7 @@ //! ``` //! //! `Point` (for generic `E: Curve`) implements many traits you might need (e.g. Serialize, PartialEq, -//! Debug, etc.) without specifying additional bounds. The same apllies to other structures (PointZ, Scalar, ...). +//! Debug, etc.) without specifying additional bounds. The same applies to other structures (PointRef, Scalar, ...). //! //! ## Implementing your own curve //! @@ -97,7 +96,7 @@ pub use self::{ }; pub use self::{ traits::{Curve, ECPoint, ECScalar, PointCoords}, - wrappers::{Generator, Point, PointRef, PointZ, Scalar, ScalarZ}, + wrappers::{Generator, Point, PointRef, Scalar}, }; pub mod error { diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index a7c2f98b..4a182c09 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -15,7 +15,7 @@ use crate::BigInt; /// Elliptic curve implementation /// /// Refers to according implementation of [ECPoint] and [ECScalar]. -pub trait Curve: PartialEq + Clone + fmt::Debug { +pub trait Curve: PartialEq + Clone + fmt::Debug + 'static { type Point: ECPoint; type Scalar: ECScalar; @@ -26,13 +26,10 @@ pub trait Curve: PartialEq + Clone + fmt::Debug { /// Scalar value modulus [group order](Self::group_order) /// /// ## Note -/// This is a low-level trait, you should not use it directly. See wrappers [Point], [PointZ], -/// [Scalar], [ScalarZ]. +/// This is a low-level trait, you should not use it directly. See wrappers [Point], [Scalar]. /// /// [Point]: super::wrappers::Point -/// [PointZ]: super::wrappers::PointZ /// [Scalar]: super::wrappers::Scalar -/// [ScalarZ]: super::wrappers::ScalarZ /// /// Trait exposes various methods to manipulate scalars. Scalar can be zero. Scalar must zeroize its /// value on drop. @@ -96,13 +93,10 @@ pub trait ECScalar: Clone + PartialEq + fmt::Debug + 'static { /// Point on elliptic curve /// /// ## Note -/// This is a low-level trait, you should not use it directly. See [Point], [PointZ], [Scalar], -/// [ScalarZ]. +/// This is a low-level trait, you should not use it directly. See [Point], [Scalar]. /// /// [Point]: super::wrappers::Point -/// [PointZ]: super::wrappers::PointZ /// [Scalar]: super::wrappers::Scalar -/// [ScalarZ]: super::wrappers::ScalarZ /// /// Trait exposes various methods that make elliptic curve arithmetic. The point can /// be [zero](ECPoint::zero). Unlike [ECScalar], ECPoint isn't required to zeroize its value on drop, diff --git a/src/elliptic/curves/wrappers/arithmetic.rs b/src/elliptic/curves/wrappers/arithmetic.rs index 32de5f3f..1e3d05d4 100644 --- a/src/elliptic/curves/wrappers/arithmetic.rs +++ b/src/elliptic/curves/wrappers/arithmetic.rs @@ -129,106 +129,96 @@ macro_rules! matrix { } #[cfg(not(release))] -fn addition_of_two_points(result: E::Point) -> PointZ { +fn addition_of_two_points(result: E::Point) -> Point { // In non-release environment we check that every addition results into correct point (either // zero or of the expected order) - PointZ::from_raw(result) + Point::from_raw(result) .expect("addition of two points must be either a zero or of the same order") } #[cfg(release)] -fn addition_of_two_points(result: E::Point) -> PointZ { +fn addition_of_two_points(result: E::Point) -> Point { // In release we skip checks - PointZ::from_raw_unchecked(result) + Point::from_raw_unchecked(result) } +// +// (o_<> Point, Point), (o_ Point, &Point), +// (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), +// +// (_o<> &Point, Point), (r_ &Point, &Point), +// (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), +// +// (_o<'p> PointRef<'p, E>, Point), (r_<'p> PointRef<'p, E>, &Point), +// (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), +// +// (_o<> Generator, Point), (r_ Generator, &Point), +// (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), +// + matrix! { trait = Add, trait_fn = add, - output = PointZ, + output = Point, output_new = addition_of_two_points, point_fn = add_point, point_assign_fn = add_point_assign, pairs = { - (o_<> Point, Point), (o_<> Point, PointZ), - (o_<> Point, &Point), (o_<> Point, &PointZ), + (o_<> Point, Point), (o_<> Point, &Point), (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), - (o_<> PointZ, Point), (o_<> PointZ, PointZ), - (o_<> PointZ, &Point), (o_<> PointZ, &PointZ), - (o_<'p> PointZ, PointRef<'p, E>), (o_<> PointZ, Generator), - - (_o<> &Point, Point), (_o<> &Point, PointZ), - (r_<> &Point, &Point), (r_<> &Point, &PointZ), + (_o<> &Point, Point), (r_<> &Point, &Point), (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), - (_o<> &PointZ, Point), (_o<> &PointZ, PointZ), - (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), - (r_<'p> &PointZ, PointRef<'p, E>), (r_<> &PointZ, Generator), - - (_o<'p> PointRef<'p, E>, Point), (_o<'p> PointRef<'p, E>, PointZ), - (r_<'p> PointRef<'p, E>, &Point), (r_<'p> PointRef<'p, E>, &PointZ), + (_o<'p> PointRef<'p, E>, Point), (r_<'p> PointRef<'p, E>, &Point), (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), - (_o<> Generator, Point), (_o<> Generator, PointZ), - (r_<> Generator, &Point), (r_<> Generator, &PointZ), + (_o<> Generator, Point), (r_<> Generator, &Point), (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), } } #[cfg(not(release))] -fn subtraction_of_two_point(result: E::Point) -> PointZ { +fn subtraction_of_two_point(result: E::Point) -> Point { // In non-release environment we check that every subtraction results into correct point (either // zero or of the expected order) - PointZ::from_raw(result) + Point::from_raw(result) .expect("subtraction of two points must be either a zero or of the same order") } #[cfg(release)] -fn subtraction_of_two_point(result: E::Point) -> PointZ { +fn subtraction_of_two_point(result: E::Point) -> Point { // In release we skip checks - PointZ::from_raw_unchecked(result) + Point::from_raw_unchecked(result) } matrix! { trait = Sub, trait_fn = sub, - output = PointZ, + output = Point, output_new = subtraction_of_two_point, point_fn = sub_point, point_assign_fn = sub_point_assign, pairs = { - (o_<> Point, Point), (o_<> Point, PointZ), - (o_<> Point, &Point), (o_<> Point, &PointZ), + (o_<> Point, Point), (o_<> Point, &Point), (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), - (o_<> PointZ, Point), (o_<> PointZ, PointZ), - (o_<> PointZ, &Point), (o_<> PointZ, &PointZ), - (o_<'p> PointZ, PointRef<'p, E>), (o_<> PointZ, Generator), - - (_o<> &Point, Point), (_o<> &Point, PointZ), - (r_<> &Point, &Point), (r_<> &Point, &PointZ), + (_o<> &Point, Point), (r_<> &Point, &Point), (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), - (_o<> &PointZ, Point), (_o<> &PointZ, PointZ), - (r_<> &PointZ, &Point), (r_<> &PointZ, &PointZ), - (r_<'p> &PointZ, PointRef<'p, E>), (r_<> &PointZ, Generator), - - (_o<'p> PointRef<'p, E>, Point), (_o<'p> PointRef<'p, E>, PointZ), - (r_<'p> PointRef<'p, E>, &Point), (r_<'p> PointRef<'p, E>, &PointZ), + (_o<'p> PointRef<'p, E>, Point), (r_<'p> PointRef<'p, E>, &Point), (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), - (_o<> Generator, Point), (_o<> Generator, PointZ), - (r_<> Generator, &Point), (r_<> Generator, &PointZ), + (_o<> Generator, Point), (r_<> Generator, &Point), (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), } } #[cfg(not(release))] -fn multiplication_of_nonzero_point_at_nonzero_scalar(result: E::Point) -> Point { +fn multiplication_of_point_at_scalar(result: E::Point) -> Point { Point::from_raw(result) - .expect("multiplication of point at non-zero scalar must always produce a non-zero point of the same order") + .expect("multiplication of point at scalar must always produce either a point of the same order or a zero point") } #[cfg(release)] -fn multiplication_of_point_at_nonzero_scalar(result: E::Point) -> Point { +fn multiplication_of_point_at_scalar(result: E::Point) -> Point { Point::from_raw_unchecked(result) } @@ -236,164 +226,65 @@ matrix! { trait = Mul, trait_fn = mul, output = Point, - output_new = multiplication_of_nonzero_point_at_nonzero_scalar, - point_fn = scalar_mul, - point_assign_fn = scalar_mul_assign, - pairs = { - (_o<> Scalar, Point), - (_r<> Scalar, &Point), - (_r<'p> Scalar, PointRef<'p, E>), - - (_o<> &Scalar, Point), - (_r<> &Scalar, &Point), - (_r<'p> &Scalar, PointRef<'p, E>), - - // --- and vice-versa --- - - (o_<> Point, Scalar), - (o_<> Point, &Scalar), - - (r_<> &Point, Scalar), - (r_<> &Point, &Scalar), - - (r_<'p> PointRef<'p, E>, Scalar), - (r_<'p> PointRef<'p, E>, &Scalar), - } -} - -#[cfg(not(release))] -fn multiplication_of_point_at_scalar(result: E::Point) -> PointZ { - PointZ::from_raw(result) - .expect("multiplication of point at scalar must always produce either a point of the same order or a zero point") -} -#[cfg(release)] -fn multiplication_of_point_at_scalar(result: E::Point) -> PointZ { - PointZ::from_raw_unchecked(result) -} - -matrix! { - trait = Mul, - trait_fn = mul, - output = PointZ, output_new = multiplication_of_point_at_scalar, point_fn = scalar_mul, point_assign_fn = scalar_mul_assign, pairs = { - (_o<> Scalar, PointZ), - (_r<> Scalar, &PointZ), - - (_o<> ScalarZ, Point), (_o<> ScalarZ, PointZ), - (_r<> ScalarZ, &Point), (_r<> ScalarZ, &PointZ), - (_r<'p> ScalarZ, PointRef<'p, E>), + (o_<> Point, Scalar), (o_<> Point, &Scalar), + (r_<> &Point, Scalar), (r_<> &Point, &Scalar), + (r_<'p> PointRef<'p, E>, Scalar), (r_<'p> PointRef<'p, E>, &Scalar), - (_o<> &Scalar, PointZ), - (_r<> &Scalar, &PointZ), - - (_o<> &ScalarZ, Point), (_o<> &ScalarZ, PointZ), - (_r<> &ScalarZ, &Point), (_r<> &ScalarZ, &PointZ), - (_r<'p> &ScalarZ, PointRef<'p, E>), - - // --- and vice-versa --- - - (o_<> Point, ScalarZ), - (o_<> Point, &ScalarZ), - - (o_<> PointZ, Scalar), (o_<> PointZ, ScalarZ), - (o_<> PointZ, &Scalar), (o_<> PointZ, &ScalarZ), - - (r_<> &Point, ScalarZ), - (r_<> &Point, &ScalarZ), - - (r_<> &PointZ, Scalar), (r_<> &PointZ, ScalarZ), - (r_<> &PointZ, &Scalar), (r_<> &PointZ, &ScalarZ), - - (r_<'p> PointRef<'p, E>, ScalarZ), - (r_<'p> PointRef<'p, E>, &ScalarZ), + (_o<> Scalar, Point), (_o<> &Scalar, Point), + (_r<> Scalar, &Point), (_r<> &Scalar, &Point), + (_r<'p> Scalar, PointRef<'p, E>), (_r<'p> &Scalar, PointRef<'p, E>), } } matrix! { trait = Add, trait_fn = add, - output = ScalarZ, - output_new = ScalarZ::from_raw, + output = Scalar, + output_new = Scalar::from_raw, point_fn = add, point_assign_fn = add_assign, pairs = { - (o_<> Scalar, Scalar), (o_<> Scalar, ScalarZ), - (o_<> Scalar, &Scalar), (o_<> Scalar, &ScalarZ), - (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), - (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), - (_o<> &Scalar, Scalar), (_o<> &Scalar, ScalarZ), - (r_<> &Scalar, &Scalar), (r_<> &Scalar, &ScalarZ), - (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), - (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), + (o_<> Scalar, Scalar), (o_<> Scalar, &Scalar), + (_o<> &Scalar, Scalar), (r_<> &Scalar, &Scalar), } } matrix! { trait = Sub, trait_fn = sub, - output = ScalarZ, - output_new = ScalarZ::from_raw, + output = Scalar, + output_new = Scalar::from_raw, point_fn = sub, point_assign_fn = sub_assign, pairs = { - (o_<> Scalar, Scalar), (o_<> Scalar, ScalarZ), - (o_<> Scalar, &Scalar), (o_<> Scalar, &ScalarZ), - (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), - (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), - (_o<> &Scalar, Scalar), (_o<> &Scalar, ScalarZ), - (r_<> &Scalar, &Scalar), (r_<> &Scalar, &ScalarZ), - (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), - (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), - } -} - -matrix! { - trait = Mul, - trait_fn = mul, - output = ScalarZ, - output_new = ScalarZ::from_raw, - point_fn = mul, - point_assign_fn = mul_assign, - pairs = { - (o_<> Scalar, ScalarZ), - (o_<> Scalar, &ScalarZ), - (o_<> ScalarZ, Scalar), (o_<> ScalarZ, ScalarZ), - (o_<> ScalarZ, &Scalar), (o_<> ScalarZ, &ScalarZ), - (_o<> &Scalar, ScalarZ), - (r_<> &Scalar, &ScalarZ), - (_o<> &ScalarZ, Scalar), (_o<> &ScalarZ, ScalarZ), - (r_<> &ScalarZ, &Scalar), (r_<> &ScalarZ, &ScalarZ), + (o_<> Scalar, Scalar), (o_<> Scalar, &Scalar), + (_o<> &Scalar, Scalar), (r_<> &Scalar, &Scalar), } } -fn multiplication_of_two_nonzero_scalars(result: E::Scalar) -> Scalar { - Scalar::from_raw(result) - .expect("multiplication of two nonzero scalar by prime modulo must be nonzero") -} - matrix! { trait = Mul, trait_fn = mul, output = Scalar, - output_new = multiplication_of_two_nonzero_scalars, + output_new = Scalar::from_raw, point_fn = mul, point_assign_fn = mul_assign, pairs = { - (o_<> Scalar, Scalar), - (o_<> Scalar, &Scalar), - (_o<> &Scalar, Scalar), - (r_<> &Scalar, &Scalar), + (o_<> Scalar, Scalar), (o_<> Scalar, &Scalar), + (_o<> &Scalar, Scalar), (r_<> &Scalar, &Scalar), } } impl ops::Mul<&Scalar> for Generator { type Output = Point; fn mul(self, rhs: &Scalar) -> Self::Output { - Point::from_raw(E::Point::generator_mul(rhs.as_raw())) - .expect("generator multiplied by non-zero scalar is always a point of group order") + Point::from_raw(E::Point::generator_mul(rhs.as_raw())).expect( + "generator multiplied by scalar is always a point of group order or a zero point", + ) } } @@ -418,40 +309,11 @@ impl ops::Mul> for Scalar { } } -impl ops::Mul<&ScalarZ> for Generator { - type Output = PointZ; - fn mul(self, rhs: &ScalarZ) -> Self::Output { - PointZ::from_raw(E::Point::generator_mul(rhs.as_raw())) - .expect("sG must be either a point of group order or a zero point") - } -} - -impl ops::Mul> for Generator { - type Output = PointZ; - fn mul(self, rhs: ScalarZ) -> Self::Output { - self.mul(&rhs) - } -} - -impl ops::Mul> for &ScalarZ { - type Output = PointZ; - fn mul(self, rhs: Generator) -> Self::Output { - rhs.mul(self) - } -} - -impl ops::Mul> for ScalarZ { - type Output = PointZ; - fn mul(self, rhs: Generator) -> Self::Output { - rhs.mul(self) - } -} - impl ops::Neg for Scalar { type Output = Scalar; fn neg(self) -> Self::Output { - Scalar::from_raw(self.as_raw().neg()).expect("neg must not produce zero point") + Scalar::from_raw(self.as_raw().neg()) } } @@ -459,23 +321,7 @@ impl ops::Neg for &Scalar { type Output = Scalar; fn neg(self) -> Self::Output { - Scalar::from_raw(self.as_raw().neg()).expect("neg must not produce zero point") - } -} - -impl ops::Neg for ScalarZ { - type Output = ScalarZ; - - fn neg(self) -> Self::Output { - ScalarZ::from_raw(self.as_raw().neg()) - } -} - -impl ops::Neg for &ScalarZ { - type Output = ScalarZ; - - fn neg(self) -> Self::Output { - ScalarZ::from_raw(self.as_raw().neg()) + Scalar::from_raw(self.as_raw().neg()) } } @@ -483,7 +329,8 @@ impl ops::Neg for Point { type Output = Point; fn neg(self) -> Self::Output { - Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") + Point::from_raw(self.as_raw().neg_point()) + .expect("neg must not produce point of different order") } } @@ -491,7 +338,8 @@ impl ops::Neg for &Point { type Output = Point; fn neg(self) -> Self::Output { - Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") + Point::from_raw(self.as_raw().neg_point()) + .expect("neg must not produce point of different order") } } @@ -499,7 +347,8 @@ impl<'p, E: Curve> ops::Neg for PointRef<'p, E> { type Output = Point; fn neg(self) -> Self::Output { - Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") + Point::from_raw(self.as_raw().neg_point()) + .expect("neg must not produce point of different order") } } @@ -507,23 +356,8 @@ impl ops::Neg for Generator { type Output = Point; fn neg(self) -> Self::Output { - Point::from_raw(self.as_raw().neg_point()).expect("neg must not produce zero point") - } -} - -impl ops::Neg for PointZ { - type Output = PointZ; - - fn neg(self) -> Self::Output { - PointZ::from_raw(self.as_raw().neg_point()).expect("negated point must have the same order") - } -} - -impl ops::Neg for &PointZ { - type Output = PointZ; - - fn neg(self) -> Self::Output { - PointZ::from_raw(self.as_raw().neg_point()).expect("negated point must have the same order") + Point::from_raw(self.as_raw().neg_point()) + .expect("neg must not produce point of different order") } } @@ -564,12 +398,12 @@ mod test { }; } - /// Function asserts that P2 can be added to P1 (ie. P1 + P2) and result is PointZ. + /// Function asserts that P2 can be added to P1 (ie. P1 + P2) and result is Point. /// If any condition doesn't meet, function won't compile. #[allow(dead_code)] fn assert_point_addition_defined() where - P1: ops::Add>, + P1: ops::Add>, E: Curve, { // no-op @@ -580,18 +414,18 @@ mod test { fn _curve() { assert_operator_defined_for! { assert_fn = assert_point_addition_defined, - lhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, - rhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, + lhs = {Point, &Point, PointRef, Generator}, + rhs = {Point, &Point, PointRef, Generator}, } } } - /// Function asserts that P2 can be subtracted from P1 (ie. P1 - P2) and result is PointZ. + /// Function asserts that P2 can be subtracted from P1 (ie. P1 - P2) and result is Point. /// If any condition doesn't meet, function won't compile. #[allow(dead_code)] fn assert_point_subtraction_defined() where - P1: ops::Sub>, + P1: ops::Sub>, E: Curve, { // no-op @@ -602,27 +436,16 @@ mod test { fn _curve() { assert_operator_defined_for! { assert_fn = assert_point_subtraction_defined, - lhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, - rhs = {Point, PointZ, &Point, &PointZ, PointRef, Generator}, + lhs = {Point, &Point, PointRef, Generator}, + rhs = {Point, &Point, PointRef, Generator}, } } } - /// Function asserts that M can be multiplied by N (ie. M * N) and result is PointZ. + /// Function asserts that M can be multiplied by N (ie. M * N) and result is Point. /// If any condition doesn't meet, function won't compile. #[allow(dead_code)] fn assert_point_multiplication_defined() - where - M: ops::Mul>, - E: Curve, - { - // no-op - } - - /// Function asserts that M can be multiplied by N (ie. M * N) and result is **non-zero** Point. - /// If any condition doesn't meet, function won't compile. - #[allow(dead_code)] - fn assert_point_nonzero_multiplication_defined() where M: ops::Mul>, E: Curve, @@ -633,48 +456,28 @@ mod test { #[test] fn test_point_multiplication_defined() { fn _curve() { - assert_operator_defined_for! { - assert_fn = assert_point_nonzero_multiplication_defined, - lhs = {Point, &Point, PointRef}, - rhs = {Scalar, &Scalar}, - } assert_operator_defined_for! { assert_fn = assert_point_multiplication_defined, - lhs = {Point, &Point, PointRef}, - rhs = {ScalarZ, &ScalarZ}, - } - assert_operator_defined_for! { - assert_fn = assert_point_multiplication_defined, - lhs = {PointZ, &PointZ}, - rhs = {Scalar, &Scalar, ScalarZ, &ScalarZ}, + lhs = {Point, &Point, PointRef, Generator}, + rhs = {Scalar, &Scalar}, } // and vice-versa - assert_operator_defined_for! { - assert_fn = assert_point_nonzero_multiplication_defined, - lhs = {Scalar, &Scalar}, - rhs = {Point, &Point, PointRef}, - } - assert_operator_defined_for! { - assert_fn = assert_point_multiplication_defined, - lhs = {ScalarZ, &ScalarZ}, - rhs = {Point, &Point, PointRef}, - } assert_operator_defined_for! { assert_fn = assert_point_multiplication_defined, - lhs = {Scalar, &Scalar, ScalarZ, &ScalarZ}, - rhs = {PointZ, &PointZ}, + lhs = {Scalar, &Scalar}, + rhs = {Point, &Point, PointRef, Generator}, } } } - /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is ScalarZ. + /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is Scalar. /// If any condition doesn't meet, function won't compile. #[allow(dead_code)] fn assert_scalars_addition_defined() where - S1: ops::Add>, + S1: ops::Add>, E: Curve, { // no-op @@ -685,18 +488,18 @@ mod test { fn _curve() { assert_operator_defined_for! { assert_fn = assert_scalars_addition_defined, - lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + lhs = {Scalar, Scalar}, + rhs = {Scalar, Scalar}, } } } - /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is ScalarZ. + /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is Scalar. /// If any condition doesn't meet, function won't compile. #[allow(dead_code)] fn assert_scalars_subtraction_defined() where - S1: ops::Sub>, + S1: ops::Sub>, E: Curve, { // no-op @@ -707,27 +510,16 @@ mod test { fn _curve() { assert_operator_defined_for! { assert_fn = assert_scalars_subtraction_defined, - lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, + lhs = {Scalar, Scalar}, + rhs = {Scalar, Scalar}, } } } - /// Function asserts that S1 can be multiplied by S2 (ie. S1 * S2) and result is ScalarZ. - /// If any condition doesn't meet, function won't compile. - #[allow(dead_code)] - fn assert_scalars_multiplication_defined() - where - S1: ops::Mul>, - E: Curve, - { - // no-op - } - /// Function asserts that S1 can be multiplied by S2 (ie. S1 * S2) and result is Scalar. /// If any condition doesn't meet, function won't compile. #[allow(dead_code)] - fn assert_nonzero_scalars_multiplication_defined() + fn assert_scalars_multiplication_defined() where S1: ops::Mul>, E: Curve, @@ -740,18 +532,8 @@ mod test { fn _curve() { assert_operator_defined_for! { assert_fn = assert_scalars_multiplication_defined, - lhs = {ScalarZ, &ScalarZ}, - rhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - } - assert_operator_defined_for! { - assert_fn = assert_scalars_multiplication_defined, - lhs = {Scalar, ScalarZ, &Scalar, &ScalarZ}, - rhs = {ScalarZ, &ScalarZ}, - } - assert_operator_defined_for! { - assert_fn = assert_nonzero_scalars_multiplication_defined, - lhs = {Scalar, &Scalar}, - rhs = {Scalar, &Scalar}, + lhs = {Scalar, Scalar}, + rhs = {Scalar, Scalar}, } } } diff --git a/src/elliptic/curves/wrappers/error.rs b/src/elliptic/curves/wrappers/error.rs index dee34b01..015d660c 100644 --- a/src/elliptic/curves/wrappers/error.rs +++ b/src/elliptic/curves/wrappers/error.rs @@ -6,10 +6,16 @@ use crate::elliptic::curves::traits::*; #[derive(Debug, Error, Clone, PartialEq)] #[error("invalid point (point order ≠ group order)")] -pub struct MismatchedPointOrder(pub(super) ()); +pub struct MismatchedPointOrder(()); + +impl MismatchedPointOrder { + pub(super) fn new() -> Self { + MismatchedPointOrder(()) + } +} #[derive(Debug, Error)] -pub enum PointZDeserializationError { +pub enum PointFromBytesError { #[error("failed to deserialize the point")] DeserializationError, #[error("invalid point ({0})")] @@ -17,7 +23,7 @@ pub enum PointZDeserializationError { } #[derive(Debug, Error)] -pub enum PointZFromCoordsError { +pub enum PointFromCoordsError { #[error("{}", NotOnCurve)] NotOnCurve, #[error("invalid point ({0})")] @@ -26,7 +32,13 @@ pub enum PointZFromCoordsError { /// Indicates that conversion or computation failed due to occurred zero point #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct ZeroPointError(pub(super) ()); +pub struct ZeroPointError(()); + +impl ZeroPointError { + pub(super) fn new() -> Self { + ZeroPointError(()) + } +} impl fmt::Display for ZeroPointError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -38,7 +50,13 @@ impl std::error::Error for ZeroPointError {} /// Indicates that conversion or computation failed due to occurred zero scalar #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct ZeroScalarError(pub(super) ()); +pub struct ZeroScalarError(()); + +impl ZeroScalarError { + pub(super) fn new() -> Self { + ZeroScalarError(()) + } +} impl fmt::Display for ZeroScalarError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -55,21 +73,3 @@ pub enum InvalidPoint { #[error("{}", MismatchedPointOrder(()))] MismatchedPointOrder, } - -/// Constructing Point from its coordinates error -#[derive(Debug, Error)] -pub enum PointFromCoordsError { - #[error("invalid point ({0})")] - InvalidPoint(InvalidPoint), - #[error("{}", NotOnCurve)] - PointNotOnCurve, -} - -/// Constructing Point from its (un)compressed representation error -#[derive(Debug, Error)] -pub enum PointFromBytesError { - #[error("invalid point ({0})")] - InvalidPoint(InvalidPoint), - #[error("{0}")] - Deserialize(#[source] DeserializationError), -} diff --git a/src/elliptic/curves/wrappers/format.rs b/src/elliptic/curves/wrappers/format.rs index 206943dc..5db47b5d 100644 --- a/src/elliptic/curves/wrappers/format.rs +++ b/src/elliptic/curves/wrappers/format.rs @@ -10,7 +10,7 @@ use crate::arithmetic::*; use crate::elliptic::curves::traits::*; use super::{ - error::{InvalidPoint, MismatchedPointOrder, PointFromCoordsError, PointZFromCoordsError}, + error::{InvalidPoint, PointFromCoordsError}, *, }; @@ -29,38 +29,6 @@ impl PointFormat { } } -impl TryFrom> for PointZ { - type Error = ConvertParsedPointError; - fn try_from(parsed: PointFormat) -> Result { - if parsed.curve != E::CURVE_NAME { - return Err(ConvertParsedPointError::MismatchedCurve { - expected: E::CURVE_NAME, - got: parsed.curve, - }); - } - match parsed.point { - None => Ok(PointZ::zero()), - Some(coords) => match PointZ::from_coords(&coords.x, &coords.y) { - Ok(p) => Ok(p), - Err(PointZFromCoordsError::NotOnCurve) => Err(ConvertParsedPointError::NotOnCurve), - Err(PointZFromCoordsError::InvalidPoint(MismatchedPointOrder(()))) => Err( - ConvertParsedPointError::InvalidPoint(InvalidPoint::MismatchedPointOrder), - ), - }, - } - } -} - -impl From> for PointFormat { - fn from(point: PointZ) -> Self { - Self { - curve: E::CURVE_NAME.into(), - point: point.coords(), - _ph: PhantomData, - } - } -} - impl TryFrom> for Point { type Error = ConvertParsedPointError; fn try_from(parsed: PointFormat) -> Result { @@ -71,17 +39,13 @@ impl TryFrom> for Point { }); } match parsed.point { - None => Err(ConvertParsedPointError::InvalidPoint( - InvalidPoint::ZeroPoint, - )), + None => Ok(Point::zero()), Some(coords) => match Point::from_coords(&coords.x, &coords.y) { Ok(p) => Ok(p), - Err(PointFromCoordsError::PointNotOnCurve) => { - Err(ConvertParsedPointError::NotOnCurve) - } - Err(PointFromCoordsError::InvalidPoint(reason)) => { - Err(ConvertParsedPointError::InvalidPoint(reason)) - } + Err(PointFromCoordsError::NotOnCurve) => Err(ConvertParsedPointError::NotOnCurve), + Err(PointFromCoordsError::InvalidPoint(_e)) => Err( + ConvertParsedPointError::InvalidPoint(InvalidPoint::MismatchedPointOrder), + ), }, } } @@ -91,7 +55,7 @@ impl From> for PointFormat { fn from(point: Point) -> Self { Self { curve: E::CURVE_NAME.into(), - point: Some(point.coords()), + point: point.coords(), _ph: PhantomData, } } @@ -101,7 +65,7 @@ impl<'p, E: Curve> From> for PointFormat { fn from(point: PointRef<'p, E>) -> Self { Self { curve: E::CURVE_NAME.into(), - point: Some(point.coords()), + point: point.coords(), _ph: PhantomData, } } @@ -128,30 +92,6 @@ pub struct ScalarFormat { scalar: ScalarHex, } -impl TryFrom> for ScalarZ { - type Error = ConvertParsedScalarError; - - fn try_from(parsed: ScalarFormat) -> Result { - if parsed.curve != E::CURVE_NAME { - return Err(ConvertParsedScalarError::MismatchedCurve { - got: parsed.curve, - expected: E::CURVE_NAME, - }); - } - - Ok(ScalarZ::from_raw(parsed.scalar.0)) - } -} - -impl From> for ScalarFormat { - fn from(s: ScalarZ) -> Self { - ScalarFormat { - curve: E::CURVE_NAME.into(), - scalar: ScalarHex(s.into_raw()), - } - } -} - impl TryFrom> for Scalar { type Error = ConvertParsedScalarError; @@ -163,9 +103,7 @@ impl TryFrom> for Scalar { }); } - ScalarZ::from_raw(parsed.scalar.0) - .ensure_nonzero() - .ok_or(ConvertParsedScalarError::ZeroScalar) + Ok(Scalar::from_raw(parsed.scalar.0)) } } diff --git a/src/elliptic/curves/wrappers/generator.rs b/src/elliptic/curves/wrappers/generator.rs index 74fd4879..a37e4f57 100644 --- a/src/elliptic/curves/wrappers/generator.rs +++ b/src/elliptic/curves/wrappers/generator.rs @@ -16,11 +16,10 @@ use super::{Point, PointRef}; /// ## Example /// /// ```rust -/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; -/// let s = Scalar::::random(); // Non-zero scalar -/// let g = Point::::generator(); // Curve generator -/// let result: Point = s * g; // Generator multiplied at non-zero scalar is -/// // always a non-zero point +/// # use curv::elliptic::curves::{Point, Scalar, Secp256k1}; +/// let s = Scalar::::random(); +/// let g = Point::::generator(); +/// let result: Point = s * g; /// ``` /// /// ## Performance @@ -29,7 +28,7 @@ use super::{Point, PointRef}; /// converting generator into the `Point` as long as it's possible: /// /// ```rust -/// # use curv::elliptic::curves::{Point, Scalar, Secp256k1, Generator, PointZ}; +/// # use curv::elliptic::curves::{Point, Scalar, Secp256k1, Generator}; /// let s: Scalar = Scalar::random(); /// // Generator multiplication: /// let g: Generator = Point::generator(); @@ -51,20 +50,19 @@ impl Default for Generator { } impl Generator { - pub fn as_raw(self) -> &'static E::Point { - E::Point::generator() - } - /// Clones generator point, returns `Point` pub fn to_point(self) -> Point { - // Safety: curve generator must be non-zero point, otherwise nothing will work at all - unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } + Point::from(self) } /// Converts generator into `PointRef` pub fn as_point(self) -> PointRef<'static, E> { - // Safety: curve generator must be non-zero point, otherwise nothing will work at all - unsafe { PointRef::from_raw_unchecked(self.as_raw()) } + PointRef::from(self) + } + + /// Returns a reference to low-level point implementation + pub fn as_raw(self) -> &'static E::Point { + E::Point::generator() } } diff --git a/src/elliptic/curves/wrappers/mod.rs b/src/elliptic/curves/wrappers/mod.rs index 27edf898..7bd58128 100644 --- a/src/elliptic/curves/wrappers/mod.rs +++ b/src/elliptic/curves/wrappers/mod.rs @@ -4,11 +4,6 @@ mod format; mod generator; mod point; mod point_ref; -mod point_z; mod scalar; -mod scalar_z; -pub use self::{ - generator::Generator, point::Point, point_ref::PointRef, point_z::PointZ, scalar::Scalar, - scalar_z::ScalarZ, -}; +pub use self::{generator::Generator, point::Point, point_ref::PointRef, scalar::Scalar}; diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index 87452558..c57180b4 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -1,4 +1,3 @@ -use std::convert::TryFrom; use std::fmt; use serde::{Deserialize, Serialize}; @@ -7,12 +6,13 @@ use crate::elliptic::curves::traits::*; use crate::BigInt; use super::{ - error::{InvalidPoint, PointFromBytesError, PointFromCoordsError, ZeroPointError}, + error::{MismatchedPointOrder, PointFromBytesError, PointFromCoordsError}, format::PointFormat, - Generator, PointRef, PointZ, + Generator, PointRef, }; +use crate::elliptic::curves::ZeroPointError; -/// Elliptic point of [group order](super::Scalar::group_order) +/// Elliptic point of a [group order](super::Scalar::group_order), or a zero point /// /// ## Guarantees /// @@ -20,42 +20,39 @@ use super::{ /// /// Any instance of `Point` is guaranteed to belong to curve `E`, i.e. its coordinates must /// satisfy curve equations -/// * Point order equals to [group order](super::Scalar::group_order) +/// * Point order equals to [group order](super::Scalar::group_order) (unless it's zero point) /// /// I.e. denoting `q = group_order`, following predicate is always true: -/// `qP = O ∧ forall 0 < s < q. sP ≠ O` +/// `P = O ∨ qP = O ∧ forall 0 < s < q. sP ≠ O` /// -/// Note that this also means that `Point` cannot be zero (zero point has `order=1`), -/// ie. `forall a b. a: PointZ ∧ b: Point → a + b ≢ a`. It also implies that `Point` is -/// guaranteed to have coordinates (only point at infinity doesn't). +/// ## Security /// -/// ## Arithmetics -/// -/// You can add, subtract two points, or multiply point at scalar. -/// -/// Addition or subtraction of two points might result into zero point, so these operators output -/// [`PointZ`](PointZ) that allowed to be zero. +/// Validate points if they come from untrusted source. Mistakenly used zero point might break security +/// of cryptoalgorithm. Use [ensure_nonzero](Point::ensure_nonzero) to validate them. /// /// ```rust -/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; -/// let p1: Point = -/// Point::generator() * Scalar::random(); // Non-zero point -/// let p2: Point = -/// Point::generator() * Scalar::random(); // Non-zero point -/// let result: PointZ = p1 + p2; // Addition of two (even non-zero) -/// // points might produce zero point -/// let nonzero_result: Option> = result.ensure_nonzero(); +/// # use curv::elliptic::curves::{Point, Curve, ZeroPointError}; +/// # struct T; +/// fn process_input(point: &Point) -> Result { +/// point.ensure_nonzero()?; +/// // ... process the point +/// # Ok(T) +/// } /// ``` /// -/// Multiplying point at non-zero scalar is guaranteed to be non-zero (as point order is known -/// to be equal to group order, and scalar is known to be less then group order): +/// ## Arithmetics +/// +/// You can add, subtract two points, or multiply point at scalar: /// /// ```rust -/// # use curv::elliptic::curves::{PointZ, Point, Scalar, Secp256k1}; -/// let s = Scalar::::random(); // Non-zero scalar -/// let g = Point::::generator(); // Curve generator -/// let result: Point = s * g; // Generator multiplied at non-zero scalar is -/// // always a non-zero point +/// # use curv::elliptic::curves::{Point, Scalar, Secp256k1}; +/// fn expression( +/// a: Point, +/// b: Point, +/// c: Scalar, +/// ) -> Point { +/// a + b * c +/// } /// ``` #[derive(Serialize, Deserialize)] #[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] @@ -64,10 +61,18 @@ pub struct Point { } impl Point { + /// Ensures that `self` is not zero, returns `Err(_)` otherwise + pub fn ensure_nonzero(&self) -> Result<(), ZeroPointError> { + if self.is_zero() { + Err(ZeroPointError::new()) + } else { + Ok(()) + } + } /// Curve generator /// - /// Returns a static reference on actual value because in most cases referenced value is fine. - /// Use [`.to_point()`](Generator::to_point) if you need to take it by value. + /// Returns a structure holding a static reference on actual value (in most cases referenced + /// value is fine). Use [`.to_point()`](Generator::to_point) if you need to take it by value. pub fn generator() -> Generator { Generator::default() } @@ -76,53 +81,62 @@ impl Point { /// /// We provide an alternative generator value and prove that it was picked randomly. /// - /// Returns a static reference on actual value because in most cases referenced value is fine. - /// Use [`.to_point()`](PointRef::to_point) if you need to take it by value. + /// Returns a structure holding a static reference on actual value (in most cases referenced + /// value is fine). Use [`.to_point()`](PointRef::to_point) if you need to take it by value. pub fn base_point2() -> PointRef<'static, E> { let p = E::Point::base_point2(); PointRef::from_raw(p).expect("base_point2 must have correct order") } - /// Constructs a point from coordinates, returns error if x,y don't satisfy curve equation or - /// correspond to zero point - pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { - let p = E::Point::from_coords(x, y) - .map_err(|NotOnCurve { .. }| PointFromCoordsError::PointNotOnCurve)?; - Self::from_raw(p).map_err(PointFromCoordsError::InvalidPoint) + /// Constructs zero point + /// + /// Zero point (or curve neutral element) is usually denoted as `O`. Its property: `forall A. A + O = A`. + /// + /// Weierstrass and Montgomery curves employ special "point at infinity" that represent a neutral + /// element, such points don't have coordinates (i.e. [from_coords], [x_coord], [y_coord] return + /// `None`). Edwards curves' neutral element has coordinates. + /// + /// [from_coords]: Self::from_coords + /// [x_coord]: Self::x_coord + /// [y_coord]: Self::y_coord + pub fn zero() -> Self { + // Safety: `self` can be constructed to hold a zero point + unsafe { Self::from_raw_unchecked(E::Point::zero()) } } - /// Tries to parse a point from its (un)compressed form - /// - /// Whether it's a compressed or uncompressed form will be deduced from its length - pub fn from_bytes(bytes: &[u8]) -> Result { - let p = E::Point::deserialize(bytes).map_err(PointFromBytesError::Deserialize)?; - Self::from_raw(p).map_err(PointFromBytesError::InvalidPoint) + /// Checks whether point is zero + pub fn is_zero(&self) -> bool { + self.as_raw().is_zero() } - /// Returns point coordinates (`x` and `y`) + /// Returns point coordinates /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn coords(&self) -> PointCoords { - self.as_point().coords() + /// Point might not have coordinates (specifically, "point at infinity" doesn't), in this case + /// `None` is returned + pub fn coords(&self) -> Option { + self.as_raw().coords() } - /// Returns `x` coordinate of point + /// Returns point x coordinate /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn x_coord(&self) -> BigInt { - self.as_point().x_coord() + /// See [coords](Self::coords) method that retrieves both x and y at once. + pub fn x_coord(&self) -> Option { + self.as_raw().x_coord() } - /// Returns `y` coordinate of point + /// Returns point y coordinate /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn y_coord(&self) -> BigInt { - self.as_point().y_coord() + /// See [coords](Self::coords) method that retrieves both x and y at once. + pub fn y_coord(&self) -> Option { + self.as_raw().y_coord() } - /// Serializes point into (un)compressed form - pub fn to_bytes(&self, compressed: bool) -> Vec { - self.as_point().to_bytes(compressed) + /// Constructs a point from its coordinates, returns error if coordinates don't satisfy + /// curve equation or if point has invalid order + pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { + let raw_point = E::Point::from_coords(x, y) + .map_err(|_: NotOnCurve| PointFromCoordsError::NotOnCurve)?; + Self::from_raw(raw_point).map_err(PointFromCoordsError::InvalidPoint) } /// Creates [PointRef] that holds a reference on `self` @@ -130,23 +144,37 @@ impl Point { PointRef::from(self) } + /// Tries to parse a point in (un)compressed form + /// + /// Whether it's in compressed or uncompressed form will be deduced from its length + pub fn from_bytes(bytes: &[u8]) -> Result { + let p = E::Point::deserialize(bytes) + .map_err(|_: DeserializationError| PointFromBytesError::DeserializationError)?; + Self::from_raw(p).map_err(PointFromBytesError::InvalidPoint) + } + + /// Serializes a point in (un)compressed form + /// + /// Returns `None` if it's point at infinity + pub fn to_bytes(&self, compressed: bool) -> Option> { + self.as_raw().serialize(compressed) + } + /// Constructs a `Point` from low-level [ECPoint] implementor /// /// Returns error if point is zero, or its order isn't equal to [group order]. /// - /// Typically, you don't need to use this constructor. See [generator](Self::generator), - /// [base_point2](Self::base_point2), [from_coords](Self::from_coords), [from_bytes](Self::from_bytes) + /// Typically, you don't need to use this constructor. See [generator](Point::generator), + /// [base_point2](Point::base_point2), [from_coords](Self::from_coords), [from_bytes](Self::from_bytes) /// constructors, and `From` and `TryFrom` traits implemented for `Point`. /// /// [ECPoint]: crate::elliptic::curves::ECPoint /// [group order]: crate::elliptic::curves::ECScalar::group_order - pub fn from_raw(raw_point: E::Point) -> Result { - if raw_point.is_zero() { - Err(InvalidPoint::ZeroPoint) - } else if !raw_point.check_point_order_equals_group_order() { - Err(InvalidPoint::MismatchedPointOrder) + pub fn from_raw(raw_point: E::Point) -> Result { + if raw_point.is_zero() || raw_point.check_point_order_equals_group_order() { + Ok(Self { raw_point }) } else { - Ok(Point { raw_point }) + Err(MismatchedPointOrder::new()) } } @@ -154,25 +182,24 @@ impl Point { /// /// # Safety /// - /// This function will not perform any checks against the point. You must guarantee that point - /// order is equal to curve [group order]. To perform this check, you may use - /// [ECPoint::check_point_order_equals_group_order][check_point_order_equals_group_order] - /// method. - /// - /// Note that it implies that point must not be zero (zero point has `order=1`). + /// This function will not perform any checks against the point. You must guarantee that either + /// point order is equal to curve [group order] or it's a zero point. To perform this check, you + /// may use [ECPoint::check_point_order_equals_group_order][check_point_order_equals_group_order] + /// and [ECPoint::is_zero][is_zero] methods. /// /// [ECPoint]: crate::elliptic::curves::ECPoint /// [group order]: crate::elliptic::curves::ECScalar::group_order /// [check_point_order_equals_group_order]: crate::elliptic::curves::ECPoint::check_point_order_equals_group_order - pub unsafe fn from_raw_unchecked(point: E::Point) -> Self { - Point { raw_point: point } + /// [is_zero]: crate::elliptic::curves::ECPoint::is_zero + pub unsafe fn from_raw_unchecked(raw_point: E::Point) -> Self { + Self { raw_point } } /// Returns a reference to low-level point implementation /// - /// Typically, you don't need to work with `ECPoint` trait directly. `Point` wraps `ECPoint` - /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization - /// traits, various getters (like [`.coords()`](Self::coords)). If you believe that some functionality + /// Typically, you don't need to work with `ECPoint` trait directly. `Point` wrapper + /// provides convenient utilities around it: it implements arithmetic operators, (de)serialization + /// traits, various getters (like [`.coords()`](Self::coords). If you believe that some functionality /// is missing, please [open an issue](https://github.com/ZenGo-X/curv). pub fn as_raw(&self) -> &E::Point { &self.raw_point @@ -181,7 +208,7 @@ impl Point { /// Converts a point into inner low-level point implementation /// /// Typically, you don't need to work with `ECPoint` trait directly. `Point` wraps `ECPoint` - /// and provides convenient utilities around it, it implements arithmetic operators, (de)serialization + /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization /// traits, various getters (like [`.coords()`](Self::coords)). If you believe that some functionality /// is missing, please [open an issue](https://github.com/ZenGo-X/curv). pub fn into_raw(self) -> E::Point { @@ -191,48 +218,45 @@ impl Point { impl PartialEq for Point { fn eq(&self, other: &Self) -> bool { - self.as_raw().eq(&other.as_raw()) - } -} - -impl PartialEq> for Point { - fn eq(&self, other: &PointZ) -> bool { - self.as_raw().eq(&other.as_raw()) + self.raw_point.eq(&other.raw_point) } } impl<'p, E: Curve> PartialEq> for Point { fn eq(&self, other: &PointRef<'p, E>) -> bool { - self.as_raw().eq(&other.as_raw()) + self.as_raw().eq(other.as_raw()) } } impl PartialEq> for Point { fn eq(&self, other: &Generator) -> bool { - self.as_raw().eq(&other.as_raw()) + self.as_raw().eq(other.as_raw()) } } impl Clone for Point { fn clone(&self) -> Self { - // Safety: `self` is guaranteed to be non-zero + // Safety: self is guaranteed to have correct order unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } } } impl fmt::Debug for Point { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.as_raw().fmt(f) + self.raw_point.fmt(f) } } -impl TryFrom> for Point { - type Error = ZeroPointError; - fn try_from(point: PointZ) -> Result { - match Self::from_raw(point.into_raw()) { - Ok(p) => Ok(p), - Err(InvalidPoint::ZeroPoint) => Err(ZeroPointError(())), - Err(InvalidPoint::MismatchedPointOrder) => panic!("Point must have correct order"), - } +impl From> for Point { + fn from(g: Generator) -> Self { + // Safety: curve generator order must be equal to group_order + unsafe { Point::from_raw_unchecked(g.as_raw().clone()) } + } +} + +impl<'p, E: Curve> From> for Point { + fn from(p: PointRef) -> Self { + // Safety: `PointRef` holds the same guarantees as `Point` + unsafe { Point::from_raw_unchecked(p.as_raw().clone()) } } } diff --git a/src/elliptic/curves/wrappers/point_ref.rs b/src/elliptic/curves/wrappers/point_ref.rs index 3864d748..affa6409 100644 --- a/src/elliptic/curves/wrappers/point_ref.rs +++ b/src/elliptic/curves/wrappers/point_ref.rs @@ -5,11 +5,11 @@ use serde::Serialize; use crate::elliptic::curves::traits::*; use crate::BigInt; -use super::{error::InvalidPoint, format::PointFormat, Generator, Point, PointZ}; +use super::{error::MismatchedPointOrder, format::PointFormat, Generator, Point}; -/// Reference on elliptic point of [group order](super::Scalar::group_order) +/// Holds a reference to elliptic point of [group order](super::Scalar::group_order) or to zero point /// -/// Holds internally a reference on [`Point`](Point), refer to its documentation to learn +/// Holds internally a reference to [`Point`](Point), refer to its documentation to learn /// more about Point/PointRef guarantees, security notes, and arithmetics. #[derive(Serialize)] #[serde(into = "PointFormat", bound = "")] @@ -18,8 +18,11 @@ pub struct PointRef<'p, E: Curve> { } impl PointRef<'static, E> { + /// Curve second generator + /// + /// We provide an alternative generator value and prove that it was picked randomly. pub fn base_point2() -> Self { - Self::from_raw(E::Point::base_point2()).expect("base_point2 must be non-zero") + Self::from_raw(E::Point::base_point2()).expect("base_point2 must be of group_order") } } @@ -29,41 +32,36 @@ where { /// Returns point coordinates (`x` and `y`) /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn coords(&self) -> PointCoords { - self.as_raw() - .coords() - .expect("Point guaranteed to have coordinates") + /// Point might not have coordinates (specifically, "point at infinity" doesn't), in this case + /// `None` is returned + pub fn coords(&self) -> Option { + self.as_raw().coords() } /// Returns `x` coordinate of point /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn x_coord(&self) -> BigInt { - self.as_raw() - .x_coord() - .expect("Point guaranteed to have coordinates") + /// See [coords](Self::coords) method that retrieves both x and y at once. + pub fn x_coord(&self) -> Option { + self.as_raw().x_coord() } /// Returns `y` coordinate of point /// - /// Method never fails as Point is guaranteed to have coordinates - pub fn y_coord(&self) -> BigInt { - self.as_raw() - .y_coord() - .expect("Point guaranteed to have coordinates") + /// See [coords](Self::coords) method that retrieves both x and y at once. + pub fn y_coord(&self) -> Option { + self.as_raw().y_coord() } /// Serializes point into (un)compressed form - pub fn to_bytes(self, compressed: bool) -> Vec { - self.as_raw() - .serialize(compressed) - .expect("non-zero point must always be serializable") + /// + /// Returns `None` if it's point at infinity + pub fn to_bytes(self, compressed: bool) -> Option> { + self.as_raw().serialize(compressed) } /// Clones the referenced point pub fn to_point(self) -> Point { - // Safety: `self` is guaranteed to have order = group_order + // Safety: `self` holds the same guarantees as `Point` requires to meet unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } } @@ -77,13 +75,11 @@ where /// /// [ECPoint]: crate::elliptic::curves::ECPoint /// [group order]: crate::elliptic::curves::ECScalar::group_order - pub fn from_raw(raw_point: &'p E::Point) -> Result { - if raw_point.is_zero() { - Err(InvalidPoint::ZeroPoint) - } else if !raw_point.check_point_order_equals_group_order() { - Err(InvalidPoint::MismatchedPointOrder) - } else { + pub fn from_raw(raw_point: &'p E::Point) -> Result { + if raw_point.is_zero() || raw_point.check_point_order_equals_group_order() { Ok(Self { raw_point }) + } else { + Err(MismatchedPointOrder::new()) } } @@ -119,7 +115,7 @@ where impl<'p, E: Curve> Clone for PointRef<'p, E> { fn clone(&self) -> Self { - // Safety: `self` is guaranteed to be non-zero + // Safety: `self` is guaranteed to be nonzero unsafe { Self::from_raw_unchecked(self.as_raw()) } } } @@ -132,13 +128,6 @@ impl<'p, E: Curve> fmt::Debug for PointRef<'p, E> { } } -impl<'p, E: Curve> From<&'p Point> for PointRef<'p, E> { - fn from(point: &'p Point) -> Self { - // Safety: `point` is guaranteed to be non-zero - unsafe { PointRef::from_raw_unchecked(point.as_raw()) } - } -} - impl<'p, E: Curve> PartialEq for PointRef<'p, E> { fn eq(&self, other: &Self) -> bool { self.as_raw().eq(other.as_raw()) @@ -151,14 +140,22 @@ impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { } } -impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { - fn eq(&self, other: &PointZ) -> bool { +impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { + fn eq(&self, other: &Generator) -> bool { self.as_raw().eq(other.as_raw()) } } -impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { - fn eq(&self, other: &Generator) -> bool { - self.as_raw().eq(other.as_raw()) +impl<'p, E: Curve> From<&'p Point> for PointRef<'p, E> { + fn from(point: &'p Point) -> Self { + // Safety: `Point` holds the same guarantees as `PointRef` + unsafe { PointRef::from_raw_unchecked(point.as_raw()) } + } +} + +impl From> for PointRef<'static, E> { + fn from(g: Generator) -> Self { + // Safety: generator must be of group_order + unsafe { PointRef::from_raw_unchecked(g.as_raw()) } } } diff --git a/src/elliptic/curves/wrappers/point_z.rs b/src/elliptic/curves/wrappers/point_z.rs deleted file mode 100644 index f2643308..00000000 --- a/src/elliptic/curves/wrappers/point_z.rs +++ /dev/null @@ -1,226 +0,0 @@ -use std::convert::TryFrom; -use std::fmt; - -use serde::{Deserialize, Serialize}; - -use crate::elliptic::curves::traits::*; -use crate::BigInt; - -use super::{ - error::{MismatchedPointOrder, PointZDeserializationError, PointZFromCoordsError}, - format::PointFormat, - Generator, Point, PointRef, -}; - -/// Either an elliptic point of a [group order](super::Scalar::group_order), or a zero point -/// -/// ## Security -/// -/// Mistakenly used zero point might break security of cryptographic algorithm. It's preferred to -/// use [`Point`](Point) that's guaranteed to be non-zero. Use [ensure_nonzero](PointZ::ensure_nonzero) -/// to convert `PointZ` into `Point`. -/// -/// ## Guarantees -/// -/// * On curve -/// -/// Any instance of `PointZ` is guaranteed to belong to curve `E`, i.e. its coordinates must -/// satisfy curve equations -/// * Point order equals to [group order](super::Scalar::group_order) (unless it's zero point) -/// -/// I.e. denoting `q = group_order`, following predicate is always true: -/// `P = O ∨ qP = O ∧ forall 0 < s < q. sP ≠ O` -/// -/// ## Arithmetics -/// -/// You can add, subtract two points, or multiply point at scalar: -/// -/// ```rust -/// # use curv::elliptic::curves::{PointZ, Scalar, Secp256k1}; -/// fn expression( -/// a: PointZ, -/// b: PointZ, -/// c: Scalar, -/// ) -> PointZ { -/// a + b * c -/// } -/// ``` -#[derive(Serialize, Deserialize)] -#[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] -pub struct PointZ { - raw_point: E::Point, -} - -impl PointZ { - /// Checks if `self` is not zero and converts it into [`Point`](Point). Returns `None` if - /// it's zero. - pub fn ensure_nonzero(self) -> Option> { - Point::try_from(self).ok() - } - - /// Constructs zero point - /// - /// Zero point (or curve neutral element) is usually denoted as `O`. Its property: `forall A. A + O = A`. - /// - /// Weierstrass and Montgomery curves employ special "point at infinity" that represent a neutral - /// element, such points don't have coordinates (i.e. [from_coords], [x_coord], [y_coord] return - /// `None`). Edwards curves' neutral element has coordinates. - /// - /// [from_coords]: Self::from_coords - /// [x_coord]: Self::x_coord - /// [y_coord]: Self::y_coord - pub fn zero() -> Self { - // Safety: `self` can be constructed to hold a zero point - unsafe { Self::from_raw_unchecked(E::Point::zero()) } - } - - /// Checks whether point is zero - pub fn is_zero(&self) -> bool { - self.as_raw().is_zero() - } - - /// Returns point coordinates - /// - /// Point might not have coordinates (specifically, "point at infinity" doesn't), in this case - /// `None` is returned - pub fn coords(&self) -> Option { - self.as_raw().coords() - } - - /// Returns point x coordinate - /// - /// See [coords](Self::coords) method that retrieves both x and y at once. - pub fn x_coord(&self) -> Option { - self.as_raw().x_coord() - } - - /// Returns point y coordinate - /// - /// See [coords](Self::coords) method that retrieves both x and y at once. - pub fn y_coord(&self) -> Option { - self.as_raw().y_coord() - } - - /// Constructs a point from its coordinates, returns error if coordinates don't satisfy - /// curve equation or if point has invalid order - pub fn from_coords(x: &BigInt, y: &BigInt) -> Result { - let raw_point = E::Point::from_coords(x, y) - .map_err(|_: NotOnCurve| PointZFromCoordsError::NotOnCurve)?; - Self::from_raw(raw_point).map_err(PointZFromCoordsError::InvalidPoint) - } - - /// Tries to parse a point in (un)compressed form - /// - /// Whether it's in compressed or uncompressed form will be deduced from its length - pub fn from_bytes(bytes: &[u8]) -> Result { - let p = E::Point::deserialize(bytes) - .map_err(|_: DeserializationError| PointZDeserializationError::DeserializationError)?; - Self::from_raw(p).map_err(PointZDeserializationError::InvalidPoint) - } - - /// Serializes a point in (un)compressed form - /// - /// Returns `None` if it's point at infinity - pub fn to_bytes(&self, compressed: bool) -> Option> { - self.as_raw().serialize(compressed) - } - - /// Constructs a `Point` from low-level [ECPoint] implementor - /// - /// Returns error if point is zero, or its order isn't equal to [group order]. - /// - /// Typically, you don't need to use this constructor. See [generator](Point::generator), - /// [base_point2](Point::base_point2), [from_coords](Self::from_coords), [from_bytes](Self::from_bytes) - /// constructors, and `From` and `TryFrom` traits implemented for `PointZ`. - /// - /// [ECPoint]: crate::elliptic::curves::ECPoint - /// [group order]: crate::elliptic::curves::ECScalar::group_order - pub fn from_raw(raw_point: E::Point) -> Result { - if raw_point.is_zero() || raw_point.check_point_order_equals_group_order() { - Ok(Self { raw_point }) - } else { - Err(MismatchedPointOrder(())) - } - } - - /// Constructs a `PointZ` from low-level [ECPoint] implementor - /// - /// # Safety - /// - /// This function will not perform any checks against the point. You must guarantee that either - /// point order is equal to curve [group order] or it's a zero point. To perform this check, you - /// may use [ECPoint::check_point_order_equals_group_order][check_point_order_equals_group_order] - /// and [ECPoint::is_zero][is_zero] methods. - /// - /// [ECPoint]: crate::elliptic::curves::ECPoint - /// [group order]: crate::elliptic::curves::ECScalar::group_order - /// [check_point_order_equals_group_order]: crate::elliptic::curves::ECPoint::check_point_order_equals_group_order - /// [is_zero]: crate::elliptic::curves::ECPoint::is_zero - pub unsafe fn from_raw_unchecked(raw_point: E::Point) -> Self { - Self { raw_point } - } - - /// Returns a reference to low-level point implementation - /// - /// Typically, you don't need to work with `ECPoint` trait directly. `PointZ` wrapper - /// provides convenient utilities around it: it implements arithmetic operators, (de)serialization - /// traits, various getters (like [`.coords()`](Self::coords). If you believe that some functionality - /// is missing, please [open an issue](https://github.com/ZenGo-X/curv). - pub fn as_raw(&self) -> &E::Point { - &self.raw_point - } - - /// Converts a point into inner low-level point implementation - /// - /// Typically, you don't need to work with `ECPoint` trait directly. `PointZ` wraps `ECPoint` - /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization - /// traits, various getters (like [`.coords()`](Self::coords)). If you believe that some functionality - /// is missing, please [open an issue](https://github.com/ZenGo-X/curv). - pub fn into_raw(self) -> E::Point { - self.raw_point - } -} - -impl PartialEq for PointZ { - fn eq(&self, other: &Self) -> bool { - self.raw_point.eq(&other.raw_point) - } -} - -impl PartialEq> for PointZ { - fn eq(&self, other: &Point) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl<'p, E: Curve> PartialEq> for PointZ { - fn eq(&self, other: &PointRef<'p, E>) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl PartialEq> for PointZ { - fn eq(&self, other: &Generator) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl Clone for PointZ { - fn clone(&self) -> Self { - // Safety: self is guaranteed to have correct order - unsafe { PointZ::from_raw_unchecked(self.as_raw().clone()) } - } -} - -impl fmt::Debug for PointZ { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.raw_point.fmt(f) - } -} - -impl From> for PointZ { - fn from(p: Point) -> Self { - // Safety: `Point` is guaranteed to have correct order - unsafe { PointZ::from_raw_unchecked(p.into_raw()) } - } -} diff --git a/src/elliptic/curves/wrappers/scalar.rs b/src/elliptic/curves/wrappers/scalar.rs index 0b8add77..df314fdc 100644 --- a/src/elliptic/curves/wrappers/scalar.rs +++ b/src/elliptic/curves/wrappers/scalar.rs @@ -1,58 +1,39 @@ -use std::convert::TryFrom; use std::fmt; use serde::{Deserialize, Serialize}; -use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::traits::{Curve, ECScalar}; use crate::BigInt; -use super::{error::ZeroScalarError, format::ScalarFormat, ScalarZ}; +use super::format::ScalarFormat; +use crate::elliptic::curves::ZeroScalarError; -/// Scalar value in a prime field that _guaranteed_ to be non zero -/// -/// ## Security -/// -/// Non-zero scalars are preferred to be used in cryptographic algorithms. Lack of checking whether -/// computation on field scalars results into zero scalar might lead to vulnerability. Using `Scalar` -/// ensures you and reviewers that check on scalar not being zero was made. +/// Scalar value in a prime field /// /// ## Guarantees /// -/// * Belongs to the curve prime field -/// -/// Denoting group order as `n`, any instance `s` of `Scalar` is guaranteed to be less than `n`: -/// `s < n` -/// * Not a zero +/// * Modulus group order /// -/// Any instance `s` of `Scalar` is guaranteed to be more than zero: `s > 0` +/// Denoting [group order](Self::group_order) as `n`, any instance `s` of `Scalar` is guaranteed +/// to be non-negative integer modulo `n`: `0 <= s < n` /// -/// Combining two rules above, any instance `s` of `Scalar` is guaranteed to be: `0 < s < n`. -/// -/// ## Arithmetic +/// ## Arithmetics /// /// Supported operations: -/// * Unary: you can [invert](Self::invert) and negate a scalar by modulo of prime field -/// * Binary: you can add, subtract, and multiply two points +/// * Unary: you can [invert](Self::invert) and negate a scalar +/// * Binary: you can add, subtract, and multiply two scalars /// -/// Addition or subtraction of two (even non-zero) scalars might result into zero -/// scalar, so these operations output [ScalarZ]. Use [ensure_nonzero](ScalarZ::ensure_nonzero) method -/// to ensure that computation doesn't produce zero scalar: +/// ### Example /// -/// ```rust -/// # use curv::elliptic::curves::{ScalarZ, Scalar, Secp256k1}; -/// let a = Scalar::::random(); -/// let b = Scalar::::random(); -/// let result: ScalarZ = a + b; -/// let non_zero_result: Option> = result.ensure_nonzero(); -/// ``` -/// -/// Multiplication of two nonzero scalars is always nonzero scalar (as scalar is by prime modulo): -/// -/// ```rust -/// # use curv::elliptic::curves::{ScalarZ, Scalar, Secp256k1}; -/// let a = Scalar::::random(); -/// let b = Scalar::::random(); -/// let result: Scalar = a * b; +/// ```rust +/// # use curv::elliptic::curves::{Scalar, Secp256k1}; +/// fn expression( +/// a: &Scalar, +/// b: &Scalar, +/// c: &Scalar +/// ) -> Scalar { +/// a + b * c +/// } /// ``` #[derive(Serialize, Deserialize)] #[serde(try_from = "ScalarFormat", into = "ScalarFormat", bound = "")] @@ -61,29 +42,33 @@ pub struct Scalar { } impl Scalar { - /// Samples a random non-zero scalar + /// Ensures that `self` is not zero, returns `Err(_)` otherwise + pub fn ensure_nonzero(&self) -> Result<(), ZeroScalarError> { + if self.is_zero() { + Err(ZeroScalarError::new()) + } else { + Ok(()) + } + } + + /// Samples a random nonzero scalar pub fn random() -> Self { loop { - if let Some(scalar) = ScalarZ::from_raw(E::Scalar::random()).ensure_nonzero() { - break scalar; + let s = E::Scalar::random(); + if !s.is_zero() { + break Scalar::from_raw(s); } } } - /// Returns modular multiplicative inverse of the scalar - /// - /// Inverse of non-zero scalar is always defined in a prime field, and inverted scalar is also - /// guaranteed to be non-zero. - pub fn invert(&self) -> Self { - self.as_raw() - .invert() - .map(|s| Scalar::from_raw(s).expect("inversion must be non-zero")) - .expect("non-zero scalar must have corresponding inversion") + /// Constructs zero scalar + pub fn zero() -> Self { + Self::from_raw(E::Scalar::zero()) } - /// Returns a curve order - pub fn group_order() -> &'static BigInt { - E::Scalar::group_order() + /// Checks if a scalar is zero + pub fn is_zero(&self) -> bool { + self.as_raw().is_zero() } /// Converts a scalar to [BigInt] @@ -91,37 +76,29 @@ impl Scalar { self.as_raw().to_bigint() } - /// Constructs a scalar from [BigInt] or returns error if it's zero - pub fn from_bigint(n: &BigInt) -> Result { + /// Constructs a scalar `n % curve_order` from given `n` + pub fn from_bigint(n: &BigInt) -> Self { Self::from_raw(E::Scalar::from_bigint(n)) } + /// Returns an order of generator point + pub fn group_order() -> &'static BigInt { + E::Scalar::group_order() + } + + /// Returns inversion `self^-1 mod group_order`, or None if `self` is zero + pub fn invert(&self) -> Option { + self.as_raw().invert().map(Self::from_raw) + } + /// Constructs a `Scalar` from low-level [ECScalar] implementor /// - /// Returns error if scalar is zero - /// /// Typically, you don't need to use this constructor. See [random](Self::random), /// [from_bigint](Self::from_bigint) constructors, and `From`, `TryFrom` traits implemented /// for `Scalar`. /// /// [ECScalar]: crate::elliptic::curves::ECScalar - pub fn from_raw(raw_scalar: E::Scalar) -> Result { - if raw_scalar.is_zero() { - Err(ZeroScalarError(())) - } else { - Ok(Self { raw_scalar }) - } - } - - /// Constructs a `Scalar` from low-level [ECScalar] implementor - /// - /// # Safety - /// - /// This function will not perform any checks against the scalar. You must guarantee that scalar - /// is not zero. To perform this check, you may use [ECScalar::is_zero][is_zero] method. - /// - /// [is_zero]: crate::elliptic::curves::ECScalar::is_zero - pub unsafe fn from_raw_unchecked(raw_scalar: E::Scalar) -> Self { + pub fn from_raw(raw_scalar: E::Scalar) -> Self { Self { raw_scalar } } @@ -148,8 +125,7 @@ impl Scalar { impl Clone for Scalar { fn clone(&self) -> Self { - // Safety: `self` is guaranteed to be non-zero - unsafe { Scalar::from_raw_unchecked(self.as_raw().clone()) } + Self::from_raw(self.as_raw().clone()) } } @@ -165,50 +141,38 @@ impl PartialEq for Scalar { } } -impl PartialEq> for Scalar { - fn eq(&self, other: &ScalarZ) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl TryFrom for Scalar { - type Error = ZeroScalarError; - fn try_from(n: u16) -> Result { - Self::from_bigint(&BigInt::from(n)) +impl From for Scalar { + fn from(n: u16) -> Self { + Self::from(&BigInt::from(n)) } } -impl TryFrom for Scalar { - type Error = ZeroScalarError; - fn try_from(n: u32) -> Result { - Self::from_bigint(&BigInt::from(n)) +impl From for Scalar { + fn from(n: u32) -> Self { + Self::from(&BigInt::from(n)) } } -impl TryFrom for Scalar { - type Error = ZeroScalarError; - fn try_from(n: u64) -> Result { - Self::from_bigint(&BigInt::from(n)) +impl From for Scalar { + fn from(n: u64) -> Self { + Self::from(&BigInt::from(n)) } } -impl TryFrom for Scalar { - type Error = ZeroScalarError; - fn try_from(n: i32) -> Result { - Self::from_bigint(&BigInt::from(n)) +impl From for Scalar { + fn from(n: i32) -> Self { + Self::from(&BigInt::from(n)) } } -impl TryFrom<&BigInt> for Scalar { - type Error = ZeroScalarError; - fn try_from(n: &BigInt) -> Result { - Self::from_bigint(n) +impl From<&BigInt> for Scalar { + fn from(n: &BigInt) -> Self { + Scalar::from_raw(E::Scalar::from_bigint(n)) } } -impl TryFrom for Scalar { - type Error = ZeroScalarError; - fn try_from(n: BigInt) -> Result { - Self::from_bigint(&n) +impl From for Scalar { + fn from(n: BigInt) -> Self { + Self::from(&n) } } diff --git a/src/elliptic/curves/wrappers/scalar_z.rs b/src/elliptic/curves/wrappers/scalar_z.rs deleted file mode 100644 index 2a11cfc1..00000000 --- a/src/elliptic/curves/wrappers/scalar_z.rs +++ /dev/null @@ -1,186 +0,0 @@ -use std::fmt; - -use serde::{Deserialize, Serialize}; - -use crate::elliptic::curves::traits::{Curve, ECScalar}; -use crate::BigInt; - -use super::{format::ScalarFormat, Scalar}; - -/// Scalar value in a prime field that **might be zero** -/// -/// ## Security -/// -/// Mistakenly used zero scalar might break security of cryptographic algorithm. It's preferred to -/// use `Scalar`[Scalar] that's guaranteed to be non-zero. Use [ensure_nonzero](ScalarZ::ensure_nonzero) -/// to convert `ScalarZ` into `Scalar`. -/// -/// ## Guarantees -/// -/// * Modulus group order -/// -/// Denoting [group order](Self::group_order) as `n`, any instance `s` of `ScalarZ` is guaranteed -/// to be non-negative integer modulo `n`: `0 <= s < n` -/// -/// ## Arithmetics -/// -/// Supported operations: -/// * Unary: you can [invert](Self::invert) and negate a scalar -/// * Binary: you can add, subtract, and multiply two points -/// -/// ### Example -/// -/// ```rust -/// # use curv::elliptic::curves::{ScalarZ, Secp256k1}; -/// fn expression( -/// a: ScalarZ, -/// b: ScalarZ, -/// c: ScalarZ -/// ) -> ScalarZ { -/// a + b * c -/// } -/// ``` -#[derive(Serialize, Deserialize)] -#[serde(try_from = "ScalarFormat", into = "ScalarFormat", bound = "")] -pub struct ScalarZ { - raw_scalar: E::Scalar, -} - -impl ScalarZ { - /// Converts a scalar into [`Scalar`](ScalarZ) if it's non-zero, returns None otherwise - pub fn ensure_nonzero(self) -> Option> { - Scalar::from_raw(self.into_raw()).ok() - } - - /// Samples a random scalar - pub fn random() -> Self { - Self::from_raw(E::Scalar::random()) - } - - /// Constructs zero scalar - pub fn zero() -> Self { - Self::from_raw(E::Scalar::zero()) - } - - /// Checks if a scalar is zero - pub fn is_zero(&self) -> bool { - self.as_raw().is_zero() - } - - /// Converts a scalar to [BigInt] - pub fn to_bigint(&self) -> BigInt { - self.as_raw().to_bigint() - } - - /// Constructs a scalar `n % curve_order` from give `n` - pub fn from_bigint(n: &BigInt) -> Self { - Self::from_raw(E::Scalar::from_bigint(n)) - } - - /// Returns an order of generator point - pub fn group_order() -> &'static BigInt { - E::Scalar::group_order() - } - - /// Returns inversion `self^-1 mod curve_order`, or None if `self` is zero - pub fn invert(&self) -> Option { - self.as_raw().invert().map(Self::from_raw) - } - - /// Constructs a `ScalarZ` from low-level [ECScalar] implementor - /// - /// Typically, you don't need to use this constructor. See [random](Self::random), - /// [from_bigint](Self::from_bigint) constructors, and `From`, `TryFrom` traits implemented - /// for `ScalarZ`. - /// - /// [ECScalar]: crate::elliptic::curves::ECScalar - pub fn from_raw(raw_scalar: E::Scalar) -> Self { - Self { raw_scalar } - } - - /// Returns a reference to low-level scalar implementation - /// - /// Typically, you don't need to work with `ECScalar` trait directly. `ScalarZ` wraps `ECScalar` - /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization - /// traits, etc. If you believe that some functionality is missing, please - /// [open an issue](https://github.com/ZenGo-X/curv). - pub fn as_raw(&self) -> &E::Scalar { - &self.raw_scalar - } - - /// Converts a scalar into inner low-level scalar implementation - /// - /// Typically, you don't need to work with `ECScalar` trait directly. `ScalarZ` wraps `ECScalar` - /// and provides convenient utilities around it: it implements arithmetic operators, (de)serialization - /// traits, etc. If you believe that some functionality is missing, please - /// [open an issue](https://github.com/ZenGo-X/curv). - pub fn into_raw(self) -> E::Scalar { - self.raw_scalar - } -} - -impl Clone for ScalarZ { - fn clone(&self) -> Self { - Self::from_raw(self.as_raw().clone()) - } -} - -impl fmt::Debug for ScalarZ { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.as_raw().fmt(f) - } -} - -impl PartialEq for ScalarZ { - fn eq(&self, other: &Self) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl PartialEq> for ScalarZ { - fn eq(&self, other: &Scalar) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl From> for ScalarZ { - fn from(scalar: Scalar) -> Self { - ScalarZ::from_raw(scalar.into_raw()) - } -} - -impl From for ScalarZ { - fn from(n: u16) -> Self { - Self::from(&BigInt::from(n)) - } -} - -impl From for ScalarZ { - fn from(n: u32) -> Self { - Self::from(&BigInt::from(n)) - } -} - -impl From for ScalarZ { - fn from(n: u64) -> Self { - Self::from(&BigInt::from(n)) - } -} - -impl From for ScalarZ { - fn from(n: i32) -> Self { - Self::from(&BigInt::from(n)) - } -} - -impl From<&BigInt> for ScalarZ { - fn from(n: &BigInt) -> Self { - ScalarZ::from_raw(E::Scalar::from_bigint(n)) - } -} - -impl From for ScalarZ { - fn from(n: BigInt) -> Self { - Self::from(&n) - } -} From e9c3cace083d6a96b03b2a757f33bb088d6a1243 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 19 Jul 2021 19:24:36 +0300 Subject: [PATCH 68/93] Serialize always succeeds --- .../hashing/blake2b512.rs | 10 +--- src/cryptographic_primitives/hashing/ext.rs | 5 +- .../hashing/hash_sha256.rs | 5 +- .../hashing/hash_sha512.rs | 5 +- .../hashing/merkle_tree.rs | 8 +-- .../dh_key_exchange_variant_with_pok_comm.rs | 37 +++---------- src/elliptic/curves/bls12_381/g1.rs | 19 ++++--- src/elliptic/curves/bls12_381/g2.rs | 19 ++++--- src/elliptic/curves/curve_ristretto.rs | 6 +-- src/elliptic/curves/ed25519.rs | 6 +-- src/elliptic/curves/p256.rs | 10 ++-- src/elliptic/curves/secp256_k1.rs | 54 +++++++------------ src/elliptic/curves/test.rs | 20 ++++--- src/elliptic/curves/traits.rs | 5 +- src/elliptic/curves/wrappers/point.rs | 4 +- src/elliptic/curves/wrappers/point_ref.rs | 4 +- 16 files changed, 82 insertions(+), 135 deletions(-) diff --git a/src/cryptographic_primitives/hashing/blake2b512.rs b/src/cryptographic_primitives/hashing/blake2b512.rs index 0da5064e..2f7d8252 100644 --- a/src/cryptographic_primitives/hashing/blake2b512.rs +++ b/src/cryptographic_primitives/hashing/blake2b512.rs @@ -29,10 +29,7 @@ impl Blake { } pub fn chain_point(&mut self, point: &Point) -> &mut Self { - match point.to_bytes(false) { - Some(bytes) => self.state.update(&bytes), - None => self.state.update(b"point at infinity"), - }; + self.state.update(&point.to_bytes(false)); self } @@ -67,10 +64,7 @@ impl Blake { // let mut digest = Blake2b::with_params(64, &[], &[], persona); for value in ge_vec { - match value.to_bytes(false) { - Some(serialized) => digest.update(&serialized), - None => digest.update(b"infinity point"), - }; + digest.update(&value.to_bytes(false)); } let result = BigInt::from_bytes(digest.finalize().as_ref()); diff --git a/src/cryptographic_primitives/hashing/ext.rs b/src/cryptographic_primitives/hashing/ext.rs index 751d6db6..ce945f6f 100644 --- a/src/cryptographic_primitives/hashing/ext.rs +++ b/src/cryptographic_primitives/hashing/ext.rs @@ -89,10 +89,7 @@ where } fn input_point(&mut self, point: &Point) { - match point.to_bytes(false) { - Some(bytes) => self.input(&bytes), - None => self.input(b"point at infinity"), - } + self.input(&point.to_bytes(false)) } fn input_scalar(&mut self, scalar: &Scalar) { diff --git a/src/cryptographic_primitives/hashing/hash_sha256.rs b/src/cryptographic_primitives/hashing/hash_sha256.rs index a3e7f49d..8637b2e1 100644 --- a/src/cryptographic_primitives/hashing/hash_sha256.rs +++ b/src/cryptographic_primitives/hashing/hash_sha256.rs @@ -34,10 +34,7 @@ impl Hash for HSha256 { fn create_hash_from_ge(ge_vec: &[&Point]) -> Scalar { let mut hasher = Sha256::new(); for value in ge_vec { - match value.to_bytes(false) { - Some(serialized) => hasher.input(&serialized), - None => hasher.input(b"infinity"), - } + hasher.input(&value.to_bytes(false)); } let result_hex = hasher.result(); diff --git a/src/cryptographic_primitives/hashing/hash_sha512.rs b/src/cryptographic_primitives/hashing/hash_sha512.rs index 6eeb653e..c215410f 100644 --- a/src/cryptographic_primitives/hashing/hash_sha512.rs +++ b/src/cryptographic_primitives/hashing/hash_sha512.rs @@ -34,10 +34,7 @@ impl Hash for HSha512 { fn create_hash_from_ge(ge_vec: &[&Point]) -> Scalar { let mut hasher = Sha512::new(); for value in ge_vec { - match value.to_bytes(false) { - Some(serialized) => hasher.input(&serialized), - None => hasher.input(b"infinity"), - } + hasher.input(&value.to_bytes(false)); } let result_hex = hasher.result(); diff --git a/src/cryptographic_primitives/hashing/merkle_tree.rs b/src/cryptographic_primitives/hashing/merkle_tree.rs index 87d62aa6..f1c17559 100644 --- a/src/cryptographic_primitives/hashing/merkle_tree.rs +++ b/src/cryptographic_primitives/hashing/merkle_tree.rs @@ -31,9 +31,7 @@ impl MT256 { let vec_bytes = (0..vec.len()) .map(|i| { let mut array = [0u8; 32]; - let bytes = vec[i] - .to_bytes(false) - .unwrap_or_else(|| b"infinity point".to_vec()); + let bytes = vec[i].to_bytes(false); array.copy_from_slice(&bytes[0..32]); array }) @@ -48,9 +46,7 @@ impl MT256 { pub fn gen_proof_for_ge(&self, value: &Point) -> Proof<[u8; 32]> { let mut array = [0u8; 32]; - let pk_slice = value - .to_bytes(false) - .unwrap_or_else(|| b"infinity point".to_vec()); + let pk_slice = value.to_bytes(false); array.copy_from_slice(&pk_slice[0..32]); MerkleTree::gen_proof::<[u8; 32]>(&self.tree, array).expect("not found in tree") } diff --git a/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs b/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs index 396e0480..b9f2165c 100644 --- a/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs +++ b/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs @@ -77,22 +77,13 @@ impl Party1FirstMessage { // we use hash based commitment let pk_commitment_blind_factor = BigInt::sample(SECURITY_BITS); let pk_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes( - &public_share - .to_bytes(true) - .expect("public_share guaranteed to be nonzero"), - ), + &BigInt::from_bytes(&public_share.to_bytes(true)), &pk_commitment_blind_factor, ); let zk_pok_blind_factor = BigInt::sample(SECURITY_BITS); let zk_pok_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes( - &d_log_proof - .pk_t_rand_commitment - .to_bytes(true) - .unwrap_or_else(|| vec![0]), - ), + &BigInt::from_bytes(&d_log_proof.pk_t_rand_commitment.to_bytes(true)), &zk_pok_blind_factor, ); let ec_key_pair = EcKeyPair { @@ -124,22 +115,13 @@ impl Party1FirstMessage { let pk_commitment_blind_factor = BigInt::sample(SECURITY_BITS); let pk_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes( - &public_share - .to_bytes(true) - .expect("public_share guaranteed to be nonzero"), - ), + &BigInt::from_bytes(&public_share.to_bytes(true)), &pk_commitment_blind_factor, ); let zk_pok_blind_factor = BigInt::sample(SECURITY_BITS); let zk_pok_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes( - &d_log_proof - .pk_t_rand_commitment - .to_bytes(true) - .unwrap_or_else(|| vec![0]), - ), + &BigInt::from_bytes(&d_log_proof.pk_t_rand_commitment.to_bytes(true)), &zk_pok_blind_factor, ); @@ -232,9 +214,7 @@ impl Party2SecondMessage { let mut flag = true; if party_one_pk_commitment != &HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&party_one_public_share.to_bytes(true).expect( - "party_one_public_share guaranteed to be nonzero by if statement above", - )), + &BigInt::from_bytes(&party_one_public_share.to_bytes(true)), &party_one_pk_commitment_blind_factor, ) { @@ -243,12 +223,7 @@ impl Party2SecondMessage { if party_one_zk_pok_commitment != &HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes( - &party_one_d_log_proof - .pk_t_rand_commitment - .to_bytes(true) - .unwrap_or_else(|| vec![0]), - ), + &BigInt::from_bytes(&party_one_d_log_proof.pk_t_rand_commitment.to_bytes(true)), &party_one_zk_pok_blind_factor, ) { diff --git a/src/elliptic/curves/bls12_381/g1.rs b/src/elliptic/curves/bls12_381/g1.rs index 74ef03bd..ee694684 100644 --- a/src/elliptic/curves/bls12_381/g1.rs +++ b/src/elliptic/curves/bls12_381/g1.rs @@ -152,18 +152,23 @@ impl ECPoint for G1Point { } } - fn serialize(&self, compressed: bool) -> Option> { + fn serialize(&self, compressed: bool) -> Vec { if self.is_zero() { - None + vec![0] } else if compressed { - Some(G1Compressed::from_affine(self.ge).as_ref().to_vec()) + G1Compressed::from_affine(self.ge).as_ref().to_vec() } else { - Some(G1Uncompressed::from_affine(self.ge).as_ref().to_vec()) + G1Uncompressed::from_affine(self.ge).as_ref().to_vec() } } fn deserialize(bytes: &[u8]) -> Result { - if bytes.len() == COMPRESSED_SIZE { + if bytes == &[0] { + Ok(G1Point { + purpose: "deserialize", + ge: Self::zero().ge, + }) + } else if bytes.len() == COMPRESSED_SIZE { let mut compressed = G1Compressed::empty(); compressed.as_mut().copy_from_slice(bytes); Ok(G1Point { @@ -263,9 +268,7 @@ impl fmt::Debug for G1Point { f, "Point {{ purpose: {:?}, uncompressed: {:?} }}", self.purpose, - self.serialize(false) - .map(hex::encode) - .unwrap_or_else(|| "infinity".to_string()), + hex::encode(self.serialize(false)), ) } } diff --git a/src/elliptic/curves/bls12_381/g2.rs b/src/elliptic/curves/bls12_381/g2.rs index 48ff8204..2f185598 100644 --- a/src/elliptic/curves/bls12_381/g2.rs +++ b/src/elliptic/curves/bls12_381/g2.rs @@ -161,18 +161,23 @@ impl ECPoint for G2Point { } } - fn serialize(&self, compressed: bool) -> Option> { + fn serialize(&self, compressed: bool) -> Vec { if self.is_zero() { - None + vec![0] } else if compressed { - Some(G2Compressed::from_affine(self.ge).as_ref().to_vec()) + G2Compressed::from_affine(self.ge).as_ref().to_vec() } else { - Some(G2Uncompressed::from_affine(self.ge).as_ref().to_vec()) + G2Uncompressed::from_affine(self.ge).as_ref().to_vec() } } fn deserialize(bytes: &[u8]) -> Result { - if bytes.len() == COMPRESSED_SIZE { + if bytes == &[0] { + Ok(G2Point { + purpose: "deserialize", + ge: Self::zero().ge, + }) + } else if bytes.len() == COMPRESSED_SIZE { let mut compressed = G2Compressed::empty(); compressed.as_mut().copy_from_slice(bytes); Ok(G2Point { @@ -272,9 +277,7 @@ impl fmt::Debug for G2Point { f, "Point {{ purpose: {:?}, uncompressed: {:?} }}", self.purpose, - self.serialize(false) - .map(hex::encode) - .unwrap_or_else(|| "infinity".to_string()), + hex::encode(self.serialize(false)), ) } } diff --git a/src/elliptic/curves/curve_ristretto.rs b/src/elliptic/curves/curve_ristretto.rs index 8a880abb..ae41fd6f 100644 --- a/src/elliptic/curves/curve_ristretto.rs +++ b/src/elliptic/curves/curve_ristretto.rs @@ -34,7 +34,7 @@ lazy_static::lazy_static! { static ref BASE_POINT2: RistrettoPoint = { let g = RistrettoPoint::generator(); - let hash = Sha256::digest(&g.serialize(true).unwrap()); + let hash = Sha256::digest(&g.serialize(true)); RistrettoPoint { purpose: "base_point2", ge: RistrettoPoint::deserialize(&hash).unwrap().ge, @@ -274,8 +274,8 @@ impl ECPoint for RistrettoPoint { }) } - fn serialize(&self, _compressed: bool) -> Option> { - Some(self.ge.compress().to_bytes().to_vec()) + fn serialize(&self, _compressed: bool) -> Vec { + self.ge.compress().to_bytes().to_vec() } fn deserialize(bytes: &[u8]) -> Result { let mut buffer = [0u8; 32]; diff --git a/src/elliptic/curves/ed25519.rs b/src/elliptic/curves/ed25519.rs index e478d170..9dfa08ec 100644 --- a/src/elliptic/curves/ed25519.rs +++ b/src/elliptic/curves/ed25519.rs @@ -52,7 +52,7 @@ lazy_static::lazy_static! { }; static ref BASE_POINT2: Ed25519Point = { - let bytes = GENERATOR.serialize(true).unwrap(); + let bytes = GENERATOR.serialize(true); let hashed = sha2::Sha256::digest(&bytes); let hashed_twice = sha2::Sha256::digest(&hashed); let p = Ed25519Point::deserialize(&hashed_twice).unwrap(); @@ -338,8 +338,8 @@ impl ECPoint for Ed25519Point { Some(PointCoords { x: xrecover(&y), y }) } - fn serialize(&self, _compress: bool) -> Option> { - Some(self.ge.to_bytes().to_vec()) + fn serialize(&self, _compress: bool) -> Vec { + self.ge.to_bytes().to_vec() } fn deserialize(bytes: &[u8]) -> Result { diff --git a/src/elliptic/curves/p256.rs b/src/elliptic/curves/p256.rs index a89d07ba..d61da9b9 100644 --- a/src/elliptic/curves/p256.rs +++ b/src/elliptic/curves/p256.rs @@ -281,12 +281,8 @@ impl ECPoint for Secp256r1Point { Some(PointCoords { x, y }) } - fn serialize(&self, compressed: bool) -> Option> { - if self.is_zero() { - None - } else { - Some(self.ge.to_encoded_point(compressed).to_bytes().into()) - } + fn serialize(&self, compressed: bool) -> Vec { + self.ge.to_encoded_point(compressed).to_bytes().into() } fn deserialize(bytes: &[u8]) -> Result { @@ -378,7 +374,7 @@ mod tests { let base_point2 = GE::base_point2(); let g = GE::generator(); - let hash = Sha256::digest(&g.serialize(true).unwrap()); + let hash = Sha256::digest(&g.serialize(true)); let hash = Sha256::digest(&hash); assert_eq!(BigInt::from_bytes(&hash), base_point2.x_coord().unwrap()); diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 71c63425..729c6272 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -371,45 +371,31 @@ impl ECPoint for Secp256k1Point { } } - fn serialize(&self, compressed: bool) -> Option> { - let ge = self.ge.as_ref()?; + fn serialize(&self, compressed: bool) -> Vec { + let ge = match &self.ge { + Some(pk) => pk, + None => return vec![0], + }; if compressed { - Some(ge.serialize().to_vec()) + ge.serialize().to_vec() } else { - // TODO: why not using ge.serialize_uncompressed()? - // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.PublicKey.html#method.serialize_uncompressed - let mut v = vec![4_u8]; - let x_vec = BigInt::to_bytes( - &self - .x_coord() - .expect("guaranteed by the first line of this function"), - ); - let y_vec = BigInt::to_bytes( - &self - .y_coord() - .expect("guaranteed by the first line of this function"), - ); - - let mut raw_x: Vec = Vec::new(); - let mut raw_y: Vec = Vec::new(); - raw_x.extend(vec![0u8; 32 - x_vec.len()]); - raw_x.extend(x_vec); - - raw_y.extend(vec![0u8; 32 - y_vec.len()]); - raw_y.extend(y_vec); - - v.extend(raw_x); - v.extend(raw_y); - Some(v) + ge.serialize_uncompressed().to_vec() } } fn deserialize(bytes: &[u8]) -> Result { - let pk = PublicKey::from_slice(bytes).map_err(|_| DeserializationError)?; - Ok(Secp256k1Point { - purpose: "from_bytes", - ge: Some(PK(pk)), - }) + if bytes == &[0] { + Ok(Secp256k1Point { + purpose: "from_bytes", + ge: None, + }) + } else { + let pk = PublicKey::from_slice(bytes).map_err(|_| DeserializationError)?; + Ok(Secp256k1Point { + purpose: "from_bytes", + ge: Some(PK(pk)), + }) + } } fn check_point_order_equals_group_order(&self) -> bool { @@ -607,7 +593,7 @@ mod test { let base_point2 = GE::base_point2(); let g = GE::generator(); - let hash = Sha256::digest(&g.serialize(true).unwrap()); + let hash = Sha256::digest(&g.serialize(true)); let hash = Sha256::digest(&hash); let hash = Sha256::digest(&hash); diff --git a/src/elliptic/curves/test.rs b/src/elliptic/curves/test.rs index 010ce2b7..33bd64a3 100644 --- a/src/elliptic/curves/test.rs +++ b/src/elliptic/curves/test.rs @@ -81,19 +81,27 @@ fn point_addition_multiplication() { test_for_all_curves!(serialize_deserialize); fn serialize_deserialize() { let point = ::generator().scalar_mul(&random_nonzero_scalar()); - let bytes = point - .serialize(true) - .expect("point has coordinates => must be serializable"); + let bytes = point.serialize(true); let deserialized = ::deserialize(&bytes).unwrap(); assert_eq!(point, deserialized); - let bytes = point - .serialize(false) - .expect("point has coordinates => must be serializable"); + let bytes = point.serialize(false); let deserialized = E::Point::deserialize(&bytes).unwrap(); assert_eq!(point, deserialized); } +test_for_all_curves!(zero_point_serialization); +fn zero_point_serialization() { + let point: E::Point = ECPoint::zero(); + let bytes = point.serialize(true); + let point_from_compressed: E::Point = ECPoint::deserialize(&bytes).unwrap(); + assert_eq!(point, point_from_compressed); + + let bytes = point.serialize(false); + let point_from_uncompressed: E::Point = ECPoint::deserialize(&bytes).unwrap(); + assert_eq!(point, point_from_uncompressed); +} + test_for_all_curves!(generator_mul_curve_order_is_zero); fn generator_mul_curve_order_is_zero() { let g: &E::Point = ECPoint::generator(); diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 4a182c09..5e436809 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -147,9 +147,8 @@ pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug + 'static { /// Serializes point into bytes either in compressed or uncompressed form /// - /// Returns None if point doesn't have coordinates, ie. it is "at infinity". If point isn't - /// at infinity, serialize always succeeds. - fn serialize(&self, compressed: bool) -> Option>; + /// Serialization must always succeed even if it's point at infinity. + fn serialize(&self, compressed: bool) -> Vec; /// Deserializes point from bytes /// /// Whether point in compressed or uncompressed form will be deducted from its size diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index c57180b4..4db26481 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -154,9 +154,7 @@ impl Point { } /// Serializes a point in (un)compressed form - /// - /// Returns `None` if it's point at infinity - pub fn to_bytes(&self, compressed: bool) -> Option> { + pub fn to_bytes(&self, compressed: bool) -> Vec { self.as_raw().serialize(compressed) } diff --git a/src/elliptic/curves/wrappers/point_ref.rs b/src/elliptic/curves/wrappers/point_ref.rs index affa6409..9239f5b7 100644 --- a/src/elliptic/curves/wrappers/point_ref.rs +++ b/src/elliptic/curves/wrappers/point_ref.rs @@ -53,9 +53,7 @@ where } /// Serializes point into (un)compressed form - /// - /// Returns `None` if it's point at infinity - pub fn to_bytes(self, compressed: bool) -> Option> { + pub fn to_bytes(self, compressed: bool) -> Vec { self.as_raw().serialize(compressed) } From 595dc897fc3dfd20e764b1ca076e1ab22cfea870 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 19 Jul 2021 19:31:53 +0300 Subject: [PATCH 69/93] Update doc --- src/elliptic/curves/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index b45f400d..9bbcc41f 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -4,7 +4,7 @@ //! //! ## Usage //! -//! Elliptic curve cryptography operates on points and scalars. We provide respective structures +//! Elliptic curve cryptography involves points and scalars. We provide respective structures //! [Point\](Point), [Scalar\](Scalar), where generic `E` stands for choice of elliptic //! curve, e.g. [Secp256k1] (`Point`, `Scalar`). //! @@ -46,8 +46,9 @@ //! //! You may have noticed that this function lacks of subgroup check (whether counterparty //! point has order=group_order), and is vulnerable to [small subgroup attack][subgroup-attack]. -//! Actually, **it isn't**! Any `Point` instance is guaranteed to have large prime order, -//! so you can be sure that subgroup check was performed. See [guarantees section] to learn more. +//! Actually, **it isn't**! Any `Point` instance is guaranteed to have large prime order (unless +//! it's zero point), so you can be sure that subgroup check was performed. See [guarantees section] +//! to learn more. //! //! [subgroup-attack]: http://safecurves.cr.yp.to/twist.html //! [Guarantees section]: Point#guarantees From 4cbec3d48b22bcad8d53ef6dbd81afb8895afc69 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 19 Jul 2021 19:33:36 +0300 Subject: [PATCH 70/93] Fix clippy warning --- src/elliptic/curves/bls12_381/g1.rs | 2 +- src/elliptic/curves/bls12_381/g2.rs | 2 +- src/elliptic/curves/secp256_k1.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/elliptic/curves/bls12_381/g1.rs b/src/elliptic/curves/bls12_381/g1.rs index ee694684..e4e9f7c1 100644 --- a/src/elliptic/curves/bls12_381/g1.rs +++ b/src/elliptic/curves/bls12_381/g1.rs @@ -163,7 +163,7 @@ impl ECPoint for G1Point { } fn deserialize(bytes: &[u8]) -> Result { - if bytes == &[0] { + if bytes == [0] { Ok(G1Point { purpose: "deserialize", ge: Self::zero().ge, diff --git a/src/elliptic/curves/bls12_381/g2.rs b/src/elliptic/curves/bls12_381/g2.rs index 2f185598..b38b8432 100644 --- a/src/elliptic/curves/bls12_381/g2.rs +++ b/src/elliptic/curves/bls12_381/g2.rs @@ -172,7 +172,7 @@ impl ECPoint for G2Point { } fn deserialize(bytes: &[u8]) -> Result { - if bytes == &[0] { + if bytes == [0] { Ok(G2Point { purpose: "deserialize", ge: Self::zero().ge, diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 729c6272..9fc4891b 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -384,7 +384,7 @@ impl ECPoint for Secp256k1Point { } fn deserialize(bytes: &[u8]) -> Result { - if bytes == &[0] { + if bytes == [0] { Ok(Secp256k1Point { purpose: "from_bytes", ge: None, From 0a0a5403acd38bfe1b942c196c218fd7de50b655 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 20 Jul 2021 14:40:49 +0300 Subject: [PATCH 71/93] VerifiableSS returns polynomial used to derive secret shares --- .../secret_sharing/feldman_vss.rs | 59 +++++++++++++++---- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs index fb70d25b..ad59d46b 100644 --- a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs +++ b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs @@ -7,6 +7,7 @@ */ use std::convert::{TryFrom, TryInto}; +use std::{fmt, ops}; use serde::{Deserialize, Serialize}; @@ -32,6 +33,21 @@ pub struct VerifiableSS { pub commitments: Vec>, } +/// Shared secret produced by [VerifiableSS::share] +/// +/// After you shared your secret, you need to distribute `shares` among other parties, and erase +/// secret from your memory (SharedSecret zeroizes on drop). +/// +/// You can retrieve a [polynomial](Self::polynomial) that was used to derive secret shares. It is +/// only needed to combine with other proofs (e.g. [low degree exponent interpolation]). +/// +/// [low degree exponent interpolation]: crate::cryptographic_primitives::proofs::low_degree_exponent_interpolation +#[derive(Clone)] +pub struct SecretShares { + shares: Vec>, + polynomial: Polynomial, +} + impl VerifiableSS { pub fn reconstruct_limit(&self) -> usize { self.parameters.threshold + 1 @@ -39,16 +55,16 @@ impl VerifiableSS { // TODO: share should accept u16 rather than usize // generate VerifiableSS from a secret - pub fn share(t: usize, n: usize, secret: &Scalar) -> (VerifiableSS, Vec>) { + pub fn share(t: usize, n: usize, secret: &Scalar) -> (VerifiableSS, SecretShares) { assert!(t < n); let t = u16::try_from(t).unwrap(); let n = u16::try_from(n).unwrap(); - let poly = Polynomial::::sample_exact_with_fixed_const_term(t, secret.clone()); - let secret_shares = poly.evaluate_many_bigint(1..=n).collect(); + let polynomial = Polynomial::::sample_exact_with_fixed_const_term(t, secret.clone()); + let shares = polynomial.evaluate_many_bigint(1..=n).collect(); let g = Point::::generator(); - let commitments = poly + let commitments = polynomial .coefficients() .iter() .map(|coef| g * coef) @@ -61,7 +77,7 @@ impl VerifiableSS { }, commitments, }, - secret_shares, + SecretShares { shares, polynomial }, ) } @@ -97,18 +113,18 @@ impl VerifiableSS { n: usize, secret: &Scalar, index_vec: &[usize], - ) -> (VerifiableSS, Vec>) { + ) -> (VerifiableSS, SecretShares) { assert_eq!(n, index_vec.len()); // TODO: share_at_indices should accept u16 rather than usize (t, n, index_vec) let t = u16::try_from(t).unwrap(); let n = u16::try_from(n).unwrap(); let index_vec = index_vec.iter().map(|&i| u16::try_from(i).unwrap()); - let poly = Polynomial::::sample_exact_with_fixed_const_term(t, secret.clone()); - let secret_shares = poly.evaluate_many_bigint(index_vec).collect(); + let polynomial = Polynomial::::sample_exact_with_fixed_const_term(t, secret.clone()); + let shares = polynomial.evaluate_many_bigint(index_vec).collect(); let g = Point::::generator(); - let commitments = poly + let commitments = polynomial .coefficients() .iter() .map(|coef| g * coef) @@ -121,7 +137,7 @@ impl VerifiableSS { }, commitments, }, - secret_shares, + SecretShares { shares, polynomial }, ) } @@ -241,7 +257,7 @@ impl VerifiableSS { // assert!(s_len > self.reconstruct_limit()); // add one to indices to get points let points: Vec> = (0..params.share_count) - .map(|i| Scalar::try_from(i as u32 + 1).expect("guaranteed to be positive")) + .map(|i| Scalar::from(i as u32 + 1)) .collect(); let xi = &points[index]; @@ -267,6 +283,27 @@ impl VerifiableSS { } } +impl SecretShares { + /// Polynomial that was used to derive secret shares + pub fn polynomial(&self) -> &Polynomial { + &self.polynomial + } +} + +impl fmt::Debug for SecretShares { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // blind sensitive data stored by the structure + write!(f, "SecretShares{{ ... }}") + } +} + +impl ops::Deref for SecretShares { + type Target = [Scalar]; + fn deref(&self) -> &Self::Target { + &self.shares + } +} + #[cfg(test)] mod tests { use super::*; From 2a75890edd23096f3adf34d77e72b99f1fd629ba Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 20 Jul 2021 16:51:26 +0300 Subject: [PATCH 72/93] Fix documentation --- src/elliptic/curves/wrappers/point.rs | 3 ++- src/elliptic/curves/wrappers/point_ref.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index 4db26481..ac94d641 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -160,7 +160,8 @@ impl Point { /// Constructs a `Point` from low-level [ECPoint] implementor /// - /// Returns error if point is zero, or its order isn't equal to [group order]. + /// Returns error if point is not valid. Valid point is either a zero point, or a point of + /// [group order]. /// /// Typically, you don't need to use this constructor. See [generator](Point::generator), /// [base_point2](Point::base_point2), [from_coords](Self::from_coords), [from_bytes](Self::from_bytes) diff --git a/src/elliptic/curves/wrappers/point_ref.rs b/src/elliptic/curves/wrappers/point_ref.rs index 9239f5b7..4f705fb9 100644 --- a/src/elliptic/curves/wrappers/point_ref.rs +++ b/src/elliptic/curves/wrappers/point_ref.rs @@ -65,7 +65,8 @@ where /// Constructs a `PointRef` from reference to low-level [ECPoint] implementor /// - /// Returns error if point is zero, or its order isn't equal to [group order]. + /// Returns error if point is not valid. Valid point is either a zero point, or a point of + /// [group order]. /// /// Typically, you don't need to use this constructor. See [generator](Point::generator), /// [base_point2](Point::base_point2) constructors, and `From` and `TryFrom` traits From 8fe5ea419057950e9ed4ddfb665a6c90a3517fa2 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 20 Jul 2021 18:04:47 +0300 Subject: [PATCH 73/93] Optimize elliptic curves implementations --- src/arithmetic/traits.rs | 25 +- src/elliptic/curves/bls12_381/g1.rs | 21 +- src/elliptic/curves/bls12_381/g2.rs | 25 +- src/elliptic/curves/bls12_381/scalar.rs | 23 +- src/elliptic/curves/curve_ristretto.rs | 71 ++---- src/elliptic/curves/ed25519.rs | 1 - src/elliptic/curves/mod.rs | 2 +- src/elliptic/curves/p256.rs | 76 ++---- src/elliptic/curves/secp256_k1.rs | 298 ++++++++---------------- 9 files changed, 199 insertions(+), 343 deletions(-) diff --git a/src/arithmetic/traits.rs b/src/arithmetic/traits.rs index 544bc1c6..b4252281 100644 --- a/src/arithmetic/traits.rs +++ b/src/arithmetic/traits.rs @@ -48,6 +48,29 @@ pub trait Converter: Sized { /// ``` fn from_bytes(bytes: &[u8]) -> Self; + /// Returns bytes representation of the number in an array with length chosen by the user + /// if the array is larger than the bytes it pads it with zeros in the most significant bytes + /// If the array is too small for the integer it returns None. + /// + /// ## Examples + /// ``` + /// # use curv::arithmetic::{BigInt, Converter}; + /// assert_eq!(BigInt::from(31).to_bytes_array(), Some([31])); + /// assert_eq!(BigInt::from(31).to_bytes_array(), Some([0, 31])); + /// assert_eq!(BigInt::from(1_000_000).to_bytes_array(), Some([15, 66, 64])); + /// assert_eq!(BigInt::from(1_000_000).to_bytes_array::<2>(), None); + /// assert_eq!(BigInt::from(1_000_000).to_bytes_array(), Some([0, 15, 66, 64])); + /// ``` + fn to_bytes_array(&self) -> Option<[u8; N]> { + let bytes = self.to_bytes(); + if bytes.len() > N { + return None; + } + let mut array = [0u8; N]; + array[N - bytes.len()..].copy_from_slice(&bytes); + Some(array) + } + /// Converts BigInt to hex representation. /// /// If the number is negative, it will be serialized by absolute value, and minus character @@ -160,7 +183,7 @@ pub trait Samplable { pub trait NumberTests { /// Returns `true` if `n` is zero /// - /// Alternatively, [BasicOps::sign] method can be used to check sign of the number. + /// Alternatively, [BasicOps::sign] method can be used to check sign of the number. fn is_zero(n: &Self) -> bool; /// Returns `true` if `n` is negative /// diff --git a/src/elliptic/curves/bls12_381/g1.rs b/src/elliptic/curves/bls12_381/g1.rs index e4e9f7c1..760a18ff 100644 --- a/src/elliptic/curves/bls12_381/g1.rs +++ b/src/elliptic/curves/bls12_381/g1.rs @@ -92,21 +92,16 @@ impl ECPoint for G1Point { } fn from_coords(x: &BigInt, y: &BigInt) -> Result { - let x = x.to_bytes(); - let y = y.to_bytes(); - - let mut uncompressed = [0u8; COMPRESSED_SIZE * 2]; - if x.len() <= COMPRESSED_SIZE { - uncompressed[COMPRESSED_SIZE - x.len()..COMPRESSED_SIZE].copy_from_slice(&x) - } else { - return Err(NotOnCurve); - } - - if y.len() <= COMPRESSED_SIZE { - uncompressed[2 * COMPRESSED_SIZE - y.len()..2 * COMPRESSED_SIZE].copy_from_slice(&y) - } else { + let vec_x = x.to_bytes(); + let vec_y = y.to_bytes(); + if vec_x.len() > COMPRESSED_SIZE || vec_y.len() > COMPRESSED_SIZE { return Err(NotOnCurve); } + let mut uncompressed = [0u8; 2 * COMPRESSED_SIZE]; + uncompressed[COMPRESSED_SIZE - vec_x.len()..COMPRESSED_SIZE].copy_from_slice(&vec_x); + uncompressed[(2 * COMPRESSED_SIZE) - vec_y.len()..].copy_from_slice(&vec_y); + debug_assert_eq!(x, &BigInt::from_bytes(&uncompressed[..COMPRESSED_SIZE])); + debug_assert_eq!(y, &BigInt::from_bytes(&uncompressed[COMPRESSED_SIZE..])); let mut point = G1Uncompressed::empty(); point.as_mut().copy_from_slice(&uncompressed); diff --git a/src/elliptic/curves/bls12_381/g2.rs b/src/elliptic/curves/bls12_381/g2.rs index b38b8432..abf19053 100644 --- a/src/elliptic/curves/bls12_381/g2.rs +++ b/src/elliptic/curves/bls12_381/g2.rs @@ -8,9 +8,7 @@ use std::fmt; use ff_zeroize::{PrimeField, ScalarEngine}; -use pairing_plus::bls12_381::G2Compressed; -use pairing_plus::bls12_381::G2Uncompressed; -use pairing_plus::bls12_381::G2; +use pairing_plus::bls12_381::{G2Compressed, G2Uncompressed, G2}; use pairing_plus::hash_to_curve::HashToCurve; use pairing_plus::hash_to_field::ExpandMsgXmd; use pairing_plus::{CurveAffine, CurveProjective, Engine}; @@ -101,21 +99,16 @@ impl ECPoint for G2Point { } fn from_coords(x: &BigInt, y: &BigInt) -> Result { - let x = x.to_bytes(); - let y = y.to_bytes(); - - let mut uncompressed = [0u8; COMPRESSED_SIZE * 2]; - if x.len() <= COMPRESSED_SIZE { - uncompressed[COMPRESSED_SIZE - x.len()..COMPRESSED_SIZE].copy_from_slice(&x) - } else { - return Err(NotOnCurve); - } - - if y.len() <= COMPRESSED_SIZE { - uncompressed[2 * COMPRESSED_SIZE - y.len()..2 * COMPRESSED_SIZE].copy_from_slice(&y) - } else { + let vec_x = x.to_bytes(); + let vec_y = y.to_bytes(); + if vec_x.len() > COMPRESSED_SIZE || vec_y.len() > COMPRESSED_SIZE { return Err(NotOnCurve); } + let mut uncompressed = [0u8; 2 * COMPRESSED_SIZE]; + uncompressed[COMPRESSED_SIZE - vec_x.len()..COMPRESSED_SIZE].copy_from_slice(&vec_x); + uncompressed[(2 * COMPRESSED_SIZE) - vec_y.len()..].copy_from_slice(&vec_y); + debug_assert_eq!(x, &BigInt::from_bytes(&uncompressed[..COMPRESSED_SIZE])); + debug_assert_eq!(y, &BigInt::from_bytes(&uncompressed[COMPRESSED_SIZE..])); let mut point = G2Uncompressed::empty(); point.as_mut().copy_from_slice(&uncompressed); diff --git a/src/elliptic/curves/bls12_381/scalar.rs b/src/elliptic/curves/bls12_381/scalar.rs index 6392a893..4f2669fc 100644 --- a/src/elliptic/curves/bls12_381/scalar.rs +++ b/src/elliptic/curves/bls12_381/scalar.rs @@ -1,8 +1,7 @@ use std::fmt; -use std::io::Cursor; use ff_zeroize::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; -use pairing_plus::bls12_381::Fr; +use pairing_plus::bls12_381::{Fr, FrRepr}; use rand::rngs::OsRng; use zeroize::Zeroizing; @@ -54,17 +53,13 @@ impl ECScalar for FieldScalar { } fn from_bigint(n: &BigInt) -> FieldScalar { - let n_mod = BigInt::modulus(n, &FieldScalar::group_order()); - let n_mod = n_mod.to_bytes(); - let mut bytes_array = [0u8; SECRET_KEY_SIZE]; - if n_mod.len() < SECRET_KEY_SIZE { - bytes_array[SECRET_KEY_SIZE - n_mod.len()..].copy_from_slice(&n_mod) - } else { - bytes_array.copy_from_slice(&n_mod[..SECRET_KEY_SIZE]) - } + let bytes = n + .modulus(Self::group_order()) + .to_bytes_array::() + .expect("n mod curve_order must be equal or less than 32 bytes"); - let mut repr = SK::default().into_repr(); - repr.read_be(Cursor::new(&bytes_array[..])).unwrap(); + let mut repr = FrRepr::default(); + repr.read_be(bytes.as_ref()).unwrap(); FieldScalar { purpose: "from_bigint", fe: Fr::from_repr(repr).unwrap().into(), @@ -73,8 +68,8 @@ impl ECScalar for FieldScalar { fn to_bigint(&self) -> BigInt { let repr = self.fe.into_repr(); - let mut bytes = vec![]; - repr.write_be(&mut bytes).unwrap(); + let mut bytes = [0u8; SECRET_KEY_SIZE]; + repr.write_be(&mut bytes[..]).unwrap(); BigInt::from_bytes(&bytes) } diff --git a/src/elliptic/curves/curve_ristretto.rs b/src/elliptic/curves/curve_ristretto.rs index ae41fd6f..62b8e1e3 100644 --- a/src/elliptic/curves/curve_ristretto.rs +++ b/src/elliptic/curves/curve_ristretto.rs @@ -6,6 +6,7 @@ License MIT: */ +use std::convert::TryInto; use std::ptr; use std::sync::atomic; @@ -89,38 +90,15 @@ impl ECScalar for RistrettoScalar { } fn from_bigint(n: &BigInt) -> RistrettoScalar { - let mut v = BigInt::to_bytes(n); - //TODO: add consistency check for sizes max 32/ max 64 - let mut bytes_array_32: [u8; 32]; - let mut bytes_array_64: [u8; 64]; - if v.len() < SECRET_KEY_SIZE { - let mut template = vec![0; SECRET_KEY_SIZE - v.len()]; - template.extend_from_slice(&v); - v = template; - } else if v.len() > SECRET_KEY_SIZE && v.len() < 2 * SECRET_KEY_SIZE { - let mut template = vec![0; 2 * SECRET_KEY_SIZE - v.len()]; - template.extend_from_slice(&v); - v = template; - } - - if v.len() == SECRET_KEY_SIZE { - bytes_array_32 = [0; SECRET_KEY_SIZE]; - let bytes = &v[..]; - bytes_array_32.copy_from_slice(&bytes); - bytes_array_32.reverse(); - RistrettoScalar { - purpose: "from_bigint", - fe: SK::from_bytes_mod_order(bytes_array_32).into(), - } - } else { - bytes_array_64 = [0; 2 * SECRET_KEY_SIZE]; - let bytes = &v[..]; - bytes_array_64.copy_from_slice(&bytes); - bytes_array_64.reverse(); - RistrettoScalar { - purpose: "from_bigint", - fe: SK::from_bytes_mod_order_wide(&bytes_array_64).into(), - } + let curve_order = RistrettoScalar::group_order(); + let mut bytes = n + .modulus(&curve_order) + .to_bytes_array::<32>() + .expect("n mod curve_order must be equal or less than 32 bytes"); + bytes.reverse(); + RistrettoScalar { + purpose: "from_bigint", + fe: SK::from_bytes_mod_order(bytes).into(), } } @@ -227,23 +205,13 @@ impl ECPoint for RistrettoPoint { } fn from_coords(x: &BigInt, y: &BigInt) -> Result { - if x != &BigInt::from_bytes(&Sha256::digest(&y.to_bytes())) { + let mut y_bytes = y.to_bytes_array::<32>().ok_or(NotOnCurve)?; + if x != &BigInt::from_bytes(&Sha256::digest(&y_bytes)) { return Err(NotOnCurve); } - let y = y.to_bytes(); - let mut y = match y.len() { - 32 => y, - n if n < 32 => { - let mut padded = vec![0u8; 32 - y.len()]; - padded.extend_from_slice(&y); - padded - } - _ => y[y.len() - 32..].to_vec(), - }; - - y.reverse(); - let compressed = CompressedRistretto::from_slice(&y); + y_bytes.reverse(); + let compressed = CompressedRistretto::from_slice(&y_bytes); Ok(RistrettoPoint { purpose: "from_coords", @@ -254,7 +222,10 @@ impl ECPoint for RistrettoPoint { fn x_coord(&self) -> Option { // Underlying library intentionally hides x coordinate. We return x=hash(y) as was proposed // here: https://github.com/dalek-cryptography/curve25519-dalek/issues/235 - let y = self.y_coord()?.to_bytes(); + let y = self + .y_coord()? + .to_bytes_array::<32>() + .expect("y coordinate is mod n, meaning it must be <= 32 bytes"); let x = Sha256::digest(&y); Some(BigInt::from_bytes(&x)) } @@ -267,7 +238,10 @@ impl ECPoint for RistrettoPoint { fn coords(&self) -> Option { let y = self.y_coord()?; - let x = Sha256::digest(&y.to_bytes()); + let y_bytes = y + .to_bytes_array::<32>() + .expect("y coordinate is mod n, meaning it must be <= 32 bytes"); + let x = Sha256::digest(&y_bytes); Some(PointCoords { x: BigInt::from_bytes(&x), y, @@ -359,7 +333,6 @@ impl PartialEq for RistrettoPoint { impl Zeroize for RistrettoPoint { fn zeroize(&mut self) { unsafe { ptr::write_volatile(&mut self.ge, PK::default()) }; - atomic::fence(atomic::Ordering::SeqCst); atomic::compiler_fence(atomic::Ordering::SeqCst); } } diff --git a/src/elliptic/curves/ed25519.rs b/src/elliptic/curves/ed25519.rs index 9dfa08ec..2cb8f98b 100644 --- a/src/elliptic/curves/ed25519.rs +++ b/src/elliptic/curves/ed25519.rs @@ -276,7 +276,6 @@ impl PartialEq for Ed25519Point { impl Zeroize for Ed25519Point { fn zeroize(&mut self) { unsafe { ptr::write_volatile(&mut self.ge, GENERATOR.ge) }; - atomic::fence(atomic::Ordering::SeqCst); atomic::compiler_fence(atomic::Ordering::SeqCst); } } diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index 9bbcc41f..9e9a1911 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -20,7 +20,7 @@ //! // Samples a random nonzero scalar (mod group order) //! let secret = Scalar::::random(); //! // Multiplies generator at secret, retrieving a public point -//! let public = Point::generator() * secret; +//! let public = Point::generator() * secret; //! ``` //! //! ### Diffie-Hellman diff --git a/src/elliptic/curves/p256.rs b/src/elliptic/curves/p256.rs index d61da9b9..327bd6bb 100644 --- a/src/elliptic/curves/p256.rs +++ b/src/elliptic/curves/p256.rs @@ -2,10 +2,8 @@ use p256::elliptic_curve::group::prime::PrimeCurveAffine; use p256::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint}; -use p256::{AffinePoint, EncodedPoint, ProjectivePoint, Scalar}; +use p256::{AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, Scalar}; -use generic_array::typenum::U32; -use generic_array::GenericArray; use rand::{thread_rng, Rng}; use serde::{Deserialize, Serialize}; use zeroize::Zeroize; @@ -14,14 +12,16 @@ use super::traits::{ECPoint, ECScalar}; use crate::arithmetic::traits::*; use crate::elliptic::curves::{Curve, DeserializationError, NotOnCurve, PointCoords}; use crate::BigInt; +use p256::elliptic_curve::group::ff::PrimeField; lazy_static::lazy_static! { static ref GROUP_ORDER: BigInt = BigInt::from_bytes(&GROUP_ORDER_BYTES); static ref BASE_POINT2_ENCODED: EncodedPoint = { - let mut g = vec![4_u8]; - g.extend_from_slice(BASE_POINT2_X.as_ref()); - g.extend_from_slice(BASE_POINT2_Y.as_ref()); + let mut g = [0u8; 65]; + g[0] = 0x04; + g[1..33].copy_from_slice(&BASE_POINT2_X); + g[33..].copy_from_slice(&BASE_POINT2_Y); EncodedPoint::from_bytes(&g).unwrap() }; @@ -84,12 +84,17 @@ impl ECScalar for Secp256r1Scalar { type Underlying = SK; fn random() -> Secp256r1Scalar { - let mut arr = [0u8; 32]; - thread_rng().fill(&mut arr[..]); - let gen_arr: GenericArray = *GenericArray::from_slice(&arr); + let mut rng = thread_rng(); + let scalar = loop { + let mut bytes = FieldBytes::default(); + rng.fill(&mut bytes[..]); + if let Some(scalar) = Scalar::from_repr(bytes) { + break scalar; + } + }; Secp256r1Scalar { purpose: "random", - fe: Scalar::from_bytes_reduced(&gen_arr).into(), + fe: scalar.into(), } } @@ -106,20 +111,14 @@ impl ECScalar for Secp256r1Scalar { fn from_bigint(n: &BigInt) -> Secp256r1Scalar { let curve_order = Secp256r1Scalar::group_order(); - let n_reduced = n.modulus(&curve_order); - let mut v = BigInt::to_bytes(&n_reduced); - const SECRET_KEY_SIZE: usize = 32; - - if v.len() < SECRET_KEY_SIZE { - let mut template = vec![0; SECRET_KEY_SIZE - v.len()]; - template.extend_from_slice(&v); - v = template; - } - let arr: GenericArray = *GenericArray::from_slice(&v); + let n_reduced = n + .modulus(&curve_order) + .to_bytes_array::<32>() + .expect("n mod curve_order must be equal or less than 32 bytes"); Secp256r1Scalar { purpose: "from_bigint", - fe: Scalar::from_bytes_reduced(&arr).into(), + fe: Scalar::from_bytes_reduced(&n_reduced.into()).into(), } } @@ -222,37 +221,12 @@ impl ECPoint for Secp256r1Point { } fn from_coords(x: &BigInt, y: &BigInt) -> Result { - let mut vec_x = BigInt::to_bytes(x); - let mut vec_y = BigInt::to_bytes(y); - - const COORDINATE_SIZE: usize = 32; - if vec_x.len() > COORDINATE_SIZE { - // x coordinate is too big - return Err(NotOnCurve); - } - if vec_y.len() > COORDINATE_SIZE { - // y coordinate is too big - return Err(NotOnCurve); - } - - if vec_x.len() < COORDINATE_SIZE { - // pad - let mut x_buffer = vec![0; COORDINATE_SIZE - vec_x.len()]; - x_buffer.extend_from_slice(&vec_x); - vec_x = x_buffer - } - if vec_y.len() < COORDINATE_SIZE { - // pad - let mut y_buffer = vec![0; COORDINATE_SIZE - vec_y.len()]; - y_buffer.extend_from_slice(&vec_y); - vec_y = y_buffer - } - - let x_arr: GenericArray = *GenericArray::from_slice(&vec_x); - let y_arr: GenericArray = *GenericArray::from_slice(&vec_y); - + let x_arr = x.to_bytes_array::<32>().ok_or(NotOnCurve)?; + let y_arr = y.to_bytes_array::<32>().ok_or(NotOnCurve)?; let ge = PK::from_encoded_point(&EncodedPoint::from_affine_coordinates( - &x_arr, &y_arr, false, + &x_arr.into(), + &y_arr.into(), + false, )) .ok_or(NotOnCurve)?; diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 9fc4891b..08679fcd 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -17,13 +17,14 @@ // use std::ops; +use std::ops::Deref; use std::ptr; use std::sync::atomic; use secp256k1::constants::{ self, GENERATOR_X, GENERATOR_Y, SECRET_KEY_SIZE, UNCOMPRESSED_PUBLIC_KEY_SIZE, }; -use secp256k1::{PublicKey, SecretKey}; +use secp256k1::{PublicKey, SecretKey, SECP256K1}; use serde::{Deserialize, Serialize}; use zeroize::{Zeroize, Zeroizing}; @@ -32,32 +33,32 @@ use crate::arithmetic::*; use super::traits::*; lazy_static::lazy_static! { - static ref CONTEXT: secp256k1::Secp256k1 = secp256k1::Secp256k1::new(); - static ref CURVE_ORDER: BigInt = BigInt::from_bytes(&constants::CURVE_ORDER); - static ref GENERATOR_UNCOMRESSED: Vec = { - let mut g = vec![4_u8]; - g.extend_from_slice(&GENERATOR_X); - g.extend_from_slice(&GENERATOR_Y); + static ref GENERATOR_UNCOMRESSED: [u8; 65] = { + let mut g = [0u8; 65]; + g[0] = 0x04; + g[1..33].copy_from_slice(&GENERATOR_X); + g[33..].copy_from_slice(&GENERATOR_Y); g }; - static ref BASE_POINT2_UNCOMPRESSED: Vec = { - let mut g = vec![4_u8]; - g.extend_from_slice(BASE_POINT2_X.as_ref()); - g.extend_from_slice(BASE_POINT2_Y.as_ref()); + static ref BASE_POINT2_UNCOMPRESSED: [u8; 65] = { + let mut g = [0u8; 65]; + g[0] = 0x04; + g[1..33].copy_from_slice(&BASE_POINT2_X); + g[33..].copy_from_slice(&BASE_POINT2_Y); g }; static ref GENERATOR: Secp256k1Point = Secp256k1Point { purpose: "generator", - ge: Some(PK(PublicKey::from_slice(&GENERATOR_UNCOMRESSED).unwrap())), + ge: Some(PK(PublicKey::from_slice(&GENERATOR_UNCOMRESSED[..]).unwrap())), }; static ref BASE_POINT2: Secp256k1Point = Secp256k1Point { purpose: "base_point2", - ge: Some(PK(PublicKey::from_slice(&BASE_POINT2_UNCOMPRESSED).unwrap())), + ge: Some(PK(PublicKey::from_slice(&BASE_POINT2_UNCOMPRESSED[..]).unwrap())), }; } @@ -119,7 +120,6 @@ impl Zeroize for PK { fn zeroize(&mut self) { let zeroed = unsafe { secp256k1::ffi::PublicKey::new() }; unsafe { ptr::write_volatile(self.0.as_mut_ptr(), zeroed) }; - atomic::fence(atomic::Ordering::SeqCst); atomic::compiler_fence(atomic::Ordering::SeqCst); } } @@ -174,25 +174,22 @@ impl ECScalar for Secp256k1Scalar { } fn from_bigint(n: &BigInt) -> Secp256k1Scalar { + let n = n.modulus(Self::group_order()); if n.is_zero() { - return Self::zero(); + return Secp256k1Scalar { + purpose: "from_bigint", + fe: Self::zero().fe, + }; } - - let group_order = Self::group_order(); - let n_reduced = n.modulus(group_order); - let bytes = BigInt::to_bytes(&n_reduced); - - let bytes = if bytes.len() < SECRET_KEY_SIZE { - let mut zero_prepended = vec![0; SECRET_KEY_SIZE - bytes.len()]; - zero_prepended.extend_from_slice(&bytes); - zero_prepended - } else { - bytes - }; + let bytes = n + .to_bytes_array::() + .expect("n mod curve_order must be equal or less than 32 bytes"); Secp256k1Scalar { purpose: "from_bigint", - fe: Zeroizing::new(SecretKey::from_slice(&bytes).map(SK).ok()), + fe: Zeroizing::new(Some(SK( + SecretKey::from_slice(&bytes).expect("fe is in (0, order) and exactly 32 bytes") + ))), } } @@ -204,41 +201,56 @@ impl ECScalar for Secp256k1Scalar { } fn add(&self, other: &Self) -> Secp256k1Scalar { - // TODO: use add_assign? - // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.add_assign - let n = BigInt::mod_add(&self.to_bigint(), &other.to_bigint(), Self::group_order()); + let fe = match (&*self.fe, &*other.fe) { + (None, right) => right.clone(), + (left, None) => left.clone(), + (Some(left), Some(right)) => { + let mut res = left.clone(); + res.add_assign(&right.0[..]).ok().map(|_| res) // right might be the negation of left. + } + }; + Secp256k1Scalar { purpose: "add", - fe: Self::from_bigint(&n).fe, + fe: Zeroizing::new(fe), } } fn mul(&self, other: &Self) -> Secp256k1Scalar { - // TODO: use mul_assign? - // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.mul_assign - let n = BigInt::mod_mul(&self.to_bigint(), &other.to_bigint(), Self::group_order()); + let fe = match (&*self.fe, &*other.fe) { + (None, _) | (_, None) => None, + (Some(left), Some(right)) => { + let mut res = left.clone(); + res.0 + .mul_assign(&right.0[..]) + .expect("Can't fail as it's a valid secret"); + Some(res) + } + }; + Secp256k1Scalar { purpose: "mul", - fe: Self::from_bigint(&n).fe, + fe: Zeroizing::new(fe), } } fn sub(&self, other: &Self) -> Secp256k1Scalar { - // TODO: use negate+add_assign? - // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.negate_assign - // https://docs.rs/secp256k1/0.20.3/secp256k1/key/struct.SecretKey.html#method.add_assign - let n = BigInt::mod_sub(&self.to_bigint(), &other.to_bigint(), Self::group_order()); + let right = other.neg(); + let res = self.clone().add(&right); Secp256k1Scalar { purpose: "sub", - fe: Self::from_bigint(&n).fe, + fe: res.fe, } } fn neg(&self) -> Self { - let n = BigInt::mod_sub(&BigInt::zero(), &self.to_bigint(), Self::group_order()); + let fe = self.fe.deref().clone().map(|mut fe| { + fe.negate_assign(); + fe + }); Secp256k1Scalar { purpose: "neg", - fe: Self::from_bigint(&n).fe, + fe: Zeroizing::new(fe), } } @@ -301,32 +313,18 @@ impl ECPoint for Secp256k1Point { } fn from_coords(x: &BigInt, y: &BigInt) -> Result { - let mut vec_x = BigInt::to_bytes(x); - let mut vec_y = BigInt::to_bytes(y); - let coor_size = (UNCOMPRESSED_PUBLIC_KEY_SIZE - 1) / 2; - - if vec_x.len() < coor_size { - // pad - let mut x_padded = vec![0; coor_size - vec_x.len()]; - x_padded.extend_from_slice(&vec_x); - vec_x = x_padded - } - - if vec_y.len() < coor_size { - // pad - let mut y_padded = vec![0; coor_size - vec_y.len()]; - y_padded.extend_from_slice(&vec_y); - vec_y = y_padded - } - - assert_eq!(x, &BigInt::from_bytes(vec_x.as_ref())); - assert_eq!(y, &BigInt::from_bytes(vec_y.as_ref())); - - let mut v = vec![4_u8]; - v.extend(vec_x); - v.extend(vec_y); - - PublicKey::from_slice(&v) + let vec_x = x.to_bytes(); + let vec_y = y.to_bytes(); + const COOR_SIZE: usize = (UNCOMPRESSED_PUBLIC_KEY_SIZE - 1) / 2; + let mut point = [0u8; UNCOMPRESSED_PUBLIC_KEY_SIZE]; + point[0] = 0x04; + point[1 + COOR_SIZE - vec_x.len()..1 + COOR_SIZE].copy_from_slice(&vec_x); + point[1 + (2 * COOR_SIZE) - vec_y.len()..].copy_from_slice(&vec_y); + + debug_assert_eq!(x, &BigInt::from_bytes(&point[1..1 + COOR_SIZE])); + debug_assert_eq!(y, &BigInt::from_bytes(&point[1 + COOR_SIZE..])); + + PublicKey::from_slice(&point) .map(|ge| Secp256k1Point { purpose: "from_coords", ge: Some(PK(ge)), @@ -372,14 +370,10 @@ impl ECPoint for Secp256k1Point { } fn serialize(&self, compressed: bool) -> Vec { - let ge = match &self.ge { - Some(pk) => pk, - None => return vec![0], - }; - if compressed { - ge.serialize().to_vec() - } else { - ge.serialize_uncompressed().to_vec() + match self.ge { + None => vec![0], + Some(ge) if compressed => ge.serialize().to_vec(), + Some(ge) => ge.serialize_uncompressed().to_vec(), } } @@ -404,150 +398,60 @@ impl ECPoint for Secp256k1Point { } fn scalar_mul(&self, scalar: &Self::Scalar) -> Secp256k1Point { - let mut new_point = match &self.ge { - Some(ge) => *ge, - None => { - // Point is zero => O * a = O - return Secp256k1Point { - purpose: "mul", - ge: None, - }; - } - }; - let scalar = match &*scalar.fe { - Some(s) => s, - None => { - // Scalar is zero => p * 0 = O - return Secp256k1Point { - purpose: "mul", - ge: None, - }; - } - }; - let result = new_point.mul_assign(&CONTEXT, &scalar[..]); - if result.is_err() { - // Multiplication resulted into zero point - return Secp256k1Point { - purpose: "mul", - ge: None, - }; - } - + let mut res = *self; + res.scalar_mul_assign(scalar); Secp256k1Point { purpose: "mul", - ge: Some(new_point), + ge: res.ge, } } fn generator_mul(scalar: &Self::Scalar) -> Self { - match &*scalar.fe { - Some(sk) => Secp256k1Point { - purpose: "generator_mul", - ge: Some(PK(PublicKey::from_secret_key(&CONTEXT, sk))), - }, - None => Secp256k1Point { - purpose: "generator_mul", - ge: None, - }, + let ge = scalar + .fe + .as_ref() + .map(|sk| PK(PublicKey::from_secret_key(&SECP256K1, sk))); + Secp256k1Point { + purpose: "generator_mul", + ge, } } fn add_point(&self, other: &Self) -> Secp256k1Point { - let ge1 = match &self.ge { - Some(ge) => ge, - None => { - // Point1 is zero => O + p2 = p2 - return Secp256k1Point { - purpose: "add", - ge: other.ge, - }; - } - }; - let ge2 = match &other.ge { - Some(ge) => ge, - None => { - // Point2 is zero => p1 + O = p1 - return Secp256k1Point { - purpose: "add", - ge: Some(*ge1), - }; - } + let ge = match (&self.ge, &other.ge) { + (None, right) => *right, + (left, None) => *left, + (Some(left), Some(right)) => left.combine(right).ok().map(PK), // right might be the negation of left }; - Secp256k1Point { - purpose: "add", - ge: ge1.combine(ge2).map(PK).ok(), - } + + Secp256k1Point { purpose: "add", ge } } fn sub_point(&self, other: &Self) -> Secp256k1Point { - let mut ge2_negated = match &other.ge { - Some(ge) => *ge, - None => { - // Point2 is zero => p1 - O = p1 - return Secp256k1Point { - purpose: "sub", - ge: self.ge, - }; - } - }; - ge2_negated.negate_assign(&CONTEXT); - - let ge1 = match &self.ge { - Some(ge) => ge, - None => { - // Point1 is zero => O - p2 = -p2 - return Secp256k1Point { - purpose: "sub", - ge: Some(ge2_negated), - }; - } - }; - - Secp256k1Point { - purpose: "sub", - ge: ge1.combine(&ge2_negated).map(PK).ok(), - } + let other_negated = other.neg_point(); + let ge = self.add_point(&other_negated).ge; + Secp256k1Point { purpose: "sub", ge } } fn neg_point(&self) -> Secp256k1Point { - Secp256k1Point { - purpose: "neg", - ge: match self.ge { - Some(mut ge) => { - ge.negate_assign(&CONTEXT); - Some(ge) - } - None => { - // Point is zero => -O = O - None - } - }, - } + let ge = self.ge.map(|mut ge| { + ge.0.negate_assign(&SECP256K1); + ge + }); + Secp256k1Point { purpose: "neg", ge } } fn scalar_mul_assign(&mut self, scalar: &Self::Scalar) { - let ge = match self.ge.as_mut() { - Some(ge) => ge, - None => { - // Point is zero => O * s = O + match (&mut self.ge, &*scalar.fe) { + (None, _) | (_, None) => { self.ge = None; - return; } - }; - - let fe = match scalar.fe.as_ref() { - Some(fe) => fe, - None => { - // Scalar is zero => p * 0 = O - self.ge = None; - return; + (Some(ge), Some(fe)) => { + ge.0.mul_assign(&SECP256K1, &fe.0[..]) + .expect("Can't fail as it's a valid secret"); } }; - - if ge.mul_assign(&CONTEXT, &fe[..]).is_err() { - // Multiplication resulted into zero - self.ge = None - } + self.purpose = "mul_assign"; } fn underlying_ref(&self) -> &Self::Underlying { From 89f3edac9378a107942bb3dc26645e9df34f2672 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 20 Jul 2021 18:08:57 +0300 Subject: [PATCH 74/93] Add serialize/deserialize to Scalars --- src/elliptic/curves/bls12_381/scalar.rs | 19 +++++++++++++++++++ src/elliptic/curves/curve_ristretto.rs | 14 ++++++++++++++ src/elliptic/curves/ed25519.rs | 14 ++++++++++++++ src/elliptic/curves/p256.rs | 15 +++++++++++++++ src/elliptic/curves/secp256_k1.rs | 22 ++++++++++++++++++++++ src/elliptic/curves/traits.rs | 6 +++++- 6 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/elliptic/curves/bls12_381/scalar.rs b/src/elliptic/curves/bls12_381/scalar.rs index 4f2669fc..6360463a 100644 --- a/src/elliptic/curves/bls12_381/scalar.rs +++ b/src/elliptic/curves/bls12_381/scalar.rs @@ -73,6 +73,25 @@ impl ECScalar for FieldScalar { BigInt::from_bytes(&bytes) } + fn serialize(&self) -> Vec { + let repr = self.fe.into_repr(); + let mut bytes = Vec::with_capacity(SECRET_KEY_SIZE); + repr.write_be(&mut bytes).unwrap(); + bytes + } + + fn deserialize(bytes: &[u8]) -> Result { + if bytes.len() != SECRET_KEY_SIZE { + return Err(DeserializationError); + } + let mut repr = FrRepr::default(); + repr.read_be(bytes.as_ref()).unwrap(); + Ok(FieldScalar { + purpose: "deserialize", + fe: Fr::from_repr(repr).unwrap().into(), + }) + } + fn add(&self, other: &Self) -> FieldScalar { let mut result = self.fe.clone(); result.add_assign(&other.fe); diff --git a/src/elliptic/curves/curve_ristretto.rs b/src/elliptic/curves/curve_ristretto.rs index 62b8e1e3..a8436c12 100644 --- a/src/elliptic/curves/curve_ristretto.rs +++ b/src/elliptic/curves/curve_ristretto.rs @@ -108,6 +108,20 @@ impl ECScalar for RistrettoScalar { BigInt::from_bytes(&t) } + fn serialize(&self) -> Vec { + self.fe.to_bytes().to_vec() + } + + fn deserialize(bytes: &[u8]) -> Result { + let bytes: [u8; 32] = bytes.try_into().or(Err(DeserializationError))?; + Ok(RistrettoScalar { + purpose: "from_bigint", + fe: SK::from_canonical_bytes(bytes) + .ok_or(DeserializationError)? + .into(), + }) + } + fn add(&self, other: &Self) -> RistrettoScalar { RistrettoScalar { purpose: "add", diff --git a/src/elliptic/curves/ed25519.rs b/src/elliptic/curves/ed25519.rs index 2cb8f98b..8534d315 100644 --- a/src/elliptic/curves/ed25519.rs +++ b/src/elliptic/curves/ed25519.rs @@ -162,6 +162,20 @@ impl ECScalar for Ed25519Scalar { BigInt::from_bytes(&t) } + fn serialize(&self) -> Vec { + self.fe.to_bytes().to_vec() + } + + fn deserialize(bytes: &[u8]) -> Result { + if bytes.len() != 32 { + return Err(DeserializationError); + } + Ok(Ed25519Scalar { + purpose: "deserialize", + fe: SK(Fe::from_bytes(bytes)).into(), + }) + } + fn add(&self, other: &Self) -> Ed25519Scalar { Ed25519Scalar { purpose: "add", diff --git a/src/elliptic/curves/p256.rs b/src/elliptic/curves/p256.rs index 327bd6bb..a079204d 100644 --- a/src/elliptic/curves/p256.rs +++ b/src/elliptic/curves/p256.rs @@ -126,6 +126,21 @@ impl ECScalar for Secp256r1Scalar { BigInt::from_bytes(self.fe.to_bytes().as_slice()) } + fn serialize(&self) -> Vec { + self.fe.to_bytes().to_vec() + } + + fn deserialize(bytes: &[u8]) -> Result { + if bytes.len() != 32 { + return Err(DeserializationError); + } + let bytes = *FieldBytes::from_slice(bytes); + Ok(Secp256r1Scalar { + purpose: "deserialize", + fe: Scalar::from_repr(bytes).ok_or(DeserializationError)?.into(), + }) + } + fn add(&self, other: &Self) -> Secp256r1Scalar { Secp256r1Scalar { purpose: "add", diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 08679fcd..2bc71c17 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -200,6 +200,28 @@ impl ECScalar for Secp256k1Scalar { } } + fn serialize(&self) -> Vec { + let scalar = match &*self.fe { + Some(s) => s, + None => return vec![0u8], + }; + scalar.0[..].to_vec() + } + + fn deserialize(bytes: &[u8]) -> Result { + let pk = if bytes == [0] { + None + } else { + Some(SK( + SecretKey::from_slice(bytes).or(Err(DeserializationError))? + )) + }; + Ok(Secp256k1Scalar { + purpose: "deserialize", + fe: pk.into(), + }) + } + fn add(&self, other: &Self) -> Secp256k1Scalar { let fe = match (&*self.fe, &*other.fe) { (None, right) => right.clone(), diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 5e436809..2a0b616c 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -51,6 +51,10 @@ pub trait ECScalar: Clone + PartialEq + fmt::Debug + 'static { fn from_bigint(n: &BigInt) -> Self; /// Converts a scalar to BigInt fn to_bigint(&self) -> BigInt; + /// Serializes scalar into bytes + fn serialize(&self) -> Vec; + /// Deserializes scalar from bytes + fn deserialize(bytes: &[u8]) -> Result; /// Calculates `(self + other) mod group_order` fn add(&self, other: &Self) -> Self; @@ -228,7 +232,7 @@ pub struct DeserializationError; impl fmt::Display for DeserializationError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "failed to deserialize the point") + write!(f, "failed to deserialize the point/scalar") } } From a955b6e78988e69a3cd9c56a4ca7a8abba2868d8 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 20 Jul 2021 19:30:30 +0300 Subject: [PATCH 75/93] Use scalar/point `serialize` functions to implement serde serialization instead of bigint --- src/elliptic/curves/wrappers/format.rs | 71 +++++++++++++------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/elliptic/curves/wrappers/format.rs b/src/elliptic/curves/wrappers/format.rs index 5db47b5d..77cd7d08 100644 --- a/src/elliptic/curves/wrappers/format.rs +++ b/src/elliptic/curves/wrappers/format.rs @@ -6,19 +6,16 @@ use std::marker::PhantomData; use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::arithmetic::*; use crate::elliptic::curves::traits::*; +use crate::elliptic::curves::InvalidPoint; -use super::{ - error::{InvalidPoint, PointFromCoordsError}, - *, -}; +use super::*; #[derive(Serialize, Deserialize)] #[serde(bound = "")] pub struct PointFormat { curve: Cow<'static, str>, - point: Option, + compressed_point: Box<[u8]>, #[serde(skip, default = "PointFormat::::_ph")] _ph: PhantomData, } @@ -38,16 +35,11 @@ impl TryFrom> for Point { got: parsed.curve, }); } - match parsed.point { - None => Ok(Point::zero()), - Some(coords) => match Point::from_coords(&coords.x, &coords.y) { - Ok(p) => Ok(p), - Err(PointFromCoordsError::NotOnCurve) => Err(ConvertParsedPointError::NotOnCurve), - Err(PointFromCoordsError::InvalidPoint(_e)) => Err( - ConvertParsedPointError::InvalidPoint(InvalidPoint::MismatchedPointOrder), - ), - }, - } + let point = E::Point::deserialize(&parsed.compressed_point) + .or(Err(ConvertParsedPointError::NotOnCurve))?; + Point::from_raw(point).or(Err(ConvertParsedPointError::InvalidPoint( + InvalidPoint::MismatchedPointOrder, + ))) } } @@ -55,7 +47,7 @@ impl From> for PointFormat { fn from(point: Point) -> Self { Self { curve: E::CURVE_NAME.into(), - point: point.coords(), + compressed_point: point.as_raw().serialize(true).into(), _ph: PhantomData, } } @@ -65,7 +57,7 @@ impl<'p, E: Curve> From> for PointFormat { fn from(point: PointRef<'p, E>) -> Self { Self { curve: E::CURVE_NAME.into(), - point: point.coords(), + compressed_point: point.as_raw().serialize(true).into(), _ph: PhantomData, } } @@ -116,35 +108,44 @@ impl From> for ScalarFormat { } } -#[derive(Debug, Error)] -pub enum ConvertParsedScalarError { - #[error("scalar must not be zero")] - ZeroScalar, - #[error("expected scalar of curve {expected}, but got scalar of curve {got}")] - MismatchedCurve { - got: Cow<'static, str>, - expected: &'static str, - }, -} - struct ScalarHex(E::Scalar); impl hex::ToHex for &ScalarHex { fn encode_hex>(&self) -> T { - self.0.to_bigint().to_bytes().encode_hex() + self.0.serialize().encode_hex() } fn encode_hex_upper>(&self) -> T { - self.0.to_bigint().to_bytes().encode_hex_upper() + self.0.serialize().encode_hex_upper() } } impl hex::FromHex for ScalarHex { - type Error = hex::FromHexError; + type Error = ScalarFromhexError; fn from_hex>(hex: T) -> Result { - let bytes = Vec::::from_hex(hex)?; - let big_int = BigInt::from_bytes(&bytes); - Ok(ScalarHex(E::Scalar::from_bigint(&big_int))) + let bytes = Vec::from_hex(hex).map_err(ScalarFromhexError::InvalidHex)?; + E::Scalar::deserialize(&bytes) + .or(Err(ScalarFromhexError::InvalidScalar)) + .map(ScalarHex) } } + +#[derive(Debug, Error)] +pub enum ConvertParsedScalarError { + #[error("scalar must not be zero")] + ZeroScalar, + #[error("expected scalar of curve {expected}, but got scalar of curve {got}")] + MismatchedCurve { + got: Cow<'static, str>, + expected: &'static str, + }, +} + +#[derive(Debug, Error)] +pub enum ScalarFromhexError { + #[error("scalar contains invalid hex: {0}")] + InvalidHex(hex::FromHexError), + #[error("scalar is not valid")] + InvalidScalar, +} From c41457982386457ac5528fff6c56b5b52bfa1cb0 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 20 Jul 2021 19:31:19 +0300 Subject: [PATCH 76/93] Add serde tests --- Cargo.toml | 8 +-- src/elliptic/curves/wrappers/format.rs | 95 ++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d00d15df..96a94eef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,11 +15,8 @@ crate-type = ["lib"] blake2b_simd = "0.5.7" cryptoxide = "0.1.2" curve25519-dalek = "3" -derivative = "2.2" digest = "0.8.1" ff-zeroize = "0.6.3" -funty = "=1.1.0" -generic-array = "0.14" hex = { version = "0.4", features = ["serde"] } hmac = "0.7.1" thiserror = "1" @@ -43,15 +40,14 @@ num-bigint = { version = "0.4", features = ["serde"], optional = true } [dependencies.secp256k1] version = "0.20" -features = ["serde", "rand-std"] +features = ["serde", "rand-std", "global-context"] [dependencies.p256] version = "0.9" features = ["ecdsa", "ecdsa-core", "zeroize"] [dev-dependencies] -bincode = "1.1" -serde_json = "1.0" +serde_test = "1.0" paste = "1.0.2" proptest = "0.10" proptest-derive = "0.2" diff --git a/src/elliptic/curves/wrappers/format.rs b/src/elliptic/curves/wrappers/format.rs index 77cd7d08..de7cb29c 100644 --- a/src/elliptic/curves/wrappers/format.rs +++ b/src/elliptic/curves/wrappers/format.rs @@ -149,3 +149,98 @@ pub enum ScalarFromhexError { #[error("scalar is not valid")] InvalidScalar, } + +#[cfg(test)] +mod serde_tests { + use crate::elliptic::curves::{ + Bls12_381_1, Bls12_381_2, Curve, ECPoint, ECScalar, Ed25519, Point, Ristretto, Secp256k1, + Secp256r1, + }; + use serde_test::{assert_tokens, Configure, Token::*}; + + #[test] + fn test_serde_zero_point() { + fn generic(serialized_zero_len: usize) { + let point = Point::::zero(); + let mut tokens = vec![ + Struct { + name: "PointFormat", + len: 2, + }, + Str("curve"), + Str(E::CURVE_NAME), + Str("compressed_point"), + ]; + tokens.push(Seq { + len: Option::Some(serialized_zero_len), + }); + + for _ in 0..serialized_zero_len { + tokens.push(U8(0)); + } + tokens.extend_from_slice(&[SeqEnd, StructEnd]); + assert_tokens(&point, &tokens); + } + generic::(1); + generic::(1); + generic::(32); + generic::(1); + generic::(1); + } + + #[test] + fn test_serde_zero_ed25519() { + let point = Point::::zero(); + let mut tokens = vec![ + Struct { + name: "PointFormat", + len: 2, + }, + Str("curve"), + Str(Ed25519::CURVE_NAME), + Str("compressed_point"), + Seq { + len: Option::Some(32), + }, + U8(1), + ]; + for _ in 0..31 { + tokens.push(U8(0)); + } + tokens.extend_from_slice(&[SeqEnd, StructEnd]); + + assert_tokens(&point, &tokens); + } + + #[test] + fn test_serde_random_point() { + fn generic() { + let random_point = E::Point::generator_mul(&E::Scalar::random()); + let point: Point = Point::from_raw(random_point).unwrap(); + let serialized = ECPoint::serialize(point.as_raw(), true); + let mut tokens = vec![ + Struct { + name: "PointFormat", + len: 2, + }, + Str("curve"), + Str(E::CURVE_NAME), + Str("compressed_point"), + ]; + tokens.push(Seq { + len: Option::Some(serialized.len()), + }); + + for i in serialized { + tokens.push(U8(i)); + } + tokens.extend_from_slice(&[SeqEnd, StructEnd]); + assert_tokens(&point.compact(), &tokens); + } + generic::(); + generic::(); + generic::(); + generic::(); + generic::(); + } +} From 10e083b8bc8499199df369770922a56194def144 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Thu, 22 Jul 2021 19:11:42 +0300 Subject: [PATCH 77/93] Add more EC serialize/deserialize tests --- src/elliptic/curves/test.rs | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/elliptic/curves/test.rs b/src/elliptic/curves/test.rs index 33bd64a3..30aecf8d 100644 --- a/src/elliptic/curves/test.rs +++ b/src/elliptic/curves/test.rs @@ -78,16 +78,17 @@ fn point_addition_multiplication() { assert_eq!(addition, multiplication); } -test_for_all_curves!(serialize_deserialize); -fn serialize_deserialize() { - let point = ::generator().scalar_mul(&random_nonzero_scalar()); - let bytes = point.serialize(true); - let deserialized = ::deserialize(&bytes).unwrap(); - assert_eq!(point, deserialized); - - let bytes = point.serialize(false); - let deserialized = E::Point::deserialize(&bytes).unwrap(); - assert_eq!(point, deserialized); +test_for_all_curves!(serialize_deserialize_point); +fn serialize_deserialize_point() { + let rand_point = ::generator().scalar_mul(&random_nonzero_scalar()); + let zero = E::Point::zero(); + for point in [rand_point, zero] { + for compressed in [true, false] { + let bytes = point.serialize(compressed); + let deserialized = ::deserialize(&bytes).unwrap(); + assert_eq!(point, deserialized); + } + } } test_for_all_curves!(zero_point_serialization); @@ -289,6 +290,17 @@ fn test_assign_multiplication_point_at_scalar() { assert_eq!(abG_1, abG_2); } +test_for_all_curves!(serialize_deserialize_scalar); +fn serialize_deserialize_scalar() { + let rand_point: E::Scalar = random_nonzero_scalar(); + let zero = E::Scalar::zero(); + for scalar in [rand_point, zero] { + let bytes = scalar.serialize(); + let deserialized = ::deserialize(&bytes).unwrap(); + assert_eq!(scalar, deserialized); + } +} + test_for_all_curves!(scalar_invert); fn scalar_invert() { let n: E::Scalar = random_nonzero_scalar(); From 043f969f664bba2622a8cde299eb3d6d394bb5d4 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 22 Jul 2021 20:45:31 +0300 Subject: [PATCH 78/93] Update examples --- examples/diffie_hellman_key_exchange.rs | 9 +++++---- examples/pedersen_commitment.rs | 13 +++++++------ examples/proof_of_knowledge_of_dlog.rs | 9 +++++---- examples/verifiable_secret_sharing.rs | 13 +++++-------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/examples/diffie_hellman_key_exchange.rs b/examples/diffie_hellman_key_exchange.rs index 29187dc0..5671e54e 100644 --- a/examples/diffie_hellman_key_exchange.rs +++ b/examples/diffie_hellman_key_exchange.rs @@ -33,10 +33,11 @@ fn main() { let curve_name = std::env::args().nth(1); match curve_name.as_deref() { Some("secp256k1") => ecdh::(), - // Some("ristretto") => ecdh::(), - // Some("ed25519") => ecdh::(), - // Some("bls12_381") => ecdh::(), - // Some("p256") => ecdh::(), + Some("ristretto") => ecdh::(), + Some("ed25519") => ecdh::(), + Some("bls12_381_1") => ecdh::(), + Some("bls12_381_2") => ecdh::(), + Some("p256") => ecdh::(), Some(unknown_curve) => eprintln!("Unknown curve: {}", unknown_curve), None => eprintln!("Missing curve name"), } diff --git a/examples/pedersen_commitment.rs b/examples/pedersen_commitment.rs index e3d8e535..a489ccca 100644 --- a/examples/pedersen_commitment.rs +++ b/examples/pedersen_commitment.rs @@ -31,14 +31,15 @@ pub fn ped_com(message: &BigInt) { fn main() { let message = "commit me!"; - let _message_bn = BigInt::from_bytes(message.as_bytes()); + let message_bn = BigInt::from_bytes(message.as_bytes()); let curve_name = std::env::args().nth(1); match curve_name.as_deref() { - Some("secp256k1") => ped_com::(&_message_bn), - // Some("ristretto") => ped_com::(&_message_bn), - // Some("ed25519") => ped_com::(&_message_bn), - // Some("bls12_381") => ped_com::(&_message_bn), - // Some("p256") => ped_com::(&_message_bn), + Some("secp256k1") => ped_com::(&message_bn), + Some("ristretto") => ped_com::(&message_bn), + Some("ed25519") => ped_com::(&message_bn), + Some("bls12_381_1") => ped_com::(&message_bn), + Some("bls12_381_2") => ped_com::(&message_bn), + Some("p256") => ped_com::(&message_bn), Some(unknown_curve) => eprintln!("Unknown curve: {}", unknown_curve), None => eprintln!("Missing curve name"), } diff --git a/examples/proof_of_knowledge_of_dlog.rs b/examples/proof_of_knowledge_of_dlog.rs index 358fe409..6e08da77 100644 --- a/examples/proof_of_knowledge_of_dlog.rs +++ b/examples/proof_of_knowledge_of_dlog.rs @@ -21,10 +21,11 @@ fn main() { let curve_name = std::env::args().nth(1); match curve_name.as_deref() { Some("secp256k1") => dlog_proof::(), - // Some("ristretto") => dlog_proof::(), - // Some("ed25519") => dlog_proof::(), - // Some("bls12_381") => dlog_proof::(), - // Some("p256") => dlog_proof::(), + Some("ristretto") => dlog_proof::(), + Some("ed25519") => dlog_proof::(), + Some("bls12_381_1") => dlog_proof::(), + Some("bls12_381_2") => dlog_proof::(), + Some("p256") => dlog_proof::(), Some(unknown_curve) => eprintln!("Unknown curve: {}", unknown_curve), None => eprintln!("Missing curve name"), } diff --git a/examples/verifiable_secret_sharing.rs b/examples/verifiable_secret_sharing.rs index 29566239..8eed3f2b 100644 --- a/examples/verifiable_secret_sharing.rs +++ b/examples/verifiable_secret_sharing.rs @@ -60,14 +60,11 @@ fn main() { let curve_name = std::env::args().nth(1); match curve_name.as_deref() { Some("secp256k1") => secret_sharing_3_out_of_5::(), - // Some("ristretto") => { - // secret_sharing_3_out_of_5::() - // } - // Some("ed25519") => secret_sharing_3_out_of_5::(), - // Some("bls12_381") => { - // secret_sharing_3_out_of_5::() - // } - // Some("p256") => secret_sharing_3_out_of_5::(), + Some("ristretto") => secret_sharing_3_out_of_5::(), + Some("ed25519") => secret_sharing_3_out_of_5::(), + Some("bls12_381_1") => secret_sharing_3_out_of_5::(), + Some("bls12_381_2") => secret_sharing_3_out_of_5::(), + Some("p256") => secret_sharing_3_out_of_5::(), Some(unknown_curve) => eprintln!("Unknown curve: {}", unknown_curve), None => eprintln!("Missing curve name"), } From 8543551ed3006a938792acc6bd9548ed3baa87f0 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 22 Jul 2021 20:48:31 +0300 Subject: [PATCH 79/93] Update Cargo.toml --- Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 96a94eef..5761ec98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,10 @@ name = "curv-kzen" version = "0.8.0-rc1" edition = "2018" -authors = ["Omer Shlomovits"] +authors = [ + "Omer Shlomovits", + "Denis Varlakov", +] license = "MIT" description = "Curv contains an extremly simple interface to onboard new elliptic curves. Use this library for general purpose elliptic curve cryptography" repository = "https://github.com/ZenGo-X/curv" From cfcaecfd320499e180f21da59dfda248f1ef40f9 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 22 Jul 2021 20:52:44 +0300 Subject: [PATCH 80/93] Update docs --- src/elliptic/curves/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index 9e9a1911..3b9f7421 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -34,12 +34,12 @@ //! [dh_key_exchange_variant_with_pok_comm]: crate::cryptographic_primitives::twoparty::dh_key_exchange_variant_with_pok_comm //! //! ```rust -//! use curv::elliptic::curves::{Point, Scalar, Secp256k1}; +//! use curv::elliptic::curves::{Point, Scalar, Ed25519}; //! //! fn diffie_hellman( -//! my_secret: &Scalar, -//! counterparty_point: &Point -//! ) -> Point { +//! my_secret: &Scalar, +//! counterparty_point: &Point +//! ) -> Point { //! my_secret * counterparty_point //! } //! ``` @@ -53,8 +53,7 @@ //! [subgroup-attack]: http://safecurves.cr.yp.to/twist.html //! [Guarantees section]: Point#guarantees //! -//! The function above performs DH only on secp256k1 curve, which is disappointing — the code will -//! look the same for any curve. Luckily, we can make it generic over choice of curve: +//! Function above can be slightly modified to be generic over choice of curve: //! //! ```rust //! use curv::elliptic::curves::{Curve, Point, Scalar}; From f65bd334375b925373e939a750d0d812d75b4b06 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 22 Jul 2021 21:10:45 +0300 Subject: [PATCH 81/93] Update vss to use u16 instead of usize fix --- .../secret_sharing/feldman_vss.rs | 67 +++++++++---------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs index ad59d46b..e518d8b9 100644 --- a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs +++ b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs @@ -17,8 +17,8 @@ use crate::ErrorSS::{self, VerifyShareError}; #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct ShamirSecretSharing { - pub threshold: usize, //t - pub share_count: usize, //n + pub threshold: u16, //t + pub share_count: u16, //n } /// Feldman VSS, based on Paul Feldman. 1987. A practical scheme for non-interactive verifiable secret sharing. @@ -49,17 +49,13 @@ pub struct SecretShares { } impl VerifiableSS { - pub fn reconstruct_limit(&self) -> usize { + pub fn reconstruct_limit(&self) -> u16 { self.parameters.threshold + 1 } - // TODO: share should accept u16 rather than usize // generate VerifiableSS from a secret - pub fn share(t: usize, n: usize, secret: &Scalar) -> (VerifiableSS, SecretShares) { + pub fn share(t: u16, n: u16, secret: &Scalar) -> (VerifiableSS, SecretShares) { assert!(t < n); - let t = u16::try_from(t).unwrap(); - let n = u16::try_from(n).unwrap(); - let polynomial = Polynomial::::sample_exact_with_fixed_const_term(t, secret.clone()); let shares = polynomial.evaluate_many_bigint(1..=n).collect(); @@ -72,8 +68,8 @@ impl VerifiableSS { ( VerifiableSS { parameters: ShamirSecretSharing { - threshold: t.into(), - share_count: n.into(), + threshold: t, + share_count: n, }, commitments, }, @@ -83,9 +79,8 @@ impl VerifiableSS { // takes given VSS and generates a new VSS for the same secret and a secret shares vector to match the new commitments pub fn reshare(&self) -> (VerifiableSS, Vec>) { - // TODO: ShamirSecretSharing::{threshold, share_count} should be u16 rather than usize - let t = u16::try_from(self.parameters.threshold).unwrap(); - let n = u16::try_from(self.parameters.share_count).unwrap(); + let t = self.parameters.threshold; + let n = self.parameters.share_count; let one = Scalar::::from(1); let poly = Polynomial::::sample_exact_with_fixed_const_term(t, one.clone()); @@ -109,19 +104,17 @@ impl VerifiableSS { // generate VerifiableSS from a secret and user defined x values (in case user wants to distribute point f(1), f(4), f(6) and not f(1),f(2),f(3)) pub fn share_at_indices( - t: usize, - n: usize, + t: u16, + n: u16, secret: &Scalar, - index_vec: &[usize], + index_vec: &[u16], ) -> (VerifiableSS, SecretShares) { - assert_eq!(n, index_vec.len()); - // TODO: share_at_indices should accept u16 rather than usize (t, n, index_vec) - let t = u16::try_from(t).unwrap(); - let n = u16::try_from(n).unwrap(); - let index_vec = index_vec.iter().map(|&i| u16::try_from(i).unwrap()); + assert_eq!(usize::from(n), index_vec.len()); let polynomial = Polynomial::::sample_exact_with_fixed_const_term(t, secret.clone()); - let shares = polynomial.evaluate_many_bigint(index_vec).collect(); + let shares = polynomial + .evaluate_many_bigint(index_vec.iter().cloned()) + .collect(); let g = Point::::generator(); let commitments = polynomial @@ -132,8 +125,8 @@ impl VerifiableSS { ( VerifiableSS { parameters: ShamirSecretSharing { - threshold: t.into(), - share_count: n.into(), + threshold: t, + share_count: n, }, commitments, }, @@ -164,13 +157,13 @@ impl VerifiableSS { Polynomial::::from_coefficients(coefficients.to_vec()).evaluate(&point) } - pub fn reconstruct(&self, indices: &[usize], shares: &[Scalar]) -> Scalar { + pub fn reconstruct(&self, indices: &[u16], shares: &[Scalar]) -> Scalar { assert_eq!(shares.len(), indices.len()); - assert!(shares.len() >= self.reconstruct_limit()); + assert!(shares.len() >= usize::from(self.reconstruct_limit())); // add one to indices to get points let points = indices .iter() - .map(|i| Scalar::from(*i as u32 + 1)) + .map(|i| Scalar::from(*i + 1)) .collect::>(); VerifiableSS::::lagrange_interpolation_at_zero(&points, &shares) } @@ -223,13 +216,13 @@ impl VerifiableSS { tail.fold(head.clone(), |acc, x| acc + x) } - pub fn validate_share(&self, secret_share: &Scalar, index: usize) -> Result<(), ErrorSS> { + pub fn validate_share(&self, secret_share: &Scalar, index: u16) -> Result<(), ErrorSS> { let g = Point::generator(); let ss_point = g * secret_share; self.validate_share_public(&ss_point, index) } - pub fn validate_share_public(&self, ss_point: &Point, index: usize) -> Result<(), ErrorSS> { + pub fn validate_share_public(&self, ss_point: &Point, index: u16) -> Result<(), ErrorSS> { let comm_to_point = self.get_point_commitment(index); if *ss_point == comm_to_point { Ok(()) @@ -238,8 +231,8 @@ impl VerifiableSS { } } - pub fn get_point_commitment(&self, index: usize) -> Point { - let index_fe = Scalar::from(index as u32); + pub fn get_point_commitment(&self, index: u16) -> Point { + let index_fe = Scalar::from(index); let mut comm_iterator = self.commitments.iter().rev(); let head = comm_iterator.next().unwrap(); let tail = comm_iterator; @@ -250,29 +243,29 @@ impl VerifiableSS { // used in http://stevengoldfeder.com/papers/GG18.pdf pub fn map_share_to_new_params( params: &ShamirSecretSharing, - index: usize, - s: &[usize], + index: u16, + s: &[u16], ) -> Scalar { let s_len = s.len(); // assert!(s_len > self.reconstruct_limit()); // add one to indices to get points let points: Vec> = (0..params.share_count) - .map(|i| Scalar::from(i as u32 + 1)) + .map(|i| Scalar::from(i + 1)) .collect(); - let xi = &points[index]; + let xi = &points[usize::from(index)]; let num = Scalar::from(1); let denum = Scalar::from(1); let num = (0..s_len).fold(num, |acc, i| { if s[i] != index { - acc * &points[s[i]] + acc * &points[usize::from(s[i])] } else { acc } }); let denum = (0..s_len).fold(denum, |acc, i| { if s[i] != index { - let xj_sub_xi = &points[s[i]] - xi; + let xj_sub_xi = &points[usize::from(s[i])] - xi; acc * xj_sub_xi } else { acc From f954bdb7ddbb748d3c0f945467019d174d7f08fb Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 22 Jul 2021 21:08:37 +0300 Subject: [PATCH 82/93] Resolve TODO --- src/elliptic/curves/p256.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/elliptic/curves/p256.rs b/src/elliptic/curves/p256.rs index a079204d..02ea8536 100644 --- a/src/elliptic/curves/p256.rs +++ b/src/elliptic/curves/p256.rs @@ -288,11 +288,9 @@ impl ECPoint for Secp256r1Point { } fn scalar_mul(&self, fe: &Self::Scalar) -> Secp256r1Point { - // TODO: p256 v0.5.0 cannot multiply AffinePoint * Scalar, but can multiply - // ProjectivePoint * Scalar. It was fixed in v0.9.0 Secp256r1Point { purpose: "scalar_mul", - ge: (ProjectivePoint::from(self.ge) * *fe.fe).to_affine(), + ge: (self.ge * *fe.fe).to_affine(), } } From affe7be236e09f3fc2add3b8a030505d67a8b0f0 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 22 Jul 2021 21:32:40 +0300 Subject: [PATCH 83/93] Fix doc --- src/elliptic/curves/wrappers/arithmetic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elliptic/curves/wrappers/arithmetic.rs b/src/elliptic/curves/wrappers/arithmetic.rs index 1e3d05d4..4528afb9 100644 --- a/src/elliptic/curves/wrappers/arithmetic.rs +++ b/src/elliptic/curves/wrappers/arithmetic.rs @@ -494,7 +494,7 @@ mod test { } } - /// Function asserts that S2 can be added to S1 (ie. S1 + S2) and result is Scalar. + /// Function asserts that S2 can be subtracted from S1 (ie. S1 - S2) and result is Scalar. /// If any condition doesn't meet, function won't compile. #[allow(dead_code)] fn assert_scalars_subtraction_defined() From 34873cd80819a9ec75992a6b84da8507e14b6210 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 23 Jul 2021 15:21:38 +0300 Subject: [PATCH 84/93] Impl iter::{Sum, Product} for wrappers --- src/elliptic/curves/wrappers/point.rs | 20 +++++++++++++++++++- src/elliptic/curves/wrappers/scalar.rs | 26 +++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index ac94d641..83b64c87 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::{fmt, iter}; use serde::{Deserialize, Serialize}; @@ -259,3 +259,21 @@ impl<'p, E: Curve> From> for Point { unsafe { Point::from_raw_unchecked(p.as_raw().clone()) } } } + +impl iter::Sum for Point { + fn sum>(iter: I) -> Self { + iter.fold(Point::zero(), |acc, p| acc + p) + } +} + +impl<'p, E: Curve> iter::Sum<&'p Point> for Point { + fn sum>>(iter: I) -> Self { + iter.fold(Point::zero(), |acc, p| acc + p) + } +} + +impl<'p, E: Curve> iter::Sum> for Point { + fn sum>>(iter: I) -> Self { + iter.fold(Point::zero(), |acc, p| acc + p) + } +} diff --git a/src/elliptic/curves/wrappers/scalar.rs b/src/elliptic/curves/wrappers/scalar.rs index df314fdc..2e968cf2 100644 --- a/src/elliptic/curves/wrappers/scalar.rs +++ b/src/elliptic/curves/wrappers/scalar.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::{fmt, iter}; use serde::{Deserialize, Serialize}; @@ -176,3 +176,27 @@ impl From for Scalar { Self::from(&n) } } + +impl iter::Sum for Scalar { + fn sum>(iter: I) -> Self { + iter.fold(Scalar::zero(), |acc, s| acc + s) + } +} + +impl<'s, E: Curve> iter::Sum<&'s Scalar> for Scalar { + fn sum>>(iter: I) -> Self { + iter.fold(Scalar::zero(), |acc, s| acc + s) + } +} + +impl iter::Product for Scalar { + fn product>(iter: I) -> Self { + iter.fold(Scalar::from(1), |acc, s| acc * s) + } +} + +impl<'s, E: Curve> iter::Product<&'s Scalar> for Scalar { + fn product>>(iter: I) -> Self { + iter.fold(Scalar::from(1), |acc, s| acc * s) + } +} From 2eb8b2bf730cca66903c45345f2f2032b7d7f3b5 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 26 Jul 2021 08:59:33 +0300 Subject: [PATCH 85/93] Ristretto: return x=None instead of x=hash(y) --- src/elliptic/curves/curve_ristretto.rs | 46 ++++++++--------------- src/elliptic/curves/test.rs | 4 ++ src/elliptic/curves/wrappers/point.rs | 5 ++- src/elliptic/curves/wrappers/point_ref.rs | 5 ++- 4 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/elliptic/curves/curve_ristretto.rs b/src/elliptic/curves/curve_ristretto.rs index a8436c12..fe16e637 100644 --- a/src/elliptic/curves/curve_ristretto.rs +++ b/src/elliptic/curves/curve_ristretto.rs @@ -50,6 +50,14 @@ pub const NUM_OF_COORDINATES: usize = 4; pub type SK = curve25519_dalek::scalar::Scalar; pub type PK = curve25519_dalek::ristretto::RistrettoPoint; +/// Ristretto curve implementation based on [curve25519_dalek] library +/// +/// ## Implementation notes +/// * x coordinate +/// +/// Underlying library intentionally doesn't expose x coordinate of curve point, therefore +/// `.x_coord()`, `.coords()` methods always return `None`, `from_coords()` constructor always +/// returns `Err(NotOnCurve)` #[derive(Debug, PartialEq, Clone)] pub enum Ristretto {} #[derive(Clone, Debug)] @@ -218,30 +226,16 @@ impl ECPoint for RistrettoPoint { &BASE_POINT2 } - fn from_coords(x: &BigInt, y: &BigInt) -> Result { - let mut y_bytes = y.to_bytes_array::<32>().ok_or(NotOnCurve)?; - if x != &BigInt::from_bytes(&Sha256::digest(&y_bytes)) { - return Err(NotOnCurve); - } - - y_bytes.reverse(); - let compressed = CompressedRistretto::from_slice(&y_bytes); - - Ok(RistrettoPoint { - purpose: "from_coords", - ge: compressed.decompress().ok_or(NotOnCurve)?, - }) + fn from_coords(_x: &BigInt, _y: &BigInt) -> Result { + // Underlying library intentionally hides x coordinate. There's no way to match if `x` + // correspond to given `y`. + Err(NotOnCurve) } fn x_coord(&self) -> Option { - // Underlying library intentionally hides x coordinate. We return x=hash(y) as was proposed - // here: https://github.com/dalek-cryptography/curve25519-dalek/issues/235 - let y = self - .y_coord()? - .to_bytes_array::<32>() - .expect("y coordinate is mod n, meaning it must be <= 32 bytes"); - let x = Sha256::digest(&y); - Some(BigInt::from_bytes(&x)) + // Underlying library intentionally hides x coordinate. There's no way we can know x + // coordinate + None } fn y_coord(&self) -> Option { @@ -251,15 +245,7 @@ impl ECPoint for RistrettoPoint { } fn coords(&self) -> Option { - let y = self.y_coord()?; - let y_bytes = y - .to_bytes_array::<32>() - .expect("y coordinate is mod n, meaning it must be <= 32 bytes"); - let x = Sha256::digest(&y_bytes); - Some(PointCoords { - x: BigInt::from_bytes(&x), - y, - }) + None } fn serialize(&self, _compressed: bool) -> Vec { diff --git a/src/elliptic/curves/test.rs b/src/elliptic/curves/test.rs index 30aecf8d..2dd97e2c 100644 --- a/src/elliptic/curves/test.rs +++ b/src/elliptic/curves/test.rs @@ -189,6 +189,10 @@ fn scalar_behaves_the_same_as_bigint() { test_for_all_curves!(from_coords_produces_the_same_point); fn from_coords_produces_the_same_point() { + if E::CURVE_NAME == "ristretto" { + // This curve is exception. + return; + } let s: E::Scalar = random_nonzero_scalar(); println!("s={}", s.to_bigint()); diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index 83b64c87..3a4c9adf 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -112,7 +112,10 @@ impl Point { /// Returns point coordinates /// /// Point might not have coordinates (specifically, "point at infinity" doesn't), in this case - /// `None` is returned + /// `None` is returned. Also, some curve libraries do not expose point coordinates (eg. see + /// [Ristretto] curve implementation notes). + /// + /// [Ristretto]: crate::elliptic::curves::Ristretto pub fn coords(&self) -> Option { self.as_raw().coords() } diff --git a/src/elliptic/curves/wrappers/point_ref.rs b/src/elliptic/curves/wrappers/point_ref.rs index 4f705fb9..1b181782 100644 --- a/src/elliptic/curves/wrappers/point_ref.rs +++ b/src/elliptic/curves/wrappers/point_ref.rs @@ -33,7 +33,10 @@ where /// Returns point coordinates (`x` and `y`) /// /// Point might not have coordinates (specifically, "point at infinity" doesn't), in this case - /// `None` is returned + /// `None` is returned. Also, some curve libraries do not expose point coordinates (eg. see + /// [Ristretto] curve implementation notes). + /// + /// [Ristretto]: crate::elliptic::curves::Ristretto pub fn coords(&self) -> Option { self.as_raw().coords() } From 373672f636aaf23843e5f208c901e8bd2ae4bc94 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 26 Jul 2021 08:59:45 +0300 Subject: [PATCH 86/93] Add documentation for the rest of the curves --- src/elliptic/curves/bls12_381/g1.rs | 1 + src/elliptic/curves/bls12_381/g2.rs | 1 + src/elliptic/curves/ed25519.rs | 9 +++++++++ src/elliptic/curves/mod.rs | 1 + src/elliptic/curves/p256.rs | 1 + src/elliptic/curves/secp256_k1.rs | 1 + 6 files changed, 14 insertions(+) diff --git a/src/elliptic/curves/bls12_381/g1.rs b/src/elliptic/curves/bls12_381/g1.rs index 760a18ff..57304fff 100644 --- a/src/elliptic/curves/bls12_381/g1.rs +++ b/src/elliptic/curves/bls12_381/g1.rs @@ -51,6 +51,7 @@ pub const COMPRESSED_SIZE: usize = 48; pub type PK = ::G1Affine; +/// Bls12-381-1 (G1) curve implementation based on [pairing_plus] library #[derive(Debug, PartialEq, Clone)] pub enum Bls12_381_1 {} diff --git a/src/elliptic/curves/bls12_381/g2.rs b/src/elliptic/curves/bls12_381/g2.rs index abf19053..0a95c579 100644 --- a/src/elliptic/curves/bls12_381/g2.rs +++ b/src/elliptic/curves/bls12_381/g2.rs @@ -57,6 +57,7 @@ pub const COMPRESSED_SIZE: usize = 96; pub type SK = ::Fr; pub type PK = ::G2Affine; +/// Bls12-381-2 (G2) curve implementation based on [pairing_plus] library #[derive(PartialEq, Debug, Clone)] pub enum Bls12_381_2 {} diff --git a/src/elliptic/curves/ed25519.rs b/src/elliptic/curves/ed25519.rs index 8534d315..87ef8509 100644 --- a/src/elliptic/curves/ed25519.rs +++ b/src/elliptic/curves/ed25519.rs @@ -91,6 +91,15 @@ impl ops::DerefMut for SK { } } +/// Ed25519 curve implementation based on [cryptoxide] library +/// +/// ## Implementation notes +/// * x coordinate +/// +/// Underlying library doesn't expose x coordinate of curve point, but there's an algorithm +/// recovering x coordinate of ed25519 point from its y coordinate. Every time you call +/// `.x_coord()` or `from_coords()`, it takes y coordinate and runs `xrecover(y)` underhood. Keep +/// in mind that `xrecover` is quite expensive operation. #[derive(Debug, PartialEq, Clone)] pub enum Ed25519 {} diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index 3b9f7421..01e230ba 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -87,6 +87,7 @@ mod test; mod traits; mod wrappers; +#[doc(inline)] pub use self::{ bls12_381::{Bls12_381_1, Bls12_381_2}, curve_ristretto::Ristretto, diff --git a/src/elliptic/curves/p256.rs b/src/elliptic/curves/p256.rs index 02ea8536..514fcf12 100644 --- a/src/elliptic/curves/p256.rs +++ b/src/elliptic/curves/p256.rs @@ -52,6 +52,7 @@ const GROUP_ORDER_BYTES: [u8; 32] = [ 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51, ]; +/// P-256 curve implementation based on [p256] library #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Secp256r1 {} diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 2bc71c17..8a9b937f 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -124,6 +124,7 @@ impl Zeroize for PK { } } +/// K-256 curve implementation based on [secp256k1] library #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Secp256k1 {} From 17d18f367c688127e96cca55f0a3251f97575b79 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 26 Jul 2021 21:02:25 +0300 Subject: [PATCH 87/93] Improve point serialization --- Cargo.toml | 1 + src/cryptographic_primitives/hashing/ext.rs | 2 +- .../hashing/hash_sha256.rs | 2 +- .../hashing/hash_sha512.rs | 2 +- .../dh_key_exchange_variant_with_pok_comm.rs | 17 +- src/elliptic/curves/bls12_381/g1.rs | 26 +-- src/elliptic/curves/bls12_381/g2.rs | 26 +-- src/elliptic/curves/curve_ristretto.rs | 14 +- src/elliptic/curves/ed25519.rs | 15 +- src/elliptic/curves/mod.rs | 2 +- src/elliptic/curves/p256.rs | 13 +- src/elliptic/curves/secp256_k1.rs | 21 +- src/elliptic/curves/test.rs | 19 +- src/elliptic/curves/traits.rs | 17 +- src/elliptic/curves/wrappers/encoded_point.rs | 19 ++ src/elliptic/curves/wrappers/format.rs | 162 -------------- src/elliptic/curves/wrappers/mod.rs | 6 +- src/elliptic/curves/wrappers/point.rs | 197 +++++++++++++++++- src/elliptic/curves/wrappers/point_ref.rs | 32 ++- 19 files changed, 347 insertions(+), 246 deletions(-) create mode 100644 src/elliptic/curves/wrappers/encoded_point.rs diff --git a/Cargo.toml b/Cargo.toml index 5761ec98..cfa8df9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ rand_legacy = { package = "rand", version = "0.6" } ring-algorithm = "0.2.3" rust-crypto = "^0.2" serde = { version = "1.0", features = ["derive"] } +serde_bytes = "0.11" serde_derive = "1.0" sha2 = "0.8.0" sha3 = "0.8.2" diff --git a/src/cryptographic_primitives/hashing/ext.rs b/src/cryptographic_primitives/hashing/ext.rs index ce945f6f..baca9131 100644 --- a/src/cryptographic_primitives/hashing/ext.rs +++ b/src/cryptographic_primitives/hashing/ext.rs @@ -89,7 +89,7 @@ where } fn input_point(&mut self, point: &Point) { - self.input(&point.to_bytes(false)) + self.input(&point.to_bytes(false)[..]) } fn input_scalar(&mut self, scalar: &Scalar) { diff --git a/src/cryptographic_primitives/hashing/hash_sha256.rs b/src/cryptographic_primitives/hashing/hash_sha256.rs index 8637b2e1..aa5848ce 100644 --- a/src/cryptographic_primitives/hashing/hash_sha256.rs +++ b/src/cryptographic_primitives/hashing/hash_sha256.rs @@ -34,7 +34,7 @@ impl Hash for HSha256 { fn create_hash_from_ge(ge_vec: &[&Point]) -> Scalar { let mut hasher = Sha256::new(); for value in ge_vec { - hasher.input(&value.to_bytes(false)); + hasher.input(&value.to_bytes(false)[..]); } let result_hex = hasher.result(); diff --git a/src/cryptographic_primitives/hashing/hash_sha512.rs b/src/cryptographic_primitives/hashing/hash_sha512.rs index c215410f..2787627c 100644 --- a/src/cryptographic_primitives/hashing/hash_sha512.rs +++ b/src/cryptographic_primitives/hashing/hash_sha512.rs @@ -34,7 +34,7 @@ impl Hash for HSha512 { fn create_hash_from_ge(ge_vec: &[&Point]) -> Scalar { let mut hasher = Sha512::new(); for value in ge_vec { - hasher.input(&value.to_bytes(false)); + hasher.input(&value.to_bytes(false)[..]); } let result_hex = hasher.result(); diff --git a/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs b/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs index b9f2165c..b1578ce1 100644 --- a/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs +++ b/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs @@ -77,13 +77,13 @@ impl Party1FirstMessage { // we use hash based commitment let pk_commitment_blind_factor = BigInt::sample(SECURITY_BITS); let pk_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&public_share.to_bytes(true)), + &BigInt::from_bytes(public_share.to_bytes(true).as_ref()), &pk_commitment_blind_factor, ); let zk_pok_blind_factor = BigInt::sample(SECURITY_BITS); let zk_pok_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&d_log_proof.pk_t_rand_commitment.to_bytes(true)), + &BigInt::from_bytes(d_log_proof.pk_t_rand_commitment.to_bytes(true).as_ref()), &zk_pok_blind_factor, ); let ec_key_pair = EcKeyPair { @@ -115,13 +115,13 @@ impl Party1FirstMessage { let pk_commitment_blind_factor = BigInt::sample(SECURITY_BITS); let pk_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&public_share.to_bytes(true)), + &BigInt::from_bytes(public_share.to_bytes(true).as_ref()), &pk_commitment_blind_factor, ); let zk_pok_blind_factor = BigInt::sample(SECURITY_BITS); let zk_pok_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&d_log_proof.pk_t_rand_commitment.to_bytes(true)), + &BigInt::from_bytes(d_log_proof.pk_t_rand_commitment.to_bytes(true).as_ref()), &zk_pok_blind_factor, ); @@ -214,7 +214,7 @@ impl Party2SecondMessage { let mut flag = true; if party_one_pk_commitment != &HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&party_one_public_share.to_bytes(true)), + &BigInt::from_bytes(party_one_public_share.to_bytes(true).as_ref()), &party_one_pk_commitment_blind_factor, ) { @@ -223,7 +223,12 @@ impl Party2SecondMessage { if party_one_zk_pok_commitment != &HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(&party_one_d_log_proof.pk_t_rand_commitment.to_bytes(true)), + &BigInt::from_bytes( + party_one_d_log_proof + .pk_t_rand_commitment + .to_bytes(true) + .as_ref(), + ), &party_one_zk_pok_blind_factor, ) { diff --git a/src/elliptic/curves/bls12_381/g1.rs b/src/elliptic/curves/bls12_381/g1.rs index 57304fff..79a74b0e 100644 --- a/src/elliptic/curves/bls12_381/g1.rs +++ b/src/elliptic/curves/bls12_381/g1.rs @@ -73,6 +73,9 @@ impl ECPoint for G1Point { type Scalar = FieldScalar; type Underlying = PK; + type CompressedPoint = G1Compressed; + type UncompressedPoint = G1Uncompressed; + fn zero() -> G1Point { G1Point { purpose: "zero", @@ -148,23 +151,16 @@ impl ECPoint for G1Point { } } - fn serialize(&self, compressed: bool) -> Vec { - if self.is_zero() { - vec![0] - } else if compressed { - G1Compressed::from_affine(self.ge).as_ref().to_vec() - } else { - G1Uncompressed::from_affine(self.ge).as_ref().to_vec() - } + fn serialize_compressed(&self) -> Self::CompressedPoint { + G1Compressed::from_affine(self.ge) + } + + fn serialize_uncompressed(&self) -> Self::UncompressedPoint { + G1Uncompressed::from_affine(self.ge) } fn deserialize(bytes: &[u8]) -> Result { - if bytes == [0] { - Ok(G1Point { - purpose: "deserialize", - ge: Self::zero().ge, - }) - } else if bytes.len() == COMPRESSED_SIZE { + if bytes.len() == COMPRESSED_SIZE { let mut compressed = G1Compressed::empty(); compressed.as_mut().copy_from_slice(bytes); Ok(G1Point { @@ -264,7 +260,7 @@ impl fmt::Debug for G1Point { f, "Point {{ purpose: {:?}, uncompressed: {:?} }}", self.purpose, - hex::encode(self.serialize(false)), + hex::encode(self.serialize_uncompressed()), ) } } diff --git a/src/elliptic/curves/bls12_381/g2.rs b/src/elliptic/curves/bls12_381/g2.rs index 0a95c579..6bddcc7c 100644 --- a/src/elliptic/curves/bls12_381/g2.rs +++ b/src/elliptic/curves/bls12_381/g2.rs @@ -80,6 +80,9 @@ impl ECPoint for G2Point { type Scalar = FieldScalar; type Underlying = PK; + type CompressedPoint = G2Compressed; + type UncompressedPoint = G2Uncompressed; + fn zero() -> G2Point { G2Point { purpose: "zero", @@ -155,23 +158,16 @@ impl ECPoint for G2Point { } } - fn serialize(&self, compressed: bool) -> Vec { - if self.is_zero() { - vec![0] - } else if compressed { - G2Compressed::from_affine(self.ge).as_ref().to_vec() - } else { - G2Uncompressed::from_affine(self.ge).as_ref().to_vec() - } + fn serialize_compressed(&self) -> Self::CompressedPoint { + G2Compressed::from_affine(self.ge) + } + + fn serialize_uncompressed(&self) -> Self::UncompressedPoint { + G2Uncompressed::from_affine(self.ge) } fn deserialize(bytes: &[u8]) -> Result { - if bytes == [0] { - Ok(G2Point { - purpose: "deserialize", - ge: Self::zero().ge, - }) - } else if bytes.len() == COMPRESSED_SIZE { + if bytes.len() == COMPRESSED_SIZE { let mut compressed = G2Compressed::empty(); compressed.as_mut().copy_from_slice(bytes); Ok(G2Point { @@ -271,7 +267,7 @@ impl fmt::Debug for G2Point { f, "Point {{ purpose: {:?}, uncompressed: {:?} }}", self.purpose, - hex::encode(self.serialize(false)), + hex::encode(self.serialize_uncompressed()), ) } } diff --git a/src/elliptic/curves/curve_ristretto.rs b/src/elliptic/curves/curve_ristretto.rs index fe16e637..49e64745 100644 --- a/src/elliptic/curves/curve_ristretto.rs +++ b/src/elliptic/curves/curve_ristretto.rs @@ -35,7 +35,7 @@ lazy_static::lazy_static! { static ref BASE_POINT2: RistrettoPoint = { let g = RistrettoPoint::generator(); - let hash = Sha256::digest(&g.serialize(true)); + let hash = Sha256::digest(g.serialize_compressed().as_ref()); RistrettoPoint { purpose: "base_point2", ge: RistrettoPoint::deserialize(&hash).unwrap().ge, @@ -207,6 +207,9 @@ impl ECPoint for RistrettoPoint { type Scalar = RistrettoScalar; type Underlying = PK; + type CompressedPoint = [u8; 32]; + type UncompressedPoint = [u8; 32]; + fn zero() -> RistrettoPoint { RistrettoPoint { purpose: "zero", @@ -248,9 +251,14 @@ impl ECPoint for RistrettoPoint { None } - fn serialize(&self, _compressed: bool) -> Vec { - self.ge.compress().to_bytes().to_vec() + fn serialize_compressed(&self) -> Self::CompressedPoint { + self.ge.compress().to_bytes() + } + + fn serialize_uncompressed(&self) -> Self::UncompressedPoint { + self.ge.compress().to_bytes() } + fn deserialize(bytes: &[u8]) -> Result { let mut buffer = [0u8; 32]; let n = bytes.len(); diff --git a/src/elliptic/curves/ed25519.rs b/src/elliptic/curves/ed25519.rs index 87ef8509..1679a9b9 100644 --- a/src/elliptic/curves/ed25519.rs +++ b/src/elliptic/curves/ed25519.rs @@ -52,8 +52,8 @@ lazy_static::lazy_static! { }; static ref BASE_POINT2: Ed25519Point = { - let bytes = GENERATOR.serialize(true); - let hashed = sha2::Sha256::digest(&bytes); + let bytes = GENERATOR.serialize_compressed(); + let hashed = sha2::Sha256::digest(bytes.as_ref()); let hashed_twice = sha2::Sha256::digest(&hashed); let p = Ed25519Point::deserialize(&hashed_twice).unwrap(); let eight = Ed25519Scalar::from_bigint(&BigInt::from(8)); @@ -307,6 +307,9 @@ impl ECPoint for Ed25519Point { type Underlying = PK; type Scalar = Ed25519Scalar; + type CompressedPoint = [u8; 32]; + type UncompressedPoint = [u8; 32]; + fn zero() -> Ed25519Point { *ZERO } @@ -360,8 +363,12 @@ impl ECPoint for Ed25519Point { Some(PointCoords { x: xrecover(&y), y }) } - fn serialize(&self, _compress: bool) -> Vec { - self.ge.to_bytes().to_vec() + fn serialize_compressed(&self) -> Self::CompressedPoint { + self.ge.to_bytes() + } + + fn serialize_uncompressed(&self) -> Self::UncompressedPoint { + self.ge.to_bytes() } fn deserialize(bytes: &[u8]) -> Result { diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index 01e230ba..3de9c1a7 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -97,7 +97,7 @@ pub use self::{ }; pub use self::{ traits::{Curve, ECPoint, ECScalar, PointCoords}, - wrappers::{Generator, Point, PointRef, Scalar}, + wrappers::{EncodedPoint, Generator, Point, PointRef, Scalar}, }; pub mod error { diff --git a/src/elliptic/curves/p256.rs b/src/elliptic/curves/p256.rs index 514fcf12..996aba6a 100644 --- a/src/elliptic/curves/p256.rs +++ b/src/elliptic/curves/p256.rs @@ -217,6 +217,9 @@ impl ECPoint for Secp256r1Point { type Scalar = Secp256r1Scalar; type Underlying = PK; + type CompressedPoint = EncodedPoint; + type UncompressedPoint = EncodedPoint; + fn zero() -> Secp256r1Point { Secp256r1Point { purpose: "zero", @@ -271,8 +274,12 @@ impl ECPoint for Secp256r1Point { Some(PointCoords { x, y }) } - fn serialize(&self, compressed: bool) -> Vec { - self.ge.to_encoded_point(compressed).to_bytes().into() + fn serialize_compressed(&self) -> Self::CompressedPoint { + self.ge.to_encoded_point(true) + } + + fn serialize_uncompressed(&self) -> Self::UncompressedPoint { + self.ge.to_encoded_point(false) } fn deserialize(bytes: &[u8]) -> Result { @@ -362,7 +369,7 @@ mod tests { let base_point2 = GE::base_point2(); let g = GE::generator(); - let hash = Sha256::digest(&g.serialize(true)); + let hash = Sha256::digest(g.serialize_compressed().as_ref()); let hash = Sha256::digest(&hash); assert_eq!(BigInt::from_bytes(&hash), base_point2.x_coord().unwrap()); diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 8a9b937f..3ffb770d 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -316,6 +316,9 @@ impl ECPoint for Secp256k1Point { type Scalar = Secp256k1Scalar; type Underlying = Option; + type CompressedPoint = [u8; 33]; + type UncompressedPoint = [u8; 65]; + fn zero() -> Secp256k1Point { Secp256k1Point { purpose: "zero", @@ -392,16 +395,22 @@ impl ECPoint for Secp256k1Point { } } - fn serialize(&self, compressed: bool) -> Vec { + fn serialize_compressed(&self) -> Self::CompressedPoint { + match self.ge { + None => [0u8; 33], + Some(ge) => ge.serialize(), + } + } + + fn serialize_uncompressed(&self) -> Self::UncompressedPoint { match self.ge { - None => vec![0], - Some(ge) if compressed => ge.serialize().to_vec(), - Some(ge) => ge.serialize_uncompressed().to_vec(), + None => [0u8; 65], + Some(ge) => ge.serialize_uncompressed(), } } fn deserialize(bytes: &[u8]) -> Result { - if bytes == [0] { + if bytes == [0; 33] || bytes == [0; 65] { Ok(Secp256k1Point { purpose: "from_bytes", ge: None, @@ -520,7 +529,7 @@ mod test { let base_point2 = GE::base_point2(); let g = GE::generator(); - let hash = Sha256::digest(&g.serialize(true)); + let hash = Sha256::digest(&g.serialize_compressed()); let hash = Sha256::digest(&hash); let hash = Sha256::digest(&hash); diff --git a/src/elliptic/curves/test.rs b/src/elliptic/curves/test.rs index 2dd97e2c..44eea5e6 100644 --- a/src/elliptic/curves/test.rs +++ b/src/elliptic/curves/test.rs @@ -83,23 +83,24 @@ fn serialize_deserialize_point() { let rand_point = ::generator().scalar_mul(&random_nonzero_scalar()); let zero = E::Point::zero(); for point in [rand_point, zero] { - for compressed in [true, false] { - let bytes = point.serialize(compressed); - let deserialized = ::deserialize(&bytes).unwrap(); - assert_eq!(point, deserialized); - } + let bytes = point.serialize_compressed(); + let deserialized = ::deserialize(bytes.as_ref()).unwrap(); + assert_eq!(point, deserialized); + let bytes = point.serialize_uncompressed(); + let deserialized = ::deserialize(bytes.as_ref()).unwrap(); + assert_eq!(point, deserialized); } } test_for_all_curves!(zero_point_serialization); fn zero_point_serialization() { let point: E::Point = ECPoint::zero(); - let bytes = point.serialize(true); - let point_from_compressed: E::Point = ECPoint::deserialize(&bytes).unwrap(); + let bytes = point.serialize_compressed(); + let point_from_compressed: E::Point = ECPoint::deserialize(bytes.as_ref()).unwrap(); assert_eq!(point, point_from_compressed); - let bytes = point.serialize(false); - let point_from_uncompressed: E::Point = ECPoint::deserialize(&bytes).unwrap(); + let bytes = point.serialize_uncompressed(); + let point_from_uncompressed: E::Point = ECPoint::deserialize(bytes.as_ref()).unwrap(); assert_eq!(point, point_from_uncompressed); } diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 2a0b616c..77de73e3 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -111,6 +111,15 @@ pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug + 'static { /// Underlying curve implementation that can be retrieved in case of missing methods in this trait type Underlying; + /// Point serialized in compressed form + /// + /// Usually represented as byte array `[u8; COMPRESSED_LEN]` + type CompressedPoint: AsRef<[u8]>; + /// Point serialized in uncompressed form + /// + /// Usually represented as byte array `[u8; UNCOMPRESSED_LEN]` + type UncompressedPoint: AsRef<[u8]>; + /// Zero point /// /// Zero point is usually denoted as O. It's curve neutral element, i.e. `forall A. A + O = A`. @@ -149,10 +158,14 @@ pub trait ECPoint: Zeroize + Clone + PartialEq + fmt::Debug + 'static { /// Returns point coordinates (`x` and `y`), or `None` if point is at infinity fn coords(&self) -> Option; - /// Serializes point into bytes either in compressed or uncompressed form + /// Serializes point into bytes in compressed + /// + /// Serialization must always succeed even if it's point at infinity. + fn serialize_compressed(&self) -> Self::CompressedPoint; + /// Serializes point into bytes in uncompressed /// /// Serialization must always succeed even if it's point at infinity. - fn serialize(&self, compressed: bool) -> Vec; + fn serialize_uncompressed(&self) -> Self::UncompressedPoint; /// Deserializes point from bytes /// /// Whether point in compressed or uncompressed form will be deducted from its size diff --git a/src/elliptic/curves/wrappers/encoded_point.rs b/src/elliptic/curves/wrappers/encoded_point.rs new file mode 100644 index 00000000..09d72752 --- /dev/null +++ b/src/elliptic/curves/wrappers/encoded_point.rs @@ -0,0 +1,19 @@ +use std::ops::Deref; + +use crate::elliptic::curves::{Curve, ECPoint}; + +/// Point encoded in (un)compressed form +pub enum EncodedPoint { + Compressed(::CompressedPoint), + Uncompressed(::UncompressedPoint), +} + +impl Deref for EncodedPoint { + type Target = [u8]; + fn deref(&self) -> &[u8] { + match self { + Self::Compressed(bytes) => bytes.as_ref(), + Self::Uncompressed(bytes) => bytes.as_ref(), + } + } +} diff --git a/src/elliptic/curves/wrappers/format.rs b/src/elliptic/curves/wrappers/format.rs index de7cb29c..653b59ca 100644 --- a/src/elliptic/curves/wrappers/format.rs +++ b/src/elliptic/curves/wrappers/format.rs @@ -1,81 +1,14 @@ use std::borrow::Cow; use std::convert::TryFrom; use std::iter; -use std::marker::PhantomData; use serde::{Deserialize, Serialize}; use thiserror::Error; use crate::elliptic::curves::traits::*; -use crate::elliptic::curves::InvalidPoint; use super::*; -#[derive(Serialize, Deserialize)] -#[serde(bound = "")] -pub struct PointFormat { - curve: Cow<'static, str>, - compressed_point: Box<[u8]>, - #[serde(skip, default = "PointFormat::::_ph")] - _ph: PhantomData, -} - -impl PointFormat { - fn _ph() -> PhantomData { - PhantomData - } -} - -impl TryFrom> for Point { - type Error = ConvertParsedPointError; - fn try_from(parsed: PointFormat) -> Result { - if parsed.curve != E::CURVE_NAME { - return Err(ConvertParsedPointError::MismatchedCurve { - expected: E::CURVE_NAME, - got: parsed.curve, - }); - } - let point = E::Point::deserialize(&parsed.compressed_point) - .or(Err(ConvertParsedPointError::NotOnCurve))?; - Point::from_raw(point).or(Err(ConvertParsedPointError::InvalidPoint( - InvalidPoint::MismatchedPointOrder, - ))) - } -} - -impl From> for PointFormat { - fn from(point: Point) -> Self { - Self { - curve: E::CURVE_NAME.into(), - compressed_point: point.as_raw().serialize(true).into(), - _ph: PhantomData, - } - } -} - -impl<'p, E: Curve> From> for PointFormat { - fn from(point: PointRef<'p, E>) -> Self { - Self { - curve: E::CURVE_NAME.into(), - compressed_point: point.as_raw().serialize(true).into(), - _ph: PhantomData, - } - } -} - -#[derive(Debug, Error)] -pub enum ConvertParsedPointError { - #[error("invalid point ({0})")] - InvalidPoint(InvalidPoint), - #[error("expected point of curve {expected}, but got point of curve {got}")] - MismatchedCurve { - got: Cow<'static, str>, - expected: &'static str, - }, - #[error("point not on the curve: x,y don't satisfy curve equation")] - NotOnCurve, -} - #[derive(Serialize, Deserialize)] #[serde(bound = "")] pub struct ScalarFormat { @@ -149,98 +82,3 @@ pub enum ScalarFromhexError { #[error("scalar is not valid")] InvalidScalar, } - -#[cfg(test)] -mod serde_tests { - use crate::elliptic::curves::{ - Bls12_381_1, Bls12_381_2, Curve, ECPoint, ECScalar, Ed25519, Point, Ristretto, Secp256k1, - Secp256r1, - }; - use serde_test::{assert_tokens, Configure, Token::*}; - - #[test] - fn test_serde_zero_point() { - fn generic(serialized_zero_len: usize) { - let point = Point::::zero(); - let mut tokens = vec![ - Struct { - name: "PointFormat", - len: 2, - }, - Str("curve"), - Str(E::CURVE_NAME), - Str("compressed_point"), - ]; - tokens.push(Seq { - len: Option::Some(serialized_zero_len), - }); - - for _ in 0..serialized_zero_len { - tokens.push(U8(0)); - } - tokens.extend_from_slice(&[SeqEnd, StructEnd]); - assert_tokens(&point, &tokens); - } - generic::(1); - generic::(1); - generic::(32); - generic::(1); - generic::(1); - } - - #[test] - fn test_serde_zero_ed25519() { - let point = Point::::zero(); - let mut tokens = vec![ - Struct { - name: "PointFormat", - len: 2, - }, - Str("curve"), - Str(Ed25519::CURVE_NAME), - Str("compressed_point"), - Seq { - len: Option::Some(32), - }, - U8(1), - ]; - for _ in 0..31 { - tokens.push(U8(0)); - } - tokens.extend_from_slice(&[SeqEnd, StructEnd]); - - assert_tokens(&point, &tokens); - } - - #[test] - fn test_serde_random_point() { - fn generic() { - let random_point = E::Point::generator_mul(&E::Scalar::random()); - let point: Point = Point::from_raw(random_point).unwrap(); - let serialized = ECPoint::serialize(point.as_raw(), true); - let mut tokens = vec![ - Struct { - name: "PointFormat", - len: 2, - }, - Str("curve"), - Str(E::CURVE_NAME), - Str("compressed_point"), - ]; - tokens.push(Seq { - len: Option::Some(serialized.len()), - }); - - for i in serialized { - tokens.push(U8(i)); - } - tokens.extend_from_slice(&[SeqEnd, StructEnd]); - assert_tokens(&point.compact(), &tokens); - } - generic::(); - generic::(); - generic::(); - generic::(); - generic::(); - } -} diff --git a/src/elliptic/curves/wrappers/mod.rs b/src/elliptic/curves/wrappers/mod.rs index 7bd58128..36d11a49 100644 --- a/src/elliptic/curves/wrappers/mod.rs +++ b/src/elliptic/curves/wrappers/mod.rs @@ -1,4 +1,5 @@ mod arithmetic; +mod encoded_point; pub mod error; mod format; mod generator; @@ -6,4 +7,7 @@ mod point; mod point_ref; mod scalar; -pub use self::{generator::Generator, point::Point, point_ref::PointRef, scalar::Scalar}; +pub use self::{ + encoded_point::EncodedPoint, generator::Generator, point::Point, point_ref::PointRef, + scalar::Scalar, +}; diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index 3a4c9adf..cbbe2560 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -1,16 +1,17 @@ +use std::marker::PhantomData; use std::{fmt, iter}; +use serde::de::{Deserializer, Error, MapAccess, Visitor}; +use serde::ser::Serializer; use serde::{Deserialize, Serialize}; use crate::elliptic::curves::traits::*; use crate::BigInt; use super::{ - error::{MismatchedPointOrder, PointFromBytesError, PointFromCoordsError}, - format::PointFormat, - Generator, PointRef, + error::{MismatchedPointOrder, PointFromBytesError, PointFromCoordsError, ZeroPointError}, + EncodedPoint, Generator, PointRef, }; -use crate::elliptic::curves::ZeroPointError; /// Elliptic point of a [group order](super::Scalar::group_order), or a zero point /// @@ -54,8 +55,6 @@ use crate::elliptic::curves::ZeroPointError; /// a + b * c /// } /// ``` -#[derive(Serialize, Deserialize)] -#[serde(try_from = "PointFormat", into = "PointFormat", bound = "")] pub struct Point { raw_point: E::Point, } @@ -150,15 +149,19 @@ impl Point { /// Tries to parse a point in (un)compressed form /// /// Whether it's in compressed or uncompressed form will be deduced from its length - pub fn from_bytes(bytes: &[u8]) -> Result { - let p = E::Point::deserialize(bytes) + pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result { + let p = E::Point::deserialize(bytes.as_ref()) .map_err(|_: DeserializationError| PointFromBytesError::DeserializationError)?; Self::from_raw(p).map_err(PointFromBytesError::InvalidPoint) } /// Serializes a point in (un)compressed form - pub fn to_bytes(&self, compressed: bool) -> Vec { - self.as_raw().serialize(compressed) + pub fn to_bytes(&self, compressed: bool) -> EncodedPoint { + if compressed { + EncodedPoint::Compressed(self.as_raw().serialize_compressed()) + } else { + EncodedPoint::Uncompressed(self.as_raw().serialize_uncompressed()) + } } /// Constructs a `Point` from low-level [ECPoint] implementor @@ -280,3 +283,177 @@ impl<'p, E: Curve> iter::Sum> for Point { iter.fold(Point::zero(), |acc, p| acc + p) } } + +impl Serialize for Point { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_point().serialize(serializer) + } +} + +impl<'de, E: Curve> Deserialize<'de> for Point { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PointVisitor(PhantomData); + + impl<'de, E: Curve> Visitor<'de> for PointVisitor { + type Value = Point; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "point of {} curve", E::CURVE_NAME) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut curve_name: Option> = None; + let mut point: Option> = None; + + while let Some(key) = map.next_key()? { + match key { + Field::Curve => { + if curve_name.is_some() { + return Err(A::Error::duplicate_field("curve_name")); + } + curve_name = Some(map.next_value()?) + } + Field::Point => { + if point.is_some() { + return Err(A::Error::duplicate_field("point")); + } + point = Some(map.next_value()?) + } + } + } + let _curve_name = + curve_name.ok_or_else(|| A::Error::missing_field("curve_name"))?; + let point = point.ok_or_else(|| A::Error::missing_field("point"))?; + Ok(point.0) + } + } + + deserializer.deserialize_struct("Point", &["curve", "point"], PointVisitor(PhantomData)) + } +} + +#[derive(Deserialize)] +#[serde(field_identifier, rename_all = "snake_case")] +enum Field { + Curve, + Point, +} + +/// Efficient guard for asserting that deserialized `&str`/`String` is `E::CURVE_NAME` +pub(super) struct CurveNameGuard(PhantomData); + +impl<'de, E: Curve> Deserialize<'de> for CurveNameGuard { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct CurveNameVisitor(PhantomData); + + impl<'de, E: Curve> Visitor<'de> for CurveNameVisitor { + type Value = (); + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "curve name (constrained to be '{}')", E::CURVE_NAME) + } + + fn visit_str(self, v: &str) -> Result + where + Err: Error, + { + if v == E::CURVE_NAME { + Ok(()) + } else { + Err(Err::invalid_value( + serde::de::Unexpected::Str(v), + &E::CURVE_NAME, + )) + } + } + } + + deserializer + .deserialize_str(CurveNameVisitor(PhantomData::)) + .map(|_| CurveNameGuard(PhantomData)) + } +} + +struct PointFromBytes(Point); + +impl<'de, E: Curve> Deserialize<'de> for PointFromBytes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PointBytesVisitor(PhantomData); + + impl<'de, E: Curve> Visitor<'de> for PointBytesVisitor { + type Value = Point; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "point of {} curve", E::CURVE_NAME) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + Err: Error, + { + Point::from_bytes(v).map_err(|e| Err::custom(format!("invalid point: {}", e))) + } + } + + deserializer + .deserialize_bytes(PointBytesVisitor(PhantomData)) + .map(PointFromBytes) + } +} + +#[cfg(test)] +mod serde_tests { + use serde_test::{assert_tokens, Token::*}; + + use crate::elliptic::curves::*; + + #[test] + fn test_serde_point() { + fn generic(point: Point) { + let bytes = point.to_bytes(true).to_vec(); + let tokens = vec![ + Struct { + name: "Point", + len: 2, + }, + Str("curve"), + Str(E::CURVE_NAME), + Str("point"), + Bytes(bytes.leak()), + StructEnd, + ]; + assert_tokens(&point, &tokens); + } + + // Test **zero points** (de)serializing + generic::(Point::zero()); + generic::(Point::zero()); + generic::(Point::zero()); + generic::(Point::zero()); + generic::(Point::zero()); + generic::(Point::zero()); + + // Test **random point** (de)serializing + generic::(Point::generator() * Scalar::random()); + generic::(Point::generator() * Scalar::random()); + generic::(Point::generator() * Scalar::random()); + generic::(Point::generator() * Scalar::random()); + generic::(Point::generator() * Scalar::random()); + generic::(Point::generator() * Scalar::random()); + } +} diff --git a/src/elliptic/curves/wrappers/point_ref.rs b/src/elliptic/curves/wrappers/point_ref.rs index 1b181782..61fd9399 100644 --- a/src/elliptic/curves/wrappers/point_ref.rs +++ b/src/elliptic/curves/wrappers/point_ref.rs @@ -1,18 +1,16 @@ use std::fmt; -use serde::Serialize; +use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::elliptic::curves::traits::*; use crate::BigInt; -use super::{error::MismatchedPointOrder, format::PointFormat, Generator, Point}; +use super::{error::MismatchedPointOrder, EncodedPoint, Generator, Point}; /// Holds a reference to elliptic point of [group order](super::Scalar::group_order) or to zero point /// /// Holds internally a reference to [`Point`](Point), refer to its documentation to learn /// more about Point/PointRef guarantees, security notes, and arithmetics. -#[derive(Serialize)] -#[serde(into = "PointFormat", bound = "")] pub struct PointRef<'p, E: Curve> { raw_point: &'p E::Point, } @@ -56,8 +54,12 @@ where } /// Serializes point into (un)compressed form - pub fn to_bytes(self, compressed: bool) -> Vec { - self.as_raw().serialize(compressed) + pub fn to_bytes(self, compressed: bool) -> EncodedPoint { + if compressed { + EncodedPoint::Compressed(self.as_raw().serialize_compressed()) + } else { + EncodedPoint::Uncompressed(self.as_raw().serialize_uncompressed()) + } } /// Clones the referenced point @@ -161,3 +163,21 @@ impl From> for PointRef<'static, E> { unsafe { PointRef::from_raw_unchecked(g.as_raw()) } } } + +impl<'p, E: Curve> Serialize for PointRef<'p, E> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde_bytes::Bytes; + + let mut s = serializer.serialize_struct("Point", 2)?; + s.serialize_field("curve", E::CURVE_NAME)?; + s.serialize_field( + "point", + // Serializes bytes efficiently + Bytes::new(&self.to_bytes(true)), + )?; + s.end() + } +} From fc6e894dd37a93d58af21ea879b9b8789b01c381 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 26 Jul 2021 21:17:23 +0300 Subject: [PATCH 88/93] Improve scalar serialization --- src/elliptic/curves/bls12_381/scalar.rs | 8 +- src/elliptic/curves/curve_ristretto.rs | 6 +- src/elliptic/curves/ed25519.rs | 6 +- src/elliptic/curves/mod.rs | 2 +- src/elliptic/curves/p256.rs | 6 +- src/elliptic/curves/secp256_k1.rs | 17 +- src/elliptic/curves/test.rs | 2 +- src/elliptic/curves/traits.rs | 5 +- .../curves/wrappers/encoded_scalar.rs | 29 ++++ src/elliptic/curves/wrappers/mod.rs | 5 +- src/elliptic/curves/wrappers/scalar.rs | 164 +++++++++++++++++- 11 files changed, 224 insertions(+), 26 deletions(-) create mode 100644 src/elliptic/curves/wrappers/encoded_scalar.rs diff --git a/src/elliptic/curves/bls12_381/scalar.rs b/src/elliptic/curves/bls12_381/scalar.rs index 6360463a..66b7d40a 100644 --- a/src/elliptic/curves/bls12_381/scalar.rs +++ b/src/elliptic/curves/bls12_381/scalar.rs @@ -38,6 +38,8 @@ pub struct FieldScalar { impl ECScalar for FieldScalar { type Underlying = SK; + type ScalarBytes = [u8; 32]; + fn random() -> FieldScalar { FieldScalar { purpose: "random", @@ -73,10 +75,10 @@ impl ECScalar for FieldScalar { BigInt::from_bytes(&bytes) } - fn serialize(&self) -> Vec { + fn serialize(&self) -> Self::ScalarBytes { let repr = self.fe.into_repr(); - let mut bytes = Vec::with_capacity(SECRET_KEY_SIZE); - repr.write_be(&mut bytes).unwrap(); + let mut bytes = [0u8; SECRET_KEY_SIZE]; + repr.write_be(&mut bytes[..]).unwrap(); bytes } diff --git a/src/elliptic/curves/curve_ristretto.rs b/src/elliptic/curves/curve_ristretto.rs index 49e64745..24cf2bd8 100644 --- a/src/elliptic/curves/curve_ristretto.rs +++ b/src/elliptic/curves/curve_ristretto.rs @@ -83,6 +83,8 @@ impl Curve for Ristretto { impl ECScalar for RistrettoScalar { type Underlying = SK; + type ScalarBytes = [u8; 32]; + fn random() -> RistrettoScalar { RistrettoScalar { purpose: "random", @@ -116,8 +118,8 @@ impl ECScalar for RistrettoScalar { BigInt::from_bytes(&t) } - fn serialize(&self) -> Vec { - self.fe.to_bytes().to_vec() + fn serialize(&self) -> Self::ScalarBytes { + self.fe.to_bytes() } fn deserialize(bytes: &[u8]) -> Result { diff --git a/src/elliptic/curves/ed25519.rs b/src/elliptic/curves/ed25519.rs index 1679a9b9..d3140a30 100644 --- a/src/elliptic/curves/ed25519.rs +++ b/src/elliptic/curves/ed25519.rs @@ -126,6 +126,8 @@ impl Curve for Ed25519 { impl ECScalar for Ed25519Scalar { type Underlying = SK; + type ScalarBytes = [u8; 32]; + // we chose to multiply by 8 (co-factor) all group elements to work in the prime order sub group. // each random fe is having its 3 first bits zeroed fn random() -> Ed25519Scalar { @@ -171,8 +173,8 @@ impl ECScalar for Ed25519Scalar { BigInt::from_bytes(&t) } - fn serialize(&self) -> Vec { - self.fe.to_bytes().to_vec() + fn serialize(&self) -> Self::ScalarBytes { + self.fe.to_bytes() } fn deserialize(bytes: &[u8]) -> Result { diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index 3de9c1a7..ee8bd044 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -97,7 +97,7 @@ pub use self::{ }; pub use self::{ traits::{Curve, ECPoint, ECScalar, PointCoords}, - wrappers::{EncodedPoint, Generator, Point, PointRef, Scalar}, + wrappers::{EncodedPoint, EncodedScalar, Generator, Point, PointRef, Scalar}, }; pub mod error { diff --git a/src/elliptic/curves/p256.rs b/src/elliptic/curves/p256.rs index 996aba6a..2d4e6dfd 100644 --- a/src/elliptic/curves/p256.rs +++ b/src/elliptic/curves/p256.rs @@ -84,6 +84,8 @@ impl Curve for Secp256r1 { impl ECScalar for Secp256r1Scalar { type Underlying = SK; + type ScalarBytes = FieldBytes; + fn random() -> Secp256r1Scalar { let mut rng = thread_rng(); let scalar = loop { @@ -127,8 +129,8 @@ impl ECScalar for Secp256r1Scalar { BigInt::from_bytes(self.fe.to_bytes().as_slice()) } - fn serialize(&self) -> Vec { - self.fe.to_bytes().to_vec() + fn serialize(&self) -> Self::ScalarBytes { + self.fe.to_bytes() } fn deserialize(bytes: &[u8]) -> Result { diff --git a/src/elliptic/curves/secp256_k1.rs b/src/elliptic/curves/secp256_k1.rs index 3ffb770d..9724a92c 100644 --- a/src/elliptic/curves/secp256_k1.rs +++ b/src/elliptic/curves/secp256_k1.rs @@ -155,6 +155,8 @@ type FE = Secp256k1Scalar; impl ECScalar for Secp256k1Scalar { type Underlying = Option; + type ScalarBytes = [u8; 32]; + fn random() -> Secp256k1Scalar { let sk = SK(SecretKey::new(&mut rand_legacy::thread_rng())); Secp256k1Scalar { @@ -201,16 +203,15 @@ impl ECScalar for Secp256k1Scalar { } } - fn serialize(&self) -> Vec { - let scalar = match &*self.fe { - Some(s) => s, - None => return vec![0u8], - }; - scalar.0[..].to_vec() + fn serialize(&self) -> Self::ScalarBytes { + match &*self.fe { + Some(s) => *s.as_ref(), + None => [0u8; 32], + } } fn deserialize(bytes: &[u8]) -> Result { - let pk = if bytes == [0] { + let sk = if bytes == [0; 32] { None } else { Some(SK( @@ -219,7 +220,7 @@ impl ECScalar for Secp256k1Scalar { }; Ok(Secp256k1Scalar { purpose: "deserialize", - fe: pk.into(), + fe: sk.into(), }) } diff --git a/src/elliptic/curves/test.rs b/src/elliptic/curves/test.rs index 44eea5e6..2dc5dccd 100644 --- a/src/elliptic/curves/test.rs +++ b/src/elliptic/curves/test.rs @@ -301,7 +301,7 @@ fn serialize_deserialize_scalar() { let zero = E::Scalar::zero(); for scalar in [rand_point, zero] { let bytes = scalar.serialize(); - let deserialized = ::deserialize(&bytes).unwrap(); + let deserialized = ::deserialize(bytes.as_ref()).unwrap(); assert_eq!(scalar, deserialized); } } diff --git a/src/elliptic/curves/traits.rs b/src/elliptic/curves/traits.rs index 77de73e3..e7f0dc0f 100644 --- a/src/elliptic/curves/traits.rs +++ b/src/elliptic/curves/traits.rs @@ -37,6 +37,9 @@ pub trait ECScalar: Clone + PartialEq + fmt::Debug + 'static { /// Underlying scalar type that can be retrieved in case of missing methods in this trait type Underlying; + /// Serialized scalar + type ScalarBytes: AsRef<[u8]>; + /// Samples a random scalar fn random() -> Self; @@ -52,7 +55,7 @@ pub trait ECScalar: Clone + PartialEq + fmt::Debug + 'static { /// Converts a scalar to BigInt fn to_bigint(&self) -> BigInt; /// Serializes scalar into bytes - fn serialize(&self) -> Vec; + fn serialize(&self) -> Self::ScalarBytes; /// Deserializes scalar from bytes fn deserialize(bytes: &[u8]) -> Result; diff --git a/src/elliptic/curves/wrappers/encoded_scalar.rs b/src/elliptic/curves/wrappers/encoded_scalar.rs new file mode 100644 index 00000000..a0319fc3 --- /dev/null +++ b/src/elliptic/curves/wrappers/encoded_scalar.rs @@ -0,0 +1,29 @@ +use std::ops::Deref; + +use crate::elliptic::curves::{Curve, ECScalar, Scalar}; + +/// Encoded scalar +pub struct EncodedScalar { + bytes: ::ScalarBytes, +} + +impl Deref for EncodedScalar { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + self.bytes.as_ref() + } +} + +impl<'s, E: Curve> From<&'s Scalar> for EncodedScalar { + fn from(s: &'s Scalar) -> Self { + Self { + bytes: s.as_raw().serialize(), + } + } +} + +impl From> for EncodedScalar { + fn from(s: Scalar) -> Self { + Self::from(&s) + } +} diff --git a/src/elliptic/curves/wrappers/mod.rs b/src/elliptic/curves/wrappers/mod.rs index 36d11a49..34fa2861 100644 --- a/src/elliptic/curves/wrappers/mod.rs +++ b/src/elliptic/curves/wrappers/mod.rs @@ -1,5 +1,6 @@ mod arithmetic; mod encoded_point; +mod encoded_scalar; pub mod error; mod format; mod generator; @@ -8,6 +9,6 @@ mod point_ref; mod scalar; pub use self::{ - encoded_point::EncodedPoint, generator::Generator, point::Point, point_ref::PointRef, - scalar::Scalar, + encoded_point::EncodedPoint, encoded_scalar::EncodedScalar, generator::Generator, point::Point, + point_ref::PointRef, scalar::Scalar, }; diff --git a/src/elliptic/curves/wrappers/scalar.rs b/src/elliptic/curves/wrappers/scalar.rs index 2e968cf2..5bbab286 100644 --- a/src/elliptic/curves/wrappers/scalar.rs +++ b/src/elliptic/curves/wrappers/scalar.rs @@ -1,12 +1,17 @@ +use std::marker::PhantomData; use std::{fmt, iter}; +use serde::de::{Error, MapAccess, Visitor}; +use serde::ser::SerializeStruct; use serde::{Deserialize, Serialize}; +use serde::{Deserializer, Serializer}; use crate::elliptic::curves::traits::{Curve, ECScalar}; use crate::BigInt; -use super::format::ScalarFormat; -use crate::elliptic::curves::ZeroScalarError; +use super::point::CurveNameGuard; +use crate::elliptic::curves::wrappers::encoded_scalar::EncodedScalar; +use crate::elliptic::curves::{DeserializationError, ZeroScalarError}; /// Scalar value in a prime field /// @@ -35,8 +40,6 @@ use crate::elliptic::curves::ZeroScalarError; /// a + b * c /// } /// ``` -#[derive(Serialize, Deserialize)] -#[serde(try_from = "ScalarFormat", into = "ScalarFormat", bound = "")] pub struct Scalar { raw_scalar: E::Scalar, } @@ -81,6 +84,16 @@ impl Scalar { Self::from_raw(E::Scalar::from_bigint(n)) } + /// Serializes a scalar to bytes + pub fn to_bytes(&self) -> EncodedScalar { + EncodedScalar::from(self) + } + + /// Constructs a scalar from bytes + pub fn from_bytes(bytes: &[u8]) -> Result { + ECScalar::deserialize(bytes).map(Self::from_raw) + } + /// Returns an order of generator point pub fn group_order() -> &'static BigInt { E::Scalar::group_order() @@ -200,3 +213,146 @@ impl<'s, E: Curve> iter::Product<&'s Scalar> for Scalar { iter.fold(Scalar::from(1), |acc, s| acc * s) } } + +impl Serialize for Scalar { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut s = serializer.serialize_struct("Scalar", 2)?; + s.serialize_field("curve", E::CURVE_NAME)?; + s.serialize_field( + "scalar", + // Serializes bytes efficiently + serde_bytes::Bytes::new(&self.to_bytes()), + )?; + s.end() + } +} + +impl<'de, E: Curve> Deserialize<'de> for Scalar { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ScalarVisitor(PhantomData); + + impl<'de, E: Curve> Visitor<'de> for ScalarVisitor { + type Value = Scalar; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "scalar of {} curve", E::CURVE_NAME) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut curve_name: Option> = None; + let mut scalar: Option> = None; + + while let Some(key) = map.next_key()? { + match key { + Field::Curve => { + if curve_name.is_some() { + return Err(A::Error::duplicate_field("curve_name")); + } + curve_name = Some(map.next_value()?) + } + Field::Scalar => { + if scalar.is_some() { + return Err(A::Error::duplicate_field("scalar")); + } + scalar = Some(map.next_value()?) + } + } + } + let _curve_name = + curve_name.ok_or_else(|| A::Error::missing_field("curve_name"))?; + let scalar = scalar.ok_or_else(|| A::Error::missing_field("scalar"))?; + Ok(scalar.0) + } + } + + deserializer.deserialize_struct("Scalar", &["curve", "scalar"], ScalarVisitor(PhantomData)) + } +} + +struct ScalarFromBytes(Scalar); + +impl<'de, E: Curve> Deserialize<'de> for ScalarFromBytes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ScalarBytesVisitor(PhantomData); + + impl<'de, E: Curve> Visitor<'de> for ScalarBytesVisitor { + type Value = Scalar; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "scalar value of {} curve", E::CURVE_NAME) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + Err: Error, + { + Scalar::from_bytes(v).map_err(|_| Err::custom("invalid scalar")) + } + } + + deserializer + .deserialize_bytes(ScalarBytesVisitor(PhantomData)) + .map(ScalarFromBytes) + } +} + +#[derive(Deserialize)] +#[serde(field_identifier, rename_all = "snake_case")] +enum Field { + Curve, + Scalar, +} + +#[cfg(test)] +mod serde_tests { + use serde_test::{assert_tokens, Token::*}; + + use crate::elliptic::curves::*; + + #[test] + fn test_serde_scalar() { + fn generic(scalar: Scalar) { + let bytes = scalar.to_bytes().to_vec(); + let tokens = vec![ + Struct { + name: "Scalar", + len: 2, + }, + Str("curve"), + Str(E::CURVE_NAME), + Str("scalar"), + Bytes(bytes.leak()), + StructEnd, + ]; + assert_tokens(&scalar, &tokens); + } + + // Test **zero scalars** (de)serializing + generic::(Scalar::zero()); + generic::(Scalar::zero()); + generic::(Scalar::zero()); + generic::(Scalar::zero()); + generic::(Scalar::zero()); + generic::(Scalar::zero()); + + // Test **random scalars** (de)serializing + generic::(Scalar::random()); + generic::(Scalar::random()); + generic::(Scalar::random()); + generic::(Scalar::random()); + generic::(Scalar::random()); + generic::(Scalar::random()); + } +} From 5abd70a96838107e50ead12cf9db5c6812ba3ed0 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 26 Jul 2021 21:16:30 +0300 Subject: [PATCH 89/93] Move serde-related stuff to dedicated module --- src/elliptic/curves/wrappers/mod.rs | 1 + src/elliptic/curves/wrappers/point.rs | 179 ---------- src/elliptic/curves/wrappers/scalar.rs | 150 -------- src/elliptic/curves/wrappers/serde_support.rs | 326 ++++++++++++++++++ 4 files changed, 327 insertions(+), 329 deletions(-) create mode 100644 src/elliptic/curves/wrappers/serde_support.rs diff --git a/src/elliptic/curves/wrappers/mod.rs b/src/elliptic/curves/wrappers/mod.rs index 34fa2861..4898f08f 100644 --- a/src/elliptic/curves/wrappers/mod.rs +++ b/src/elliptic/curves/wrappers/mod.rs @@ -7,6 +7,7 @@ mod generator; mod point; mod point_ref; mod scalar; +mod serde_support; pub use self::{ encoded_point::EncodedPoint, encoded_scalar::EncodedScalar, generator::Generator, point::Point, diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index cbbe2560..17937ed2 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -1,10 +1,5 @@ -use std::marker::PhantomData; use std::{fmt, iter}; -use serde::de::{Deserializer, Error, MapAccess, Visitor}; -use serde::ser::Serializer; -use serde::{Deserialize, Serialize}; - use crate::elliptic::curves::traits::*; use crate::BigInt; @@ -283,177 +278,3 @@ impl<'p, E: Curve> iter::Sum> for Point { iter.fold(Point::zero(), |acc, p| acc + p) } } - -impl Serialize for Point { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.as_point().serialize(serializer) - } -} - -impl<'de, E: Curve> Deserialize<'de> for Point { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct PointVisitor(PhantomData); - - impl<'de, E: Curve> Visitor<'de> for PointVisitor { - type Value = Point; - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "point of {} curve", E::CURVE_NAME) - } - - fn visit_map(self, mut map: A) -> Result - where - A: MapAccess<'de>, - { - let mut curve_name: Option> = None; - let mut point: Option> = None; - - while let Some(key) = map.next_key()? { - match key { - Field::Curve => { - if curve_name.is_some() { - return Err(A::Error::duplicate_field("curve_name")); - } - curve_name = Some(map.next_value()?) - } - Field::Point => { - if point.is_some() { - return Err(A::Error::duplicate_field("point")); - } - point = Some(map.next_value()?) - } - } - } - let _curve_name = - curve_name.ok_or_else(|| A::Error::missing_field("curve_name"))?; - let point = point.ok_or_else(|| A::Error::missing_field("point"))?; - Ok(point.0) - } - } - - deserializer.deserialize_struct("Point", &["curve", "point"], PointVisitor(PhantomData)) - } -} - -#[derive(Deserialize)] -#[serde(field_identifier, rename_all = "snake_case")] -enum Field { - Curve, - Point, -} - -/// Efficient guard for asserting that deserialized `&str`/`String` is `E::CURVE_NAME` -pub(super) struct CurveNameGuard(PhantomData); - -impl<'de, E: Curve> Deserialize<'de> for CurveNameGuard { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct CurveNameVisitor(PhantomData); - - impl<'de, E: Curve> Visitor<'de> for CurveNameVisitor { - type Value = (); - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "curve name (constrained to be '{}')", E::CURVE_NAME) - } - - fn visit_str(self, v: &str) -> Result - where - Err: Error, - { - if v == E::CURVE_NAME { - Ok(()) - } else { - Err(Err::invalid_value( - serde::de::Unexpected::Str(v), - &E::CURVE_NAME, - )) - } - } - } - - deserializer - .deserialize_str(CurveNameVisitor(PhantomData::)) - .map(|_| CurveNameGuard(PhantomData)) - } -} - -struct PointFromBytes(Point); - -impl<'de, E: Curve> Deserialize<'de> for PointFromBytes { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct PointBytesVisitor(PhantomData); - - impl<'de, E: Curve> Visitor<'de> for PointBytesVisitor { - type Value = Point; - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "point of {} curve", E::CURVE_NAME) - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - Err: Error, - { - Point::from_bytes(v).map_err(|e| Err::custom(format!("invalid point: {}", e))) - } - } - - deserializer - .deserialize_bytes(PointBytesVisitor(PhantomData)) - .map(PointFromBytes) - } -} - -#[cfg(test)] -mod serde_tests { - use serde_test::{assert_tokens, Token::*}; - - use crate::elliptic::curves::*; - - #[test] - fn test_serde_point() { - fn generic(point: Point) { - let bytes = point.to_bytes(true).to_vec(); - let tokens = vec![ - Struct { - name: "Point", - len: 2, - }, - Str("curve"), - Str(E::CURVE_NAME), - Str("point"), - Bytes(bytes.leak()), - StructEnd, - ]; - assert_tokens(&point, &tokens); - } - - // Test **zero points** (de)serializing - generic::(Point::zero()); - generic::(Point::zero()); - generic::(Point::zero()); - generic::(Point::zero()); - generic::(Point::zero()); - generic::(Point::zero()); - - // Test **random point** (de)serializing - generic::(Point::generator() * Scalar::random()); - generic::(Point::generator() * Scalar::random()); - generic::(Point::generator() * Scalar::random()); - generic::(Point::generator() * Scalar::random()); - generic::(Point::generator() * Scalar::random()); - generic::(Point::generator() * Scalar::random()); - } -} diff --git a/src/elliptic/curves/wrappers/scalar.rs b/src/elliptic/curves/wrappers/scalar.rs index 5bbab286..0fa6e485 100644 --- a/src/elliptic/curves/wrappers/scalar.rs +++ b/src/elliptic/curves/wrappers/scalar.rs @@ -1,15 +1,8 @@ -use std::marker::PhantomData; use std::{fmt, iter}; -use serde::de::{Error, MapAccess, Visitor}; -use serde::ser::SerializeStruct; -use serde::{Deserialize, Serialize}; -use serde::{Deserializer, Serializer}; - use crate::elliptic::curves::traits::{Curve, ECScalar}; use crate::BigInt; -use super::point::CurveNameGuard; use crate::elliptic::curves::wrappers::encoded_scalar::EncodedScalar; use crate::elliptic::curves::{DeserializationError, ZeroScalarError}; @@ -213,146 +206,3 @@ impl<'s, E: Curve> iter::Product<&'s Scalar> for Scalar { iter.fold(Scalar::from(1), |acc, s| acc * s) } } - -impl Serialize for Scalar { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut s = serializer.serialize_struct("Scalar", 2)?; - s.serialize_field("curve", E::CURVE_NAME)?; - s.serialize_field( - "scalar", - // Serializes bytes efficiently - serde_bytes::Bytes::new(&self.to_bytes()), - )?; - s.end() - } -} - -impl<'de, E: Curve> Deserialize<'de> for Scalar { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct ScalarVisitor(PhantomData); - - impl<'de, E: Curve> Visitor<'de> for ScalarVisitor { - type Value = Scalar; - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "scalar of {} curve", E::CURVE_NAME) - } - - fn visit_map(self, mut map: A) -> Result - where - A: MapAccess<'de>, - { - let mut curve_name: Option> = None; - let mut scalar: Option> = None; - - while let Some(key) = map.next_key()? { - match key { - Field::Curve => { - if curve_name.is_some() { - return Err(A::Error::duplicate_field("curve_name")); - } - curve_name = Some(map.next_value()?) - } - Field::Scalar => { - if scalar.is_some() { - return Err(A::Error::duplicate_field("scalar")); - } - scalar = Some(map.next_value()?) - } - } - } - let _curve_name = - curve_name.ok_or_else(|| A::Error::missing_field("curve_name"))?; - let scalar = scalar.ok_or_else(|| A::Error::missing_field("scalar"))?; - Ok(scalar.0) - } - } - - deserializer.deserialize_struct("Scalar", &["curve", "scalar"], ScalarVisitor(PhantomData)) - } -} - -struct ScalarFromBytes(Scalar); - -impl<'de, E: Curve> Deserialize<'de> for ScalarFromBytes { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct ScalarBytesVisitor(PhantomData); - - impl<'de, E: Curve> Visitor<'de> for ScalarBytesVisitor { - type Value = Scalar; - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "scalar value of {} curve", E::CURVE_NAME) - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - Err: Error, - { - Scalar::from_bytes(v).map_err(|_| Err::custom("invalid scalar")) - } - } - - deserializer - .deserialize_bytes(ScalarBytesVisitor(PhantomData)) - .map(ScalarFromBytes) - } -} - -#[derive(Deserialize)] -#[serde(field_identifier, rename_all = "snake_case")] -enum Field { - Curve, - Scalar, -} - -#[cfg(test)] -mod serde_tests { - use serde_test::{assert_tokens, Token::*}; - - use crate::elliptic::curves::*; - - #[test] - fn test_serde_scalar() { - fn generic(scalar: Scalar) { - let bytes = scalar.to_bytes().to_vec(); - let tokens = vec![ - Struct { - name: "Scalar", - len: 2, - }, - Str("curve"), - Str(E::CURVE_NAME), - Str("scalar"), - Bytes(bytes.leak()), - StructEnd, - ]; - assert_tokens(&scalar, &tokens); - } - - // Test **zero scalars** (de)serializing - generic::(Scalar::zero()); - generic::(Scalar::zero()); - generic::(Scalar::zero()); - generic::(Scalar::zero()); - generic::(Scalar::zero()); - generic::(Scalar::zero()); - - // Test **random scalars** (de)serializing - generic::(Scalar::random()); - generic::(Scalar::random()); - generic::(Scalar::random()); - generic::(Scalar::random()); - generic::(Scalar::random()); - generic::(Scalar::random()); - } -} diff --git a/src/elliptic/curves/wrappers/serde_support.rs b/src/elliptic/curves/wrappers/serde_support.rs new file mode 100644 index 00000000..3a452928 --- /dev/null +++ b/src/elliptic/curves/wrappers/serde_support.rs @@ -0,0 +1,326 @@ +use std::fmt; +use std::marker::PhantomData; + +use serde::de::{Error, MapAccess, Visitor}; +use serde::ser::SerializeStruct; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::elliptic::curves::{Curve, Point, Scalar}; + +// --- +// --- Point (de)serialization +// --- + +impl Serialize for Point { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_point().serialize(serializer) + } +} + +impl<'de, E: Curve> Deserialize<'de> for Point { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PointVisitor(PhantomData); + + impl<'de, E: Curve> Visitor<'de> for PointVisitor { + type Value = Point; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "point of {} curve", E::CURVE_NAME) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut curve_name: Option> = None; + let mut point: Option> = None; + + while let Some(key) = map.next_key()? { + match key { + PointField::Curve => { + if curve_name.is_some() { + return Err(A::Error::duplicate_field("curve_name")); + } + curve_name = Some(map.next_value()?) + } + PointField::Point => { + if point.is_some() { + return Err(A::Error::duplicate_field("point")); + } + point = Some(map.next_value()?) + } + } + } + let _curve_name = + curve_name.ok_or_else(|| A::Error::missing_field("curve_name"))?; + let point = point.ok_or_else(|| A::Error::missing_field("point"))?; + Ok(point.0) + } + } + + deserializer.deserialize_struct("Point", &["curve", "point"], PointVisitor(PhantomData)) + } +} + +#[derive(Deserialize)] +#[serde(field_identifier, rename_all = "snake_case")] +enum PointField { + Curve, + Point, +} + +/// Efficient guard for asserting that deserialized `&str`/`String` is `E::CURVE_NAME` +struct CurveNameGuard(PhantomData); + +impl<'de, E: Curve> Deserialize<'de> for CurveNameGuard { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct CurveNameVisitor(PhantomData); + + impl<'de, E: Curve> Visitor<'de> for CurveNameVisitor { + type Value = (); + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "curve name (constrained to be '{}')", E::CURVE_NAME) + } + + fn visit_str(self, v: &str) -> Result + where + Err: Error, + { + if v == E::CURVE_NAME { + Ok(()) + } else { + Err(Err::invalid_value( + serde::de::Unexpected::Str(v), + &E::CURVE_NAME, + )) + } + } + } + + deserializer + .deserialize_str(CurveNameVisitor(PhantomData::)) + .map(|_| CurveNameGuard(PhantomData)) + } +} + +struct PointFromBytes(Point); + +impl<'de, E: Curve> Deserialize<'de> for PointFromBytes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PointBytesVisitor(PhantomData); + + impl<'de, E: Curve> Visitor<'de> for PointBytesVisitor { + type Value = Point; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "point of {} curve", E::CURVE_NAME) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + Err: Error, + { + Point::from_bytes(v).map_err(|e| Err::custom(format!("invalid point: {}", e))) + } + } + + deserializer + .deserialize_bytes(PointBytesVisitor(PhantomData)) + .map(PointFromBytes) + } +} + +// --- +// --- Scalar (de)serialization +// --- + +impl Serialize for Scalar { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut s = serializer.serialize_struct("Scalar", 2)?; + s.serialize_field("curve", E::CURVE_NAME)?; + s.serialize_field( + "scalar", + // Serializes bytes efficiently + serde_bytes::Bytes::new(&self.to_bytes()), + )?; + s.end() + } +} + +impl<'de, E: Curve> Deserialize<'de> for Scalar { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ScalarVisitor(PhantomData); + + impl<'de, E: Curve> Visitor<'de> for ScalarVisitor { + type Value = Scalar; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "scalar of {} curve", E::CURVE_NAME) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut curve_name: Option> = None; + let mut scalar: Option> = None; + + while let Some(key) = map.next_key()? { + match key { + ScalarField::Curve => { + if curve_name.is_some() { + return Err(A::Error::duplicate_field("curve_name")); + } + curve_name = Some(map.next_value()?) + } + ScalarField::Scalar => { + if scalar.is_some() { + return Err(A::Error::duplicate_field("scalar")); + } + scalar = Some(map.next_value()?) + } + } + } + let _curve_name = + curve_name.ok_or_else(|| A::Error::missing_field("curve_name"))?; + let scalar = scalar.ok_or_else(|| A::Error::missing_field("scalar"))?; + Ok(scalar.0) + } + } + + deserializer.deserialize_struct("Scalar", &["curve", "scalar"], ScalarVisitor(PhantomData)) + } +} + +struct ScalarFromBytes(Scalar); + +impl<'de, E: Curve> Deserialize<'de> for ScalarFromBytes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ScalarBytesVisitor(PhantomData); + + impl<'de, E: Curve> Visitor<'de> for ScalarBytesVisitor { + type Value = Scalar; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "scalar value of {} curve", E::CURVE_NAME) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + Err: Error, + { + Scalar::from_bytes(v).map_err(|_| Err::custom("invalid scalar")) + } + } + + deserializer + .deserialize_bytes(ScalarBytesVisitor(PhantomData)) + .map(ScalarFromBytes) + } +} + +#[derive(Deserialize)] +#[serde(field_identifier, rename_all = "snake_case")] +enum ScalarField { + Curve, + Scalar, +} + +#[cfg(test)] +mod serde_tests { + use serde_test::{assert_tokens, Token::*}; + + use crate::elliptic::curves::*; + + #[test] + fn test_serde_point() { + fn generic(point: Point) { + let bytes = point.to_bytes(true).to_vec(); + let tokens = vec![ + Struct { + name: "Point", + len: 2, + }, + Str("curve"), + Str(E::CURVE_NAME), + Str("point"), + Bytes(bytes.leak()), + StructEnd, + ]; + assert_tokens(&point, &tokens); + } + + // Test **zero points** (de)serializing + generic::(Point::zero()); + generic::(Point::zero()); + generic::(Point::zero()); + generic::(Point::zero()); + generic::(Point::zero()); + generic::(Point::zero()); + + // Test **random point** (de)serializing + generic::(Point::generator() * Scalar::random()); + generic::(Point::generator() * Scalar::random()); + generic::(Point::generator() * Scalar::random()); + generic::(Point::generator() * Scalar::random()); + generic::(Point::generator() * Scalar::random()); + generic::(Point::generator() * Scalar::random()); + } + + #[test] + fn test_serde_scalar() { + fn generic(scalar: Scalar) { + let bytes = scalar.to_bytes().to_vec(); + let tokens = vec![ + Struct { + name: "Scalar", + len: 2, + }, + Str("curve"), + Str(E::CURVE_NAME), + Str("scalar"), + Bytes(bytes.leak()), + StructEnd, + ]; + assert_tokens(&scalar, &tokens); + } + + // Test **zero scalars** (de)serializing + generic::(Scalar::zero()); + generic::(Scalar::zero()); + generic::(Scalar::zero()); + generic::(Scalar::zero()); + generic::(Scalar::zero()); + generic::(Scalar::zero()); + + // Test **random scalars** (de)serializing + generic::(Scalar::random()); + generic::(Scalar::random()); + generic::(Scalar::random()); + generic::(Scalar::random()); + generic::(Scalar::random()); + generic::(Scalar::random()); + } +} From 5d8b4bd2eac1af960696fcedbd495266a2755d6d Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 26 Jul 2021 21:36:14 +0300 Subject: [PATCH 90/93] Improve serde tests --- src/elliptic/curves/wrappers/serde_support.rs | 95 +++++++++++-------- 1 file changed, 53 insertions(+), 42 deletions(-) diff --git a/src/elliptic/curves/wrappers/serde_support.rs b/src/elliptic/curves/wrappers/serde_support.rs index 3a452928..db508f2a 100644 --- a/src/elliptic/curves/wrappers/serde_support.rs +++ b/src/elliptic/curves/wrappers/serde_support.rs @@ -99,10 +99,11 @@ impl<'de, E: Curve> Deserialize<'de> for CurveNameGuard { if v == E::CURVE_NAME { Ok(()) } else { - Err(Err::invalid_value( - serde::de::Unexpected::Str(v), - &E::CURVE_NAME, - )) + Err(Err::custom(format!( + "belongs to {} curve, expected {} curve", + v, + E::CURVE_NAME + ))) } } } @@ -250,13 +251,16 @@ enum ScalarField { #[cfg(test)] mod serde_tests { - use serde_test::{assert_tokens, Token::*}; + use serde_test::{assert_de_tokens_error, assert_tokens, Token::*}; use crate::elliptic::curves::*; + use crate::test_for_all_curves; - #[test] - fn test_serde_point() { - fn generic(point: Point) { + test_for_all_curves!(test_serde_point); + fn test_serde_point() { + let random_point = Point::::generator() * Scalar::random(); + for point in [Point::zero(), random_point] { + println!("Point: {:?}", point); let bytes = point.to_bytes(true).to_vec(); let tokens = vec![ Struct { @@ -271,27 +275,12 @@ mod serde_tests { ]; assert_tokens(&point, &tokens); } - - // Test **zero points** (de)serializing - generic::(Point::zero()); - generic::(Point::zero()); - generic::(Point::zero()); - generic::(Point::zero()); - generic::(Point::zero()); - generic::(Point::zero()); - - // Test **random point** (de)serializing - generic::(Point::generator() * Scalar::random()); - generic::(Point::generator() * Scalar::random()); - generic::(Point::generator() * Scalar::random()); - generic::(Point::generator() * Scalar::random()); - generic::(Point::generator() * Scalar::random()); - generic::(Point::generator() * Scalar::random()); } - #[test] - fn test_serde_scalar() { - fn generic(scalar: Scalar) { + test_for_all_curves!(test_serde_scalar); + fn test_serde_scalar() { + for scalar in [Scalar::::zero(), Scalar::random()] { + println!("Scalar: {:?}", scalar); let bytes = scalar.to_bytes().to_vec(); let tokens = vec![ Struct { @@ -306,21 +295,43 @@ mod serde_tests { ]; assert_tokens(&scalar, &tokens); } + } + + test_for_all_curves!(doesnt_deserialize_point_from_different_curve); + fn doesnt_deserialize_point_from_different_curve() { + let tokens = vec![ + Struct { + name: "Point", + len: 2, + }, + Str("curve"), + Str("%not_existing%"), + ]; + assert_de_tokens_error::>( + &tokens, + &format!( + "belongs to %not_existing% curve, expected {} curve", + E::CURVE_NAME + ), + ) + } - // Test **zero scalars** (de)serializing - generic::(Scalar::zero()); - generic::(Scalar::zero()); - generic::(Scalar::zero()); - generic::(Scalar::zero()); - generic::(Scalar::zero()); - generic::(Scalar::zero()); - - // Test **random scalars** (de)serializing - generic::(Scalar::random()); - generic::(Scalar::random()); - generic::(Scalar::random()); - generic::(Scalar::random()); - generic::(Scalar::random()); - generic::(Scalar::random()); + test_for_all_curves!(doesnt_deserialize_scalar_from_different_curve); + fn doesnt_deserialize_scalar_from_different_curve() { + let tokens = vec![ + Struct { + name: "Scalar", + len: 2, + }, + Str("curve"), + Str("%not_existing%"), + ]; + assert_de_tokens_error::>( + &tokens, + &format!( + "belongs to %not_existing% curve, expected {} curve", + E::CURVE_NAME + ), + ) } } From 093f8106c0a2cbc9f2ec4306edc874de2874a01f Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 26 Jul 2021 22:29:53 +0300 Subject: [PATCH 91/93] Remove PointRef wrapper --- .../hashing/blake2b512.rs | 20 +- src/cryptographic_primitives/hashing/ext.rs | 24 +-- .../hashing/hash_sha256.rs | 10 +- .../hashing/hash_sha512.rs | 10 +- .../hashing/merkle_tree.rs | 4 +- .../proofs/sigma_ec_ddh.rs | 4 +- .../proofs/sigma_valid_pedersen.rs | 17 +- .../proofs/sigma_valid_pedersen_blind.rs | 4 +- src/elliptic/curves/bls12_381/pairing.rs | 6 +- src/elliptic/curves/mod.rs | 4 +- src/elliptic/curves/wrappers/arithmetic.rs | 85 ++------ src/elliptic/curves/wrappers/encoded_point.rs | 10 +- src/elliptic/curves/wrappers/generator.rs | 21 +- src/elliptic/curves/wrappers/mod.rs | 3 +- src/elliptic/curves/wrappers/point.rs | 96 +++++---- src/elliptic/curves/wrappers/point_ref.rs | 183 ------------------ src/elliptic/curves/wrappers/scalar.rs | 4 +- src/elliptic/curves/wrappers/serde_support.rs | 14 +- 18 files changed, 157 insertions(+), 362 deletions(-) delete mode 100644 src/elliptic/curves/wrappers/point_ref.rs diff --git a/src/cryptographic_primitives/hashing/blake2b512.rs b/src/cryptographic_primitives/hashing/blake2b512.rs index 2f7d8252..9b0feae1 100644 --- a/src/cryptographic_primitives/hashing/blake2b512.rs +++ b/src/cryptographic_primitives/hashing/blake2b512.rs @@ -99,34 +99,34 @@ mod tests { crate::test_for_all_curves!(create_hash_from_ge_test_legacy); fn create_hash_from_ge_test_legacy() { #![allow(deprecated)] - let base_point2 = Point::base_point2().to_point(); - let generator = Point::generator().to_point(); + let base_point2 = Point::::base_point2(); + let generator = Point::::generator(); let result1 = - Blake::create_hash_from_ge::(&[&base_point2, &generator], b"Zcash_RedJubjubH"); + Blake::create_hash_from_ge::(&[base_point2, &generator], b"Zcash_RedJubjubH"); assert!(result1.to_bigint().bit_length() > 240); - let result2 = Blake::create_hash_from_ge(&[&generator, &base_point2], b"Zcash_RedJubjubH"); + let result2 = Blake::create_hash_from_ge(&[&generator, base_point2], b"Zcash_RedJubjubH"); assert_ne!(result1, result2); - let result3 = Blake::create_hash_from_ge(&[&generator, &base_point2], b"Zcash_RedJubjubH"); + let result3 = Blake::create_hash_from_ge(&[&generator, base_point2], b"Zcash_RedJubjubH"); assert_eq!(result2, result3); } crate::test_for_all_curves!(create_hash_from_ge_test); fn create_hash_from_ge_test() { - let base_point2 = Point::::base_point2().to_point(); - let generator = Point::::generator().to_point(); + let base_point2 = Point::::base_point2(); + let generator = Point::::generator(); let result1 = Blake::with_personal(b"Zcash_RedJubjubH") - .chain_point(&base_point2) + .chain_point(base_point2) .chain_point(&generator) .result_scalar::(); assert!(result1.to_bigint().bit_length() > 240); let result2 = Blake::with_personal(b"Zcash_RedJubjubH") .chain_point(&generator) - .chain_point(&base_point2) + .chain_point(base_point2) .result_scalar::(); assert_ne!(result1, result2); let result3 = Blake::with_personal(b"Zcash_RedJubjubH") .chain_point(&generator) - .chain_point(&base_point2) + .chain_point(base_point2) .result_scalar::(); assert_eq!(result2, result3); } diff --git a/src/cryptographic_primitives/hashing/ext.rs b/src/cryptographic_primitives/hashing/ext.rs index baca9131..27c8efca 100644 --- a/src/cryptographic_primitives/hashing/ext.rs +++ b/src/cryptographic_primitives/hashing/ext.rs @@ -19,8 +19,8 @@ use crate::elliptic::curves::{Curve, Point, Scalar}; /// use curv::elliptic::curves::{Secp256k1, Point}; /// /// let hash = Sha256::new() -/// .chain_point(&Point::::generator().to_point()) -/// .chain_point(&Point::::base_point2().to_point()) +/// .chain_point(&Point::::generator()) +/// .chain_point(Point::::base_point2()) /// .chain_bigint(&BigInt::from(10)) /// .result_bigint(); /// @@ -255,20 +255,20 @@ mod test { crate::test_for_all_curves!(create_sha512_from_ge_test); fn create_sha256_from_ge_test() { - let generator = Point::::generator().to_point(); - let base_point2 = Point::::base_point2().to_point(); + let generator = Point::::generator(); + let base_point2 = Point::::base_point2(); let result1 = Sha256::new() .chain_point(&generator) - .chain_point(&base_point2) + .chain_point(base_point2) .result_scalar::(); assert!(result1.to_bigint().bit_length() > 240); let result2 = Sha256::new() - .chain_point(&base_point2) + .chain_point(base_point2) .chain_point(&generator) .result_scalar::(); assert_ne!(result1, result2); let result3 = Sha256::new() - .chain_point(&base_point2) + .chain_point(base_point2) .chain_point(&generator) .result_scalar::(); assert_eq!(result2, result3); @@ -276,20 +276,20 @@ mod test { crate::test_for_all_curves!(create_sha256_from_ge_test); fn create_sha512_from_ge_test() { - let generator = Point::::generator().to_point(); - let base_point2 = Point::::base_point2().to_point(); + let generator = Point::::generator(); + let base_point2 = Point::::base_point2(); let result1 = Sha512::new() .chain_point(&generator) - .chain_point(&base_point2) + .chain_point(base_point2) .result_scalar::(); assert!(result1.to_bigint().bit_length() > 240); let result2 = Sha512::new() - .chain_point(&base_point2) + .chain_point(base_point2) .chain_point(&generator) .result_scalar::(); assert_ne!(result1, result2); let result3 = Sha512::new() - .chain_point(&base_point2) + .chain_point(base_point2) .chain_point(&generator) .result_scalar::(); assert_eq!(result2, result3); diff --git a/src/cryptographic_primitives/hashing/hash_sha256.rs b/src/cryptographic_primitives/hashing/hash_sha256.rs index aa5848ce..a592b713 100644 --- a/src/cryptographic_primitives/hashing/hash_sha256.rs +++ b/src/cryptographic_primitives/hashing/hash_sha256.rs @@ -115,13 +115,13 @@ mod tests { crate::test_for_all_curves!(create_sha256_from_ge_test); fn create_sha256_from_ge_test() { - let generator = Point::generator().to_point(); - let base_point2 = Point::base_point2().to_point(); - let result1 = HSha256::create_hash_from_ge::(&[&base_point2, &generator]); + let generator = Point::::generator(); + let base_point2 = Point::::base_point2(); + let result1 = HSha256::create_hash_from_ge::(&[base_point2, &generator]); assert!(result1.to_bigint().bit_length() > 240); - let result2 = HSha256::create_hash_from_ge(&[&generator, &base_point2]); + let result2 = HSha256::create_hash_from_ge(&[&generator, base_point2]); assert_ne!(result1, result2); - let result3 = HSha256::create_hash_from_ge(&[&generator, &base_point2]); + let result3 = HSha256::create_hash_from_ge(&[&generator, base_point2]); assert_eq!(result2, result3); } } diff --git a/src/cryptographic_primitives/hashing/hash_sha512.rs b/src/cryptographic_primitives/hashing/hash_sha512.rs index 2787627c..cdceda0a 100644 --- a/src/cryptographic_primitives/hashing/hash_sha512.rs +++ b/src/cryptographic_primitives/hashing/hash_sha512.rs @@ -103,13 +103,13 @@ mod tests { crate::test_for_all_curves!(create_sha512_from_ge_test); fn create_sha512_from_ge_test() { - let generator = Point::generator().to_point(); - let base_point2 = Point::base_point2().to_point(); - let result1 = HSha512::create_hash_from_ge::(&[&base_point2, &generator]); + let generator = Point::::generator(); + let base_point2 = Point::::base_point2(); + let result1 = HSha512::create_hash_from_ge::(&[base_point2, &generator]); assert!(result1.to_bigint().bit_length() > 240); - let result2 = HSha512::create_hash_from_ge(&[&generator, &base_point2]); + let result2 = HSha512::create_hash_from_ge(&[&generator, base_point2]); assert_ne!(result1, result2); - let result3 = HSha512::create_hash_from_ge(&[&generator, &base_point2]); + let result3 = HSha512::create_hash_from_ge(&[&generator, base_point2]); assert_eq!(result2, result3); } } diff --git a/src/cryptographic_primitives/hashing/merkle_tree.rs b/src/cryptographic_primitives/hashing/merkle_tree.rs index f1c17559..b5950788 100644 --- a/src/cryptographic_primitives/hashing/merkle_tree.rs +++ b/src/cryptographic_primitives/hashing/merkle_tree.rs @@ -75,7 +75,7 @@ mod tests { test_for_all_curves!(test_mt_functionality_four_leaves); fn test_mt_functionality_four_leaves() { - let ge1: Point = Point::generator().to_point().into(); + let ge1: Point = Point::generator().to_point(); let ge2: Point = ge1.clone(); let ge3: Point = &ge1 + &ge2; let ge4: Point = &ge1 + &ge3; @@ -90,7 +90,7 @@ mod tests { test_for_all_curves!(test_mt_functionality_three_leaves); fn test_mt_functionality_three_leaves() { - let ge1: Point = Point::generator().to_point().into(); + let ge1: Point = Point::generator().to_point(); let ge2: Point = ge1.clone(); let ge3: Point = &ge1 + &ge2; diff --git a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs index 77b9838e..a64fd071 100644 --- a/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs +++ b/src/cryptographic_primitives/proofs/sigma_ec_ddh.rs @@ -99,7 +99,7 @@ mod tests { let h2 = g2 * &x; let delta = ECDDHStatement { g1: g1.to_point(), - g2: g2.to_point(), + g2: g2.clone(), h1, h2, }; @@ -118,7 +118,7 @@ mod tests { let h2 = g2 * &x2; let delta = ECDDHStatement { g1: g1.to_point(), - g2: g2.to_point(), + g2: g2.clone(), h1, h2, }; diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs index 0dfa8bfb..2343cdc8 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen.rs @@ -50,7 +50,7 @@ impl PedersenProof { ); let e = Sha256::new() - .chain_points([&g.to_point(), &h.to_point(), &com, &a1, &a2]) + .chain_points([&g.to_point(), h, &com, &a1, &a2]) .result_scalar(); let em = &e * m; @@ -71,22 +71,9 @@ impl PedersenProof { pub fn verify(proof: &PedersenProof) -> Result<(), ProofError> { let g = Point::::generator(); let h = Point::::base_point2(); - // let e = Sha256::new() - // .chain_point(&g.to_point()) - // .chain_point(&h.to_point()) - // .chain_pointz(&proof.com) - // .chain_point(&proof.a1) - // .chain_point(&proof.a2) - // .result_scalar(); let e = Sha256::new() - .chain_points([ - &g.to_point(), - &h.to_point(), - &proof.com, - &proof.a1, - &proof.a2, - ]) + .chain_points([&g.to_point(), &h, &proof.com, &proof.a1, &proof.a2]) .result_scalar(); let z1g = g * &proof.z1; diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs index cc4d3f82..82af4240 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs @@ -46,7 +46,7 @@ impl PedersenBlindingProof { ); let g = Point::::generator(); let e = Sha256::new() - .chain_points([&g.to_point(), &h.to_point(), &com, &a]) + .chain_points([&g.to_point(), h, &com, &a]) .chain_scalar(&m) .result_scalar(); @@ -65,7 +65,7 @@ impl PedersenBlindingProof { let g = Point::::generator(); let h = Point::::base_point2(); let e = Sha256::new() - .chain_points([&g.to_point(), &h.to_point(), &proof.com, &proof.a]) + .chain_points([&g.to_point(), h, &proof.com, &proof.a]) .chain_scalar(&proof.m) .result_scalar(); diff --git a/src/elliptic/curves/bls12_381/pairing.rs b/src/elliptic/curves/bls12_381/pairing.rs index bec1912a..4c3c4399 100644 --- a/src/elliptic/curves/bls12_381/pairing.rs +++ b/src/elliptic/curves/bls12_381/pairing.rs @@ -85,10 +85,10 @@ mod tests { fn pairing() { let p = Point::::generator().to_point(); let q = Point::::generator().to_point(); - let r = Point::::base_point2().to_point(); - let q_plus_r = &q + &r; + let r = Point::::base_point2(); + let q_plus_r = &q + r; let e_p_q = Pair::compute_pairing(&p, &q); - let e_p_r = Pair::compute_pairing(&p, &r); + let e_p_r = Pair::compute_pairing(&p, r); let e_p_q_r = Pair::compute_pairing(&p, &q_plus_r); let e_p_q_add_e_p_r = e_p_q.add_pair(&e_p_r); assert_eq!(e_p_q_add_e_p_r, e_p_q_r); diff --git a/src/elliptic/curves/mod.rs b/src/elliptic/curves/mod.rs index ee8bd044..3103c2eb 100644 --- a/src/elliptic/curves/mod.rs +++ b/src/elliptic/curves/mod.rs @@ -67,7 +67,7 @@ //! ``` //! //! `Point` (for generic `E: Curve`) implements many traits you might need (e.g. Serialize, PartialEq, -//! Debug, etc.) without specifying additional bounds. The same applies to other structures (PointRef, Scalar, ...). +//! Debug, etc.) without specifying additional bounds. The same applies to `Scalar`. //! //! ## Implementing your own curve //! @@ -97,7 +97,7 @@ pub use self::{ }; pub use self::{ traits::{Curve, ECPoint, ECScalar, PointCoords}, - wrappers::{EncodedPoint, EncodedScalar, Generator, Point, PointRef, Scalar}, + wrappers::{EncodedPoint, EncodedScalar, Generator, Point, Scalar}, }; pub mod error { diff --git a/src/elliptic/curves/wrappers/arithmetic.rs b/src/elliptic/curves/wrappers/arithmetic.rs index 4528afb9..88a26fdb 100644 --- a/src/elliptic/curves/wrappers/arithmetic.rs +++ b/src/elliptic/curves/wrappers/arithmetic.rs @@ -128,32 +128,9 @@ macro_rules! matrix { }; } -#[cfg(not(release))] fn addition_of_two_points(result: E::Point) -> Point { - // In non-release environment we check that every addition results into correct point (either - // zero or of the expected order) - Point::from_raw(result) - .expect("addition of two points must be either a zero or of the same order") + unsafe { Point::from_raw_unchecked(result) } } -#[cfg(release)] -fn addition_of_two_points(result: E::Point) -> Point { - // In release we skip checks - Point::from_raw_unchecked(result) -} - -// -// (o_<> Point, Point), (o_ Point, &Point), -// (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), -// -// (_o<> &Point, Point), (r_ &Point, &Point), -// (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), -// -// (_o<'p> PointRef<'p, E>, Point), (r_<'p> PointRef<'p, E>, &Point), -// (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), -// -// (_o<> Generator, Point), (r_ Generator, &Point), -// (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), -// matrix! { trait = Add, @@ -164,30 +141,18 @@ matrix! { point_assign_fn = add_point_assign, pairs = { (o_<> Point, Point), (o_<> Point, &Point), - (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), + (o_<> Point, Generator), (_o<> &Point, Point), (r_<> &Point, &Point), - (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), - - (_o<'p> PointRef<'p, E>, Point), (r_<'p> PointRef<'p, E>, &Point), - (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), + (r_<> &Point, Generator), (_o<> Generator, Point), (r_<> Generator, &Point), - (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), + (r_<> Generator, Generator), } } -#[cfg(not(release))] fn subtraction_of_two_point(result: E::Point) -> Point { - // In non-release environment we check that every subtraction results into correct point (either - // zero or of the expected order) - Point::from_raw(result) - .expect("subtraction of two points must be either a zero or of the same order") -} -#[cfg(release)] -fn subtraction_of_two_point(result: E::Point) -> Point { - // In release we skip checks - Point::from_raw_unchecked(result) + unsafe { Point::from_raw_unchecked(result) } } matrix! { @@ -199,27 +164,18 @@ matrix! { point_assign_fn = sub_point_assign, pairs = { (o_<> Point, Point), (o_<> Point, &Point), - (o_<'p> Point, PointRef<'p, E>), (o_<> Point, Generator), + (o_<> Point, Generator), (_o<> &Point, Point), (r_<> &Point, &Point), - (r_<'p> &Point, PointRef<'p, E>), (r_<> &Point, Generator), - - (_o<'p> PointRef<'p, E>, Point), (r_<'p> PointRef<'p, E>, &Point), - (r_<'a, 'b> PointRef<'a, E>, PointRef<'b, E>), (r_<'p> PointRef<'p, E>, Generator), + (r_<> &Point, Generator), (_o<> Generator, Point), (r_<> Generator, &Point), - (r_<'p> Generator, PointRef<'p, E>), (r_<> Generator, Generator), + (r_<> Generator, Generator), } } -#[cfg(not(release))] -fn multiplication_of_point_at_scalar(result: E::Point) -> Point { - Point::from_raw(result) - .expect("multiplication of point at scalar must always produce either a point of the same order or a zero point") -} -#[cfg(release)] fn multiplication_of_point_at_scalar(result: E::Point) -> Point { - Point::from_raw_unchecked(result) + unsafe { Point::from_raw_unchecked(result) } } matrix! { @@ -232,11 +188,9 @@ matrix! { pairs = { (o_<> Point, Scalar), (o_<> Point, &Scalar), (r_<> &Point, Scalar), (r_<> &Point, &Scalar), - (r_<'p> PointRef<'p, E>, Scalar), (r_<'p> PointRef<'p, E>, &Scalar), (_o<> Scalar, Point), (_o<> &Scalar, Point), (_r<> Scalar, &Point), (_r<> &Scalar, &Point), - (_r<'p> Scalar, PointRef<'p, E>), (_r<'p> &Scalar, PointRef<'p, E>), } } @@ -343,15 +297,6 @@ impl ops::Neg for &Point { } } -impl<'p, E: Curve> ops::Neg for PointRef<'p, E> { - type Output = Point; - - fn neg(self) -> Self::Output { - Point::from_raw(self.as_raw().neg_point()) - .expect("neg must not produce point of different order") - } -} - impl ops::Neg for Generator { type Output = Point; @@ -414,8 +359,8 @@ mod test { fn _curve() { assert_operator_defined_for! { assert_fn = assert_point_addition_defined, - lhs = {Point, &Point, PointRef, Generator}, - rhs = {Point, &Point, PointRef, Generator}, + lhs = {Point, &Point, Generator}, + rhs = {Point, &Point, Generator}, } } } @@ -436,8 +381,8 @@ mod test { fn _curve() { assert_operator_defined_for! { assert_fn = assert_point_subtraction_defined, - lhs = {Point, &Point, PointRef, Generator}, - rhs = {Point, &Point, PointRef, Generator}, + lhs = {Point, &Point, Generator}, + rhs = {Point, &Point, Generator}, } } } @@ -458,7 +403,7 @@ mod test { fn _curve() { assert_operator_defined_for! { assert_fn = assert_point_multiplication_defined, - lhs = {Point, &Point, PointRef, Generator}, + lhs = {Point, &Point, Generator}, rhs = {Scalar, &Scalar}, } @@ -467,7 +412,7 @@ mod test { assert_operator_defined_for! { assert_fn = assert_point_multiplication_defined, lhs = {Scalar, &Scalar}, - rhs = {Point, &Point, PointRef, Generator}, + rhs = {Point, &Point, Generator}, } } } diff --git a/src/elliptic/curves/wrappers/encoded_point.rs b/src/elliptic/curves/wrappers/encoded_point.rs index 09d72752..fc43b7b7 100644 --- a/src/elliptic/curves/wrappers/encoded_point.rs +++ b/src/elliptic/curves/wrappers/encoded_point.rs @@ -3,7 +3,9 @@ use std::ops::Deref; use crate::elliptic::curves::{Curve, ECPoint}; /// Point encoded in (un)compressed form -pub enum EncodedPoint { +pub struct EncodedPoint(pub(super) EncodedPointChoice); + +pub(super) enum EncodedPointChoice { Compressed(::CompressedPoint), Uncompressed(::UncompressedPoint), } @@ -11,9 +13,9 @@ pub enum EncodedPoint { impl Deref for EncodedPoint { type Target = [u8]; fn deref(&self) -> &[u8] { - match self { - Self::Compressed(bytes) => bytes.as_ref(), - Self::Uncompressed(bytes) => bytes.as_ref(), + match &self.0 { + EncodedPointChoice::Compressed(bytes) => bytes.as_ref(), + EncodedPointChoice::Uncompressed(bytes) => bytes.as_ref(), } } } diff --git a/src/elliptic/curves/wrappers/generator.rs b/src/elliptic/curves/wrappers/generator.rs index a37e4f57..356611dc 100644 --- a/src/elliptic/curves/wrappers/generator.rs +++ b/src/elliptic/curves/wrappers/generator.rs @@ -1,15 +1,16 @@ use std::marker::PhantomData; +use std::ops::Deref; use crate::elliptic::curves::traits::*; -use super::{Point, PointRef}; +use super::Point; /// Elliptic curve generator /// /// Holds internally a static reference on curve generator. Can be used in arithmetic interchangeably -/// as [`PointRef`](PointRef). +/// as [&Point\](Point). /// -/// You can convert the generator into `Point` and `PointRef` using +/// You can convert the generator into `Point` and `&'static Point` using /// [`to_point`](Self::to_point) and [`as_point`](Self::as_point) /// methods respectively. /// @@ -55,9 +56,10 @@ impl Generator { Point::from(self) } - /// Converts generator into `PointRef` - pub fn as_point(self) -> PointRef<'static, E> { - PointRef::from(self) + /// Converts generator into `&'static Point` + pub fn as_point(self) -> &'static Point { + // Safety: generator point expected to have correct order + unsafe { Point::from_raw_ref_unchecked(self.as_raw()) } } /// Returns a reference to low-level point implementation @@ -73,3 +75,10 @@ impl Clone for Generator { } impl Copy for Generator {} + +impl Deref for Generator { + type Target = Point; + fn deref(&self) -> &Point { + self.as_point() + } +} diff --git a/src/elliptic/curves/wrappers/mod.rs b/src/elliptic/curves/wrappers/mod.rs index 4898f08f..ef815f17 100644 --- a/src/elliptic/curves/wrappers/mod.rs +++ b/src/elliptic/curves/wrappers/mod.rs @@ -5,11 +5,10 @@ pub mod error; mod format; mod generator; mod point; -mod point_ref; mod scalar; mod serde_support; pub use self::{ encoded_point::EncodedPoint, encoded_scalar::EncodedScalar, generator::Generator, point::Point, - point_ref::PointRef, scalar::Scalar, + scalar::Scalar, }; diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index 17937ed2..36e3ce07 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -5,8 +5,9 @@ use crate::BigInt; use super::{ error::{MismatchedPointOrder, PointFromBytesError, PointFromCoordsError, ZeroPointError}, - EncodedPoint, Generator, PointRef, + EncodedPoint, Generator, }; +use crate::elliptic::curves::wrappers::encoded_point::EncodedPointChoice; /// Elliptic point of a [group order](super::Scalar::group_order), or a zero point /// @@ -50,6 +51,7 @@ use super::{ /// a + b * c /// } /// ``` +#[repr(transparent)] pub struct Point { raw_point: E::Point, } @@ -75,11 +77,12 @@ impl Point { /// /// We provide an alternative generator value and prove that it was picked randomly. /// - /// Returns a structure holding a static reference on actual value (in most cases referenced - /// value is fine). Use [`.to_point()`](PointRef::to_point) if you need to take it by value. - pub fn base_point2() -> PointRef<'static, E> { + /// Returns a static reference to actual point — in most cases referenced value is fine. Use + /// `.clone()` to take it by value. + pub fn base_point2() -> &'static Self { let p = E::Point::base_point2(); - PointRef::from_raw(p).expect("base_point2 must have correct order") + // Safety: we proof that base_point2 has correct order + unsafe { Self::from_raw_ref_unchecked(p) } } /// Constructs zero point @@ -136,11 +139,6 @@ impl Point { Self::from_raw(raw_point).map_err(PointFromCoordsError::InvalidPoint) } - /// Creates [PointRef] that holds a reference on `self` - pub fn as_point(&self) -> PointRef { - PointRef::from(self) - } - /// Tries to parse a point in (un)compressed form /// /// Whether it's in compressed or uncompressed form will be deduced from its length @@ -153,9 +151,13 @@ impl Point { /// Serializes a point in (un)compressed form pub fn to_bytes(&self, compressed: bool) -> EncodedPoint { if compressed { - EncodedPoint::Compressed(self.as_raw().serialize_compressed()) + EncodedPoint(EncodedPointChoice::Compressed( + self.as_raw().serialize_compressed(), + )) } else { - EncodedPoint::Uncompressed(self.as_raw().serialize_uncompressed()) + EncodedPoint(EncodedPointChoice::Uncompressed( + self.as_raw().serialize_uncompressed(), + )) } } @@ -178,13 +180,36 @@ impl Point { } } + /// Constructs a `&Point` from reference to low-level [ECPoint] implementation + /// + /// Returns error if point is not valid. Valid point is either a zero point, or a point of + /// [group order]. + /// + /// Typically, you don't need to use this constructor. See [generator](Point::generator), + /// [base_point2](Point::base_point2) constructors. + /// + /// [ECPoint]: crate::elliptic::curves::ECPoint + /// [group order]: crate::elliptic::curves::ECScalar::group_order + pub fn from_raw_ref(raw_point: &E::Point) -> Result<&Self, MismatchedPointOrder> { + if raw_point.is_zero() || raw_point.check_point_order_equals_group_order() { + // Safety: Self is repr(transparent) wrapper over E::Point => cast is sound + let reference = unsafe { &*(raw_point as *const E::Point as *const Self) }; + Ok(reference) + } else { + Err(MismatchedPointOrder::new()) + } + } + /// Constructs a `Point` from low-level [ECPoint] implementor /// + /// Unsafe equivalent of [from_raw](Self::from_raw). It debug asserts that given `raw_point` is + /// valid (the assertion is optimized out in release builds by default). + /// /// # Safety /// - /// This function will not perform any checks against the point. You must guarantee that either - /// point order is equal to curve [group order] or it's a zero point. To perform this check, you - /// may use [ECPoint::check_point_order_equals_group_order][check_point_order_equals_group_order] + /// You must guarantee that either point order is equal to curve [group order] or it's a zero point. + /// To perform this check, you may use + /// [ECPoint::check_point_order_equals_group_order][check_point_order_equals_group_order] /// and [ECPoint::is_zero][is_zero] methods. /// /// [ECPoint]: crate::elliptic::curves::ECPoint @@ -192,9 +217,31 @@ impl Point { /// [check_point_order_equals_group_order]: crate::elliptic::curves::ECPoint::check_point_order_equals_group_order /// [is_zero]: crate::elliptic::curves::ECPoint::is_zero pub unsafe fn from_raw_unchecked(raw_point: E::Point) -> Self { + debug_assert!(raw_point.is_zero() || raw_point.check_point_order_equals_group_order()); Self { raw_point } } + /// Constructs a `Point` from reference to low-level [ECPoint] implementor + /// + /// Unsafe equivalent of [from_raw](Self::from_raw). It debug asserts that given `raw_point` is + /// valid (the assertion is optimized out in release builds by default). + /// + /// # Safety + /// + /// You must guarantee that either point order is equal to curve [group order] or it's a zero point. + /// To perform this check, you may use + /// [ECPoint::check_point_order_equals_group_order][check_point_order_equals_group_order] + /// and [ECPoint::is_zero][is_zero] methods. + /// + /// [ECPoint]: crate::elliptic::curves::ECPoint + /// [group order]: crate::elliptic::curves::ECScalar::group_order + /// [check_point_order_equals_group_order]: crate::elliptic::curves::ECPoint::check_point_order_equals_group_order + /// [is_zero]: crate::elliptic::curves::ECPoint::is_zero + pub unsafe fn from_raw_ref_unchecked(raw_point: &E::Point) -> &Self { + // Safety: Self is repr(transparent) wrapper over E::Point => cast is sound + &*(raw_point as *const E::Point as *const Self) + } + /// Returns a reference to low-level point implementation /// /// Typically, you don't need to work with `ECPoint` trait directly. `Point` wrapper @@ -222,12 +269,6 @@ impl PartialEq for Point { } } -impl<'p, E: Curve> PartialEq> for Point { - fn eq(&self, other: &PointRef<'p, E>) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - impl PartialEq> for Point { fn eq(&self, other: &Generator) -> bool { self.as_raw().eq(other.as_raw()) @@ -254,13 +295,6 @@ impl From> for Point { } } -impl<'p, E: Curve> From> for Point { - fn from(p: PointRef) -> Self { - // Safety: `PointRef` holds the same guarantees as `Point` - unsafe { Point::from_raw_unchecked(p.as_raw().clone()) } - } -} - impl iter::Sum for Point { fn sum>(iter: I) -> Self { iter.fold(Point::zero(), |acc, p| acc + p) @@ -272,9 +306,3 @@ impl<'p, E: Curve> iter::Sum<&'p Point> for Point { iter.fold(Point::zero(), |acc, p| acc + p) } } - -impl<'p, E: Curve> iter::Sum> for Point { - fn sum>>(iter: I) -> Self { - iter.fold(Point::zero(), |acc, p| acc + p) - } -} diff --git a/src/elliptic/curves/wrappers/point_ref.rs b/src/elliptic/curves/wrappers/point_ref.rs deleted file mode 100644 index 61fd9399..00000000 --- a/src/elliptic/curves/wrappers/point_ref.rs +++ /dev/null @@ -1,183 +0,0 @@ -use std::fmt; - -use serde::ser::{Serialize, SerializeStruct, Serializer}; - -use crate::elliptic::curves::traits::*; -use crate::BigInt; - -use super::{error::MismatchedPointOrder, EncodedPoint, Generator, Point}; - -/// Holds a reference to elliptic point of [group order](super::Scalar::group_order) or to zero point -/// -/// Holds internally a reference to [`Point`](Point), refer to its documentation to learn -/// more about Point/PointRef guarantees, security notes, and arithmetics. -pub struct PointRef<'p, E: Curve> { - raw_point: &'p E::Point, -} - -impl PointRef<'static, E> { - /// Curve second generator - /// - /// We provide an alternative generator value and prove that it was picked randomly. - pub fn base_point2() -> Self { - Self::from_raw(E::Point::base_point2()).expect("base_point2 must be of group_order") - } -} - -impl<'p, E> PointRef<'p, E> -where - E: Curve, -{ - /// Returns point coordinates (`x` and `y`) - /// - /// Point might not have coordinates (specifically, "point at infinity" doesn't), in this case - /// `None` is returned. Also, some curve libraries do not expose point coordinates (eg. see - /// [Ristretto] curve implementation notes). - /// - /// [Ristretto]: crate::elliptic::curves::Ristretto - pub fn coords(&self) -> Option { - self.as_raw().coords() - } - - /// Returns `x` coordinate of point - /// - /// See [coords](Self::coords) method that retrieves both x and y at once. - pub fn x_coord(&self) -> Option { - self.as_raw().x_coord() - } - - /// Returns `y` coordinate of point - /// - /// See [coords](Self::coords) method that retrieves both x and y at once. - pub fn y_coord(&self) -> Option { - self.as_raw().y_coord() - } - - /// Serializes point into (un)compressed form - pub fn to_bytes(self, compressed: bool) -> EncodedPoint { - if compressed { - EncodedPoint::Compressed(self.as_raw().serialize_compressed()) - } else { - EncodedPoint::Uncompressed(self.as_raw().serialize_uncompressed()) - } - } - - /// Clones the referenced point - pub fn to_point(self) -> Point { - // Safety: `self` holds the same guarantees as `Point` requires to meet - unsafe { Point::from_raw_unchecked(self.as_raw().clone()) } - } - - /// Constructs a `PointRef` from reference to low-level [ECPoint] implementor - /// - /// Returns error if point is not valid. Valid point is either a zero point, or a point of - /// [group order]. - /// - /// Typically, you don't need to use this constructor. See [generator](Point::generator), - /// [base_point2](Point::base_point2) constructors, and `From` and `TryFrom` traits - /// implemented for `Point` and `PointRef`. - /// - /// [ECPoint]: crate::elliptic::curves::ECPoint - /// [group order]: crate::elliptic::curves::ECScalar::group_order - pub fn from_raw(raw_point: &'p E::Point) -> Result { - if raw_point.is_zero() || raw_point.check_point_order_equals_group_order() { - Ok(Self { raw_point }) - } else { - Err(MismatchedPointOrder::new()) - } - } - - /// Constructs a `PointRef` from reference to low-level [ECPoint] implementor - /// - /// # Safety - /// - /// This function will not perform any checks against the point. You must guarantee that point - /// order is equal to curve [group order]. To perform this check, you may use - /// [ECPoint::check_point_order_equals_group_order][check_point_order_equals_group_order] - /// method. - /// - /// Note that it implies that point must not be zero (zero point has `order=1`). - /// - /// [ECPoint]: crate::elliptic::curves::ECPoint - /// [group order]: crate::elliptic::curves::ECScalar::group_order - /// [check_point_order_equals_group_order]: crate::elliptic::curves::ECPoint::check_point_order_equals_group_order - pub unsafe fn from_raw_unchecked(raw_point: &'p E::Point) -> Self { - PointRef { raw_point } - } - - /// Returns a reference to low-level point implementation - /// - /// Typically, you don't need to work with `ECPoint` trait directly. `PointRef` wraps a - /// reference to `ECPoint` implementation and provides convenient utilities around it: it - /// implements arithmetic operators, serialization trait, various getters (like - /// [`.coords()`](Self::coords)). If you believe that some functionality is missing, please - /// [open an issue](https://github.com/ZenGo-X/curv). - pub fn as_raw(self) -> &'p E::Point { - self.raw_point - } -} - -impl<'p, E: Curve> Clone for PointRef<'p, E> { - fn clone(&self) -> Self { - // Safety: `self` is guaranteed to be nonzero - unsafe { Self::from_raw_unchecked(self.as_raw()) } - } -} - -impl<'p, E: Curve> Copy for PointRef<'p, E> {} - -impl<'p, E: Curve> fmt::Debug for PointRef<'p, E> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.as_raw().fmt(f) - } -} - -impl<'p, E: Curve> PartialEq for PointRef<'p, E> { - fn eq(&self, other: &Self) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { - fn eq(&self, other: &Point) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl<'p, E: Curve> PartialEq> for PointRef<'p, E> { - fn eq(&self, other: &Generator) -> bool { - self.as_raw().eq(other.as_raw()) - } -} - -impl<'p, E: Curve> From<&'p Point> for PointRef<'p, E> { - fn from(point: &'p Point) -> Self { - // Safety: `Point` holds the same guarantees as `PointRef` - unsafe { PointRef::from_raw_unchecked(point.as_raw()) } - } -} - -impl From> for PointRef<'static, E> { - fn from(g: Generator) -> Self { - // Safety: generator must be of group_order - unsafe { PointRef::from_raw_unchecked(g.as_raw()) } - } -} - -impl<'p, E: Curve> Serialize for PointRef<'p, E> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - use serde_bytes::Bytes; - - let mut s = serializer.serialize_struct("Point", 2)?; - s.serialize_field("curve", E::CURVE_NAME)?; - s.serialize_field( - "point", - // Serializes bytes efficiently - Bytes::new(&self.to_bytes(true)), - )?; - s.end() - } -} diff --git a/src/elliptic/curves/wrappers/scalar.rs b/src/elliptic/curves/wrappers/scalar.rs index 0fa6e485..3b782603 100644 --- a/src/elliptic/curves/wrappers/scalar.rs +++ b/src/elliptic/curves/wrappers/scalar.rs @@ -1,10 +1,9 @@ use std::{fmt, iter}; use crate::elliptic::curves::traits::{Curve, ECScalar}; -use crate::BigInt; - use crate::elliptic::curves::wrappers::encoded_scalar::EncodedScalar; use crate::elliptic::curves::{DeserializationError, ZeroScalarError}; +use crate::BigInt; /// Scalar value in a prime field /// @@ -33,6 +32,7 @@ use crate::elliptic::curves::{DeserializationError, ZeroScalarError}; /// a + b * c /// } /// ``` +#[repr(transparent)] pub struct Scalar { raw_scalar: E::Scalar, } diff --git a/src/elliptic/curves/wrappers/serde_support.rs b/src/elliptic/curves/wrappers/serde_support.rs index db508f2a..45d19d7c 100644 --- a/src/elliptic/curves/wrappers/serde_support.rs +++ b/src/elliptic/curves/wrappers/serde_support.rs @@ -4,6 +4,7 @@ use std::marker::PhantomData; use serde::de::{Error, MapAccess, Visitor}; use serde::ser::SerializeStruct; use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde_bytes::Bytes; use crate::elliptic::curves::{Curve, Point, Scalar}; @@ -11,12 +12,19 @@ use crate::elliptic::curves::{Curve, Point, Scalar}; // --- Point (de)serialization // --- -impl Serialize for Point { +impl<'p, E: Curve> Serialize for Point { fn serialize(&self, serializer: S) -> Result where S: Serializer, { - self.as_point().serialize(serializer) + let mut s = serializer.serialize_struct("Point", 2)?; + s.serialize_field("curve", E::CURVE_NAME)?; + s.serialize_field( + "point", + // Serializes bytes efficiently + Bytes::new(&self.to_bytes(true)), + )?; + s.end() } } @@ -158,7 +166,7 @@ impl Serialize for Scalar { s.serialize_field( "scalar", // Serializes bytes efficiently - serde_bytes::Bytes::new(&self.to_bytes()), + Bytes::new(&self.to_bytes()), )?; s.end() } From a1d1464a3974d684a27ef8bc467828b101869c98 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 27 Jul 2021 16:18:40 +0300 Subject: [PATCH 92/93] Move actual unsafe code to a single function --- src/elliptic/curves/wrappers/point.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index 36e3ce07..765fb1f5 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -192,8 +192,8 @@ impl Point { /// [group order]: crate::elliptic::curves::ECScalar::group_order pub fn from_raw_ref(raw_point: &E::Point) -> Result<&Self, MismatchedPointOrder> { if raw_point.is_zero() || raw_point.check_point_order_equals_group_order() { - // Safety: Self is repr(transparent) wrapper over E::Point => cast is sound - let reference = unsafe { &*(raw_point as *const E::Point as *const Self) }; + // Safety: we checked that point is either zero or has correct order + let reference = unsafe { Self::from_raw_ref_unchecked(raw_point) }; Ok(reference) } else { Err(MismatchedPointOrder::new()) From 3e315f5cdf94fc9d0f368c428331d248ab7a0cbe Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 27 Jul 2021 16:43:37 +0300 Subject: [PATCH 93/93] Finalization --- .../proofs/sigma_valid_pedersen_blind.rs | 4 +- .../secret_sharing/feldman_vss.rs | 6 +- .../dh_key_exchange_variant_with_pok_comm.rs | 17 ++-- src/elliptic/curves/wrappers/arithmetic.rs | 6 ++ src/elliptic/curves/wrappers/format.rs | 84 ------------------- src/elliptic/curves/wrappers/mod.rs | 1 - src/elliptic/curves/wrappers/point.rs | 7 +- 7 files changed, 21 insertions(+), 104 deletions(-) delete mode 100644 src/elliptic/curves/wrappers/format.rs diff --git a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs index 82af4240..3066616b 100644 --- a/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs +++ b/src/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs @@ -46,7 +46,7 @@ impl PedersenBlindingProof { ); let g = Point::::generator(); let e = Sha256::new() - .chain_points([&g.to_point(), h, &com, &a]) + .chain_points([g.as_point(), h, &com, &a]) .chain_scalar(&m) .result_scalar(); @@ -65,7 +65,7 @@ impl PedersenBlindingProof { let g = Point::::generator(); let h = Point::::base_point2(); let e = Sha256::new() - .chain_points([&g.to_point(), h, &proof.com, &proof.a]) + .chain_points([g.as_point(), h, &proof.com, &proof.a]) .chain_scalar(&proof.m) .result_scalar(); diff --git a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs index e518d8b9..e1bd78a8 100644 --- a/src/cryptographic_primitives/secret_sharing/feldman_vss.rs +++ b/src/cryptographic_primitives/secret_sharing/feldman_vss.rs @@ -135,7 +135,7 @@ impl VerifiableSS { } // returns vector of coefficients - #[deprecated(since = "0.7.1", note = "please use Polynomial::sample instead")] + #[deprecated(since = "0.8.0", note = "please use Polynomial::sample instead")] pub fn sample_polynomial(t: usize, coef0: &Scalar) -> Vec> { Polynomial::::sample_exact_with_fixed_const_term(t.try_into().unwrap(), coef0.clone()) .coefficients() @@ -143,7 +143,7 @@ impl VerifiableSS { } #[deprecated( - since = "0.7.1", + since = "0.8.0", note = "please use Polynomial::evaluate_many_bigint instead" )] pub fn evaluate_polynomial(coefficients: &[Scalar], index_vec: &[usize]) -> Vec> { @@ -152,7 +152,7 @@ impl VerifiableSS { .collect() } - #[deprecated(since = "0.7.1", note = "please use Polynomial::evaluate instead")] + #[deprecated(since = "0.8.0", note = "please use Polynomial::evaluate instead")] pub fn mod_evaluate_polynomial(coefficients: &[Scalar], point: Scalar) -> Scalar { Polynomial::::from_coefficients(coefficients.to_vec()).evaluate(&point) } diff --git a/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs b/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs index b1578ce1..b9f2165c 100644 --- a/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs +++ b/src/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs @@ -77,13 +77,13 @@ impl Party1FirstMessage { // we use hash based commitment let pk_commitment_blind_factor = BigInt::sample(SECURITY_BITS); let pk_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(public_share.to_bytes(true).as_ref()), + &BigInt::from_bytes(&public_share.to_bytes(true)), &pk_commitment_blind_factor, ); let zk_pok_blind_factor = BigInt::sample(SECURITY_BITS); let zk_pok_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(d_log_proof.pk_t_rand_commitment.to_bytes(true).as_ref()), + &BigInt::from_bytes(&d_log_proof.pk_t_rand_commitment.to_bytes(true)), &zk_pok_blind_factor, ); let ec_key_pair = EcKeyPair { @@ -115,13 +115,13 @@ impl Party1FirstMessage { let pk_commitment_blind_factor = BigInt::sample(SECURITY_BITS); let pk_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(public_share.to_bytes(true).as_ref()), + &BigInt::from_bytes(&public_share.to_bytes(true)), &pk_commitment_blind_factor, ); let zk_pok_blind_factor = BigInt::sample(SECURITY_BITS); let zk_pok_commitment = HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(d_log_proof.pk_t_rand_commitment.to_bytes(true).as_ref()), + &BigInt::from_bytes(&d_log_proof.pk_t_rand_commitment.to_bytes(true)), &zk_pok_blind_factor, ); @@ -214,7 +214,7 @@ impl Party2SecondMessage { let mut flag = true; if party_one_pk_commitment != &HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(party_one_public_share.to_bytes(true).as_ref()), + &BigInt::from_bytes(&party_one_public_share.to_bytes(true)), &party_one_pk_commitment_blind_factor, ) { @@ -223,12 +223,7 @@ impl Party2SecondMessage { if party_one_zk_pok_commitment != &HashCommitment::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes( - party_one_d_log_proof - .pk_t_rand_commitment - .to_bytes(true) - .as_ref(), - ), + &BigInt::from_bytes(&party_one_d_log_proof.pk_t_rand_commitment.to_bytes(true)), &party_one_zk_pok_blind_factor, ) { diff --git a/src/elliptic/curves/wrappers/arithmetic.rs b/src/elliptic/curves/wrappers/arithmetic.rs index 88a26fdb..d25b7003 100644 --- a/src/elliptic/curves/wrappers/arithmetic.rs +++ b/src/elliptic/curves/wrappers/arithmetic.rs @@ -129,6 +129,8 @@ macro_rules! matrix { } fn addition_of_two_points(result: E::Point) -> Point { + // Safety: addition of two points of group order is always either a zero point or point of group + // order: `A + B = aG + bG = (a + b)G` unsafe { Point::from_raw_unchecked(result) } } @@ -152,6 +154,8 @@ matrix! { } fn subtraction_of_two_point(result: E::Point) -> Point { + // Safety: subtraction of two points of group order is always either a zero point or point of group + // order: `A - B = aG - bG = (a - b)G` unsafe { Point::from_raw_unchecked(result) } } @@ -175,6 +179,8 @@ matrix! { } fn multiplication_of_point_at_scalar(result: E::Point) -> Point { + // Safety: multiplication of point of group order at a scalar is always either a zero point or + // point of group order: `kA = kaG` unsafe { Point::from_raw_unchecked(result) } } diff --git a/src/elliptic/curves/wrappers/format.rs b/src/elliptic/curves/wrappers/format.rs deleted file mode 100644 index 653b59ca..00000000 --- a/src/elliptic/curves/wrappers/format.rs +++ /dev/null @@ -1,84 +0,0 @@ -use std::borrow::Cow; -use std::convert::TryFrom; -use std::iter; - -use serde::{Deserialize, Serialize}; -use thiserror::Error; - -use crate::elliptic::curves::traits::*; - -use super::*; - -#[derive(Serialize, Deserialize)] -#[serde(bound = "")] -pub struct ScalarFormat { - curve: Cow<'static, str>, - #[serde(with = "hex")] - scalar: ScalarHex, -} - -impl TryFrom> for Scalar { - type Error = ConvertParsedScalarError; - - fn try_from(parsed: ScalarFormat) -> Result { - if parsed.curve != E::CURVE_NAME { - return Err(ConvertParsedScalarError::MismatchedCurve { - got: parsed.curve, - expected: E::CURVE_NAME, - }); - } - - Ok(Scalar::from_raw(parsed.scalar.0)) - } -} - -impl From> for ScalarFormat { - fn from(s: Scalar) -> Self { - ScalarFormat { - curve: E::CURVE_NAME.into(), - scalar: ScalarHex(s.into_raw()), - } - } -} - -struct ScalarHex(E::Scalar); - -impl hex::ToHex for &ScalarHex { - fn encode_hex>(&self) -> T { - self.0.serialize().encode_hex() - } - - fn encode_hex_upper>(&self) -> T { - self.0.serialize().encode_hex_upper() - } -} - -impl hex::FromHex for ScalarHex { - type Error = ScalarFromhexError; - - fn from_hex>(hex: T) -> Result { - let bytes = Vec::from_hex(hex).map_err(ScalarFromhexError::InvalidHex)?; - E::Scalar::deserialize(&bytes) - .or(Err(ScalarFromhexError::InvalidScalar)) - .map(ScalarHex) - } -} - -#[derive(Debug, Error)] -pub enum ConvertParsedScalarError { - #[error("scalar must not be zero")] - ZeroScalar, - #[error("expected scalar of curve {expected}, but got scalar of curve {got}")] - MismatchedCurve { - got: Cow<'static, str>, - expected: &'static str, - }, -} - -#[derive(Debug, Error)] -pub enum ScalarFromhexError { - #[error("scalar contains invalid hex: {0}")] - InvalidHex(hex::FromHexError), - #[error("scalar is not valid")] - InvalidScalar, -} diff --git a/src/elliptic/curves/wrappers/mod.rs b/src/elliptic/curves/wrappers/mod.rs index ef815f17..9f63f382 100644 --- a/src/elliptic/curves/wrappers/mod.rs +++ b/src/elliptic/curves/wrappers/mod.rs @@ -2,7 +2,6 @@ mod arithmetic; mod encoded_point; mod encoded_scalar; pub mod error; -mod format; mod generator; mod point; mod scalar; diff --git a/src/elliptic/curves/wrappers/point.rs b/src/elliptic/curves/wrappers/point.rs index 765fb1f5..a5eb69be 100644 --- a/src/elliptic/curves/wrappers/point.rs +++ b/src/elliptic/curves/wrappers/point.rs @@ -142,8 +142,8 @@ impl Point { /// Tries to parse a point in (un)compressed form /// /// Whether it's in compressed or uncompressed form will be deduced from its length - pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result { - let p = E::Point::deserialize(bytes.as_ref()) + pub fn from_bytes(bytes: &[u8]) -> Result { + let p = E::Point::deserialize(bytes) .map_err(|_: DeserializationError| PointFromBytesError::DeserializationError)?; Self::from_raw(p).map_err(PointFromBytesError::InvalidPoint) } @@ -223,7 +223,7 @@ impl Point { /// Constructs a `Point` from reference to low-level [ECPoint] implementor /// - /// Unsafe equivalent of [from_raw](Self::from_raw). It debug asserts that given `raw_point` is + /// Unsafe equivalent of [from_raw_ref](Self::from_raw_ref). It debug asserts that given `raw_point` is /// valid (the assertion is optimized out in release builds by default). /// /// # Safety @@ -238,6 +238,7 @@ impl Point { /// [check_point_order_equals_group_order]: crate::elliptic::curves::ECPoint::check_point_order_equals_group_order /// [is_zero]: crate::elliptic::curves::ECPoint::is_zero pub unsafe fn from_raw_ref_unchecked(raw_point: &E::Point) -> &Self { + debug_assert!(raw_point.is_zero() || raw_point.check_point_order_equals_group_order()); // Safety: Self is repr(transparent) wrapper over E::Point => cast is sound &*(raw_point as *const E::Point as *const Self) }