diff --git a/Cargo.lock b/Cargo.lock index 690171bf..8ce391fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -330,9 +330,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "elliptic-curve" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdd8c93ccd534d6a9790f4455cd71e7adb53a12e9af7dd54d1e258473f100cea" +checksum = "4f6664c6a37892ed55da8dda26a99e6ccc783f0c72fa3c2eeaa00ed30d8f4d9a" dependencies = [ "base16ct", "base64ct", diff --git a/p384/Cargo.toml b/p384/Cargo.toml index ba21e60b..691dd6ca 100644 --- a/p384/Cargo.toml +++ b/p384/Cargo.toml @@ -17,7 +17,7 @@ edition = "2021" rust-version = "1.57" [dependencies] -elliptic-curve = { version = "0.12", default-features = false, features = ["hazmat", "sec1"] } +elliptic-curve = { version = "0.12.1", default-features = false, features = ["hazmat", "sec1"] } # optional dependencies ecdsa-core = { version = "0.14", package = "ecdsa", optional = true, default-features = false, features = ["der"] } diff --git a/p384/src/arithmetic/field.rs b/p384/src/arithmetic/field.rs index 03eef3eb..283eebb0 100644 --- a/p384/src/arithmetic/field.rs +++ b/p384/src/arithmetic/field.rs @@ -28,8 +28,8 @@ use self::field_impl::*; use crate::FieldBytes; use core::ops::{AddAssign, MulAssign, Neg, SubAssign}; use elliptic_curve::{ - bigint::{self, ArrayEncoding, Encoding, Integer, Limb, U384}, - subtle::{Choice, ConstantTimeEq, ConstantTimeLess, CtOption}, + bigint::{self, Encoding, Limb, U384}, + subtle::{Choice, ConstantTimeEq, CtOption}, }; /// Constant representing the modulus @@ -40,7 +40,7 @@ pub(crate) const MODULUS: U384 = U384::from_be_hex("ffffffffffffffffffffffffffff #[derive(Clone, Copy, Debug)] pub struct FieldElement(pub(super) U384); -impl_field_element!( +elliptic_curve::impl_field_element!( FieldElement, FieldBytes, U384, diff --git a/p384/src/arithmetic/macros.rs b/p384/src/arithmetic/macros.rs index 57b8bb47..62789f24 100644 --- a/p384/src/arithmetic/macros.rs +++ b/p384/src/arithmetic/macros.rs @@ -1,429 +1,3 @@ -//! Field arithmetic macros - -// TODO(tarcieri): extract this into the `elliptic-curve` crate when stable - -/// Provides both inherent and trait impls for a field element type which are -/// backed by a core set of arithmetic functions specified as macro arguments. -/// -/// # Inherent impls -/// - `const ZERO: Self` -/// - `const ONE: Self` (multiplicative identity) -/// - `pub fn from_be_bytes` -/// - `pub fn from_be_slice` -/// - `pub fn from_le_bytes` -/// - `pub fn from_le_slice` -/// - `pub fn from_uint` -/// - `fn from_uint_unchecked` -/// - `pub fn to_be_bytes` -/// - `pub fn to_le_bytes` -/// - `pub fn to_canonical` -/// - `pub fn is_odd` -/// - `pub fn is_zero` -/// - `pub fn double` -/// -/// NOTE: field implementations must provide their own inherent impls of -/// the following methods in order for the code generated by this macro to -/// compile: -/// -/// - `pub fn invert` -/// - `pub fn sqrt` -/// -/// # Trait impls -/// - `AsRef<$arr>` -/// - `ConditionallySelectable` -/// - `ConstantTimeEq` -/// - `ConstantTimeGreater` -/// - `ConstantTimeLess` -/// - `Default` -/// - `DefaultIsZeroes` -/// - `Eq` -/// - `Field` -/// - `PartialEq` -/// -/// ## Ops -/// - `Add` -/// - `AddAssign` -/// - `Sub` -/// - `SubAssign` -/// - `Mul` -/// - `MulAssign` -/// - `Neg` -macro_rules! impl_field_element { - ( - $fe:tt, - $bytes:ty, - $uint:ty, - $modulus:expr, - $arr:ty, - $from_mont:ident, - $to_mont:ident, - $add:ident, - $sub:ident, - $mul:ident, - $neg:ident, - $square:ident - ) => { - impl $fe { - /// Zero element. - pub const ZERO: Self = Self(<$uint>::ZERO); - - /// Multiplicative identity. - pub const ONE: Self = Self::from_uint_unchecked(<$uint>::ONE); - - /// Create a [` - #[doc = stringify!($fe)] - /// `] from a canonical big-endian representation. - pub fn from_be_bytes(repr: $bytes) -> ::elliptic_curve::subtle::CtOption { - Self::from_uint(<$uint>::from_be_byte_array(repr)) - } - - /// Decode [` - #[doc = stringify!($fe)] - /// `] from a big endian byte slice. - pub fn from_be_slice(slice: &[u8]) -> ::elliptic_curve::Result { - <$uint as ::elliptic_curve::bigint::Encoding>::Repr::try_from(slice) - .ok() - .and_then(|array| Self::from_be_bytes(array.into()).into()) - .ok_or(::elliptic_curve::Error) - } - - /// Create a [` - #[doc = stringify!($fe)] - /// `] from a canonical little-endian representation. - pub fn from_le_bytes(repr: $bytes) -> ::elliptic_curve::subtle::CtOption { - Self::from_uint(<$uint>::from_le_byte_array(repr)) - } - - /// Decode [` - #[doc = stringify!($fe)] - /// `] from a little endian byte slice. - pub fn from_le_slice(slice: &[u8]) -> ::elliptic_curve::Result { - <$uint as Encoding>::Repr::try_from(slice) - .ok() - .and_then(|array| Self::from_le_bytes(array.into()).into()) - .ok_or(::elliptic_curve::Error) - } - - /// Decode [` - #[doc = stringify!($fe)] - /// `] - /// from [` - #[doc = stringify!($uint)] - /// `] converting it into Montgomery form: - /// - /// ```text - /// w * R^2 * R^-1 mod p = wR mod p - /// ``` - pub fn from_uint(uint: $uint) -> ::elliptic_curve::subtle::CtOption { - let is_some = uint.ct_lt(&$modulus); - ::elliptic_curve::subtle::CtOption::new(Self::from_uint_unchecked(uint), is_some) - } - - /// Parse a [` - #[doc = stringify!($fe)] - /// `] from big endian hex-encoded bytes. - /// - /// Does *not* perform a check that the field element does not overflow the order. - /// - /// This method is primarily intended for defining internal constants. - #[allow(dead_code)] - pub(crate) const fn from_be_hex(hex: &str) -> Self { - Self::from_uint_unchecked(<$uint>::from_be_hex(hex)) - } - - /// Parse a [` - #[doc = stringify!($fe)] - /// `] from little endian hex-encoded bytes. - /// - /// Does *not* perform a check that the field element does not overflow the order. - /// - /// This method is primarily intended for defining internal constants. - #[allow(dead_code)] - pub(crate) const fn from_le_hex(hex: &str) -> Self { - Self::from_uint_unchecked(<$uint>::from_le_hex(hex)) - } - - /// Decode [` - #[doc = stringify!($fe)] - /// `] from [` - #[doc = stringify!($uint)] - /// `] converting it into Montgomery form. - /// - /// Does *not* perform a check that the field element does not overflow the order. - /// - /// Used incorrectly this can lead to invalid results! - const fn from_uint_unchecked(w: $uint) -> Self { - Self(<$uint>::from_uint_array($to_mont(w.as_uint_array()))) - } - - /// Returns the big-endian encoding of this [` - #[doc = stringify!($fe)] - /// `]. - pub fn to_be_bytes(self) -> $bytes { - self.to_canonical().to_be_byte_array() - } - - /// Returns the little-endian encoding of this [` - #[doc = stringify!($fe)] - /// `]. - pub fn to_le_bytes(self) -> $bytes { - self.to_canonical().to_le_byte_array() - } - - /// Translate [` - #[doc = stringify!($fe)] - /// `] out of the Montgomery domain, returning a [` - #[doc = stringify!($uint)] - /// `] in canonical form. - #[inline] - pub const fn to_canonical(self) -> $uint { - <$uint>::from_uint_array($from_mont(self.0.as_uint_array())) - } - - /// Determine if this [` - #[doc = stringify!($fe)] - /// `] is odd in the SEC1 sense: `self mod 2 == 1`. - /// - /// # Returns - /// - /// If odd, return `Choice(1)`. Otherwise, return `Choice(0)`. - pub fn is_odd(&self) -> Choice { - self.to_canonical().is_odd() - } - - /// Determine if this [` - #[doc = stringify!($fe)] - /// `] is zero. - /// - /// # Returns - /// - /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. - pub fn is_zero(&self) -> Choice { - self.ct_eq(&Self::ZERO) - } - - /// Add elements. - pub const fn add(&self, rhs: &Self) -> Self { - Self(<$uint>::from_uint_array($add( - self.0.as_uint_array(), - rhs.0.as_uint_array(), - ))) - } - - /// Double element (add it to itself). - #[must_use] - pub const fn double(&self) -> Self { - self.add(self) - } - - /// Subtract elements. - pub const fn sub(&self, rhs: &Self) -> Self { - Self(<$uint>::from_uint_array($sub( - self.0.as_uint_array(), - rhs.0.as_uint_array(), - ))) - } - - /// Multiply elements. - pub const fn mul(&self, rhs: &Self) -> Self { - Self(<$uint>::from_uint_array($mul( - self.0.as_uint_array(), - rhs.0.as_uint_array(), - ))) - } - - /// Negate element. - pub const fn neg(&self) -> Self { - Self(<$uint>::from_uint_array($neg(self.0.as_uint_array()))) - } - - /// Compute modular square. - #[must_use] - pub const fn square(&self) -> Self { - Self(<$uint>::from_uint_array($square(self.0.as_uint_array()))) - } - } - - impl AsRef<$arr> for $fe { - fn as_ref(&self) -> &$arr { - self.0.as_ref() - } - } - - impl Default for $fe { - fn default() -> Self { - Self::ZERO - } - } - - impl Eq for $fe {} - - impl PartialEq for $fe { - fn eq(&self, rhs: &Self) -> bool { - self.0.ct_eq(&(rhs.0)).into() - } - } - - impl ::elliptic_curve::subtle::ConditionallySelectable for $fe { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Self(<$uint>::conditional_select(&a.0, &b.0, choice)) - } - } - - impl ::elliptic_curve::subtle::ConstantTimeEq for $fe { - fn ct_eq(&self, other: &Self) -> ::elliptic_curve::subtle::Choice { - self.0.ct_eq(&other.0) - } - } - - impl ::elliptic_curve::subtle::ConstantTimeGreater for $fe { - fn ct_gt(&self, other: &Self) -> ::elliptic_curve::subtle::Choice { - self.0.ct_gt(&other.0) - } - } - - impl ::elliptic_curve::subtle::ConstantTimeLess for $fe { - fn ct_lt(&self, other: &Self) -> ::elliptic_curve::subtle::Choice { - self.0.ct_lt(&other.0) - } - } - - impl ::elliptic_curve::zeroize::DefaultIsZeroes for $fe {} - - impl ::elliptic_curve::ff::Field for $fe { - fn random(mut rng: impl ::elliptic_curve::rand_core::RngCore) -> Self { - // NOTE: can't use ScalarCore::random due to CryptoRng bound - let mut bytes = <$bytes>::default(); - - loop { - rng.fill_bytes(&mut bytes); - if let Some(fe) = Self::from_be_bytes(bytes).into() { - return fe; - } - } - } - - fn zero() -> Self { - Self::ZERO - } - - fn one() -> Self { - Self::ONE - } - - fn is_zero(&self) -> Choice { - Self::ZERO.ct_eq(self) - } - - #[must_use] - fn square(&self) -> Self { - self.square() - } - - #[must_use] - fn double(&self) -> Self { - self.double() - } - - fn invert(&self) -> CtOption { - self.invert() - } - - fn sqrt(&self) -> CtOption { - self.sqrt() - } - } - - impl_field_op!($fe, $uint, Add, add, $add); - impl_field_op!($fe, $uint, Sub, sub, $sub); - impl_field_op!($fe, $uint, Mul, mul, $mul); - - impl AddAssign<$fe> for $fe { - #[inline] - fn add_assign(&mut self, other: $fe) { - *self = *self + other; - } - } - - impl AddAssign<&$fe> for $fe { - #[inline] - fn add_assign(&mut self, other: &$fe) { - *self = *self + other; - } - } - - impl SubAssign<$fe> for $fe { - #[inline] - fn sub_assign(&mut self, other: $fe) { - *self = *self - other; - } - } - - impl SubAssign<&$fe> for $fe { - #[inline] - fn sub_assign(&mut self, other: &$fe) { - *self = *self - other; - } - } - - impl MulAssign<&$fe> for $fe { - #[inline] - fn mul_assign(&mut self, other: &$fe) { - *self = *self * other; - } - } - - impl MulAssign for $fe { - #[inline] - fn mul_assign(&mut self, other: $fe) { - *self = *self * other; - } - } - - impl Neg for $fe { - type Output = $fe; - - #[inline] - fn neg(self) -> $fe { - Self($neg(self.as_ref()).into()) - } - } - }; -} - -/// Emit impls for a `core::ops` trait for all combinations of reference types, -/// which thunk to the given function. -macro_rules! impl_field_op { - ($fe:tt, $uint:ty, $op:tt, $op_fn:ident, $func:ident) => { - impl ::core::ops::$op for $fe { - type Output = $fe; - - #[inline] - fn $op_fn(self, rhs: $fe) -> $fe { - $fe($func(self.as_ref(), rhs.as_ref()).into()) - } - } - - impl ::core::ops::$op<&$fe> for $fe { - type Output = $fe; - - #[inline] - fn $op_fn(self, rhs: &$fe) -> $fe { - $fe($func(self.as_ref(), rhs.as_ref()).into()) - } - } - - impl ::core::ops::$op<&$fe> for &$fe { - type Output = $fe; - - #[inline] - fn $op_fn(self, rhs: &$fe) -> $fe { - $fe($func(self.as_ref(), rhs.as_ref()).into()) - } - } - }; -} - /// Implement field element inversion. macro_rules! impl_field_invert { ( diff --git a/p384/src/arithmetic/projective.rs b/p384/src/arithmetic/projective.rs index 139d6e24..b16960a4 100644 --- a/p384/src/arithmetic/projective.rs +++ b/p384/src/arithmetic/projective.rs @@ -17,6 +17,7 @@ use elliptic_curve::{ rand_core::RngCore, sec1::{FromEncodedPoint, ToEncodedPoint}, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, + weierstrass, zeroize::DefaultIsZeroes, Error, PrimeCurveArithmetic, ProjectiveArithmetic, Result, }; @@ -92,95 +93,31 @@ impl ProjectivePoint { /// Returns `self + other`. fn add(&self, other: &ProjectivePoint) -> ProjectivePoint { - // We implement the complete addition formula from Renes-Costello-Batina 2015 - // (https://eprint.iacr.org/2015/1060 Algorithm 4). The comments after each line - // indicate which algorithm steps are being performed. - - let xx = self.x * &other.x; // 1 - let yy = self.y * &other.y; // 2 - let zz = self.z * &other.z; // 3 - let xy_pairs = ((self.x + &self.y) * &(other.x + &other.y)) - &(xx + &yy); // 4, 5, 6, 7, 8 - let yz_pairs = ((self.y + &self.z) * &(other.y + &other.z)) - &(yy + &zz); // 9, 10, 11, 12, 13 - let xz_pairs = ((self.x + &self.z) * &(other.x + &other.z)) - &(xx + &zz); // 14, 15, 16, 17, 18 - - let bzz_part = xz_pairs - &(CURVE_EQUATION_B * &zz); // 19, 20 - let bzz3_part = bzz_part.double() + &bzz_part; // 21, 22 - let yy_m_bzz3 = yy - &bzz3_part; // 23 - let yy_p_bzz3 = yy + &bzz3_part; // 24 - - let zz3 = zz.double() + &zz; // 26, 27 - let bxz_part = (CURVE_EQUATION_B * &xz_pairs) - &(zz3 + &xx); // 25, 28, 29 - let bxz3_part = bxz_part.double() + &bxz_part; // 30, 31 - let xx3_m_zz3 = xx.double() + &xx - &zz3; // 32, 33, 34 - - ProjectivePoint { - x: (yy_p_bzz3 * &xy_pairs) - &(yz_pairs * &bxz3_part), // 35, 39, 40 - y: (yy_p_bzz3 * &yy_m_bzz3) + &(xx3_m_zz3 * &bxz3_part), // 36, 37, 38 - z: (yy_m_bzz3 * &yz_pairs) + &(xy_pairs * &xx3_m_zz3), // 41, 42, 43 - } + let (x, y, z) = weierstrass::add( + (self.x, self.y, self.z), + (other.x, other.y, other.z), + CURVE_EQUATION_B, + ); + Self { x, y, z } } /// Returns `self + other`. fn add_mixed(&self, other: &AffinePoint) -> ProjectivePoint { - // We implement the complete mixed addition formula from Renes-Costello-Batina - // 2015 (Algorithm 5). The comments after each line indicate which algorithm - // steps are being performed. - - let xx = self.x * &other.x; // 1 - let yy = self.y * &other.y; // 2 - let xy_pairs = ((self.x + &self.y) * &(other.x + &other.y)) - &(xx + &yy); // 3, 4, 5, 6, 7 - let yz_pairs = (other.y * &self.z) + &self.y; // 8, 9 (t4) - let xz_pairs = (other.x * &self.z) + &self.x; // 10, 11 (y3) - - let bz_part = xz_pairs - &(CURVE_EQUATION_B * &self.z); // 12, 13 - let bz3_part = bz_part.double() + &bz_part; // 14, 15 - let yy_m_bzz3 = yy - &bz3_part; // 16 - let yy_p_bzz3 = yy + &bz3_part; // 17 - - let z3 = self.z.double() + &self.z; // 19, 20 - let bxz_part = (CURVE_EQUATION_B * &xz_pairs) - &(z3 + &xx); // 18, 21, 22 - let bxz3_part = bxz_part.double() + &bxz_part; // 23, 24 - let xx3_m_zz3 = xx.double() + &xx - &z3; // 25, 26, 27 - - let mut ret = ProjectivePoint { - x: (yy_p_bzz3 * &xy_pairs) - &(yz_pairs * &bxz3_part), // 28, 32, 33 - y: (yy_p_bzz3 * &yy_m_bzz3) + &(xx3_m_zz3 * &bxz3_part), // 29, 30, 31 - z: (yy_m_bzz3 * &yz_pairs) + &(xy_pairs * &xx3_m_zz3), // 34, 35, 36 - }; + let (x, y, z) = weierstrass::add_mixed( + (self.x, self.y, self.z), + (other.x, other.y), + CURVE_EQUATION_B, + ); + + let mut ret = ProjectivePoint { x, y, z }; ret.conditional_assign(self, other.is_identity()); ret } /// Doubles this point. pub fn double(&self) -> ProjectivePoint { - // We implement the exception-free point doubling formula from - // Renes-Costello-Batina 2015 (Algorithm 6). The comments after each line - // indicate which algorithm steps are being performed. - - let xx = self.x.square(); // 1 - let yy = self.y.square(); // 2 - let zz = self.z.square(); // 3 - let xy2 = (self.x * &self.y).double(); // 4, 5 - let xz2 = (self.x * &self.z).double(); // 6, 7 - - let bzz_part = (CURVE_EQUATION_B * &zz) - &xz2; // 8, 9 - let bzz3_part = bzz_part.double() + &bzz_part; // 10, 11 - let yy_m_bzz3 = yy - &bzz3_part; // 12 - let yy_p_bzz3 = yy + &bzz3_part; // 13 - let y_frag = yy_p_bzz3 * &yy_m_bzz3; // 14 - let x_frag = yy_m_bzz3 * &xy2; // 15 - - let zz3 = zz.double() + &zz; // 16, 17 - let bxz2_part = (CURVE_EQUATION_B * &xz2) - &(zz3 + &xx); // 18, 19, 20 - let bxz6_part = bxz2_part.double() + &bxz2_part; // 21, 22 - let xx3_m_zz3 = xx.double() + &xx - &zz3; // 23, 24, 25 - - let y = y_frag + &(xx3_m_zz3 * &bxz6_part); // 26, 27 - let yz2 = (self.y * &self.z).double(); // 28, 29 - let x = x_frag - &(bxz6_part * &yz2); // 30, 31 - let z = (yz2 * &yy).double().double(); // 32, 33, 34 - - ProjectivePoint { x, y, z } + let (x, y, z) = weierstrass::double((self.x, self.y, self.z), CURVE_EQUATION_B); + Self { x, y, z } } /// Returns `self - other`. diff --git a/p384/src/arithmetic/scalar.rs b/p384/src/arithmetic/scalar.rs index 50d850a4..36f90ec6 100644 --- a/p384/src/arithmetic/scalar.rs +++ b/p384/src/arithmetic/scalar.rs @@ -15,13 +15,10 @@ use self::scalar_impl::*; use crate::{FieldBytes, NistP384, SecretKey, U384}; use core::ops::{AddAssign, MulAssign, Neg, SubAssign}; use elliptic_curve::{ - bigint::{self, ArrayEncoding, Encoding, Integer, Limb}, + bigint::{self, Encoding, Limb}, ff::PrimeField, ops::Reduce, - subtle::{ - Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, - CtOption, - }, + subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption}, Curve as _, Error, IsHigh, Result, ScalarArithmetic, ScalarCore, }; @@ -37,7 +34,7 @@ impl ScalarArithmetic for NistP384 { #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] pub struct Scalar(U384); -impl_field_element!( +elliptic_curve::impl_field_element!( Scalar, FieldBytes, U384,