From 9835e2ae736235810b4ea1c162ca5e65c547e770 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 04:49:50 +0200 Subject: Merging upstream version 1.71.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/p384/src/arithmetic.rs | 76 +++- vendor/p384/src/arithmetic/affine.rs | 415 ------------------- vendor/p384/src/arithmetic/field.rs | 89 ++-- vendor/p384/src/arithmetic/hash2curve.rs | 326 +++++++++++++++ vendor/p384/src/arithmetic/macros.rs | 8 +- vendor/p384/src/arithmetic/projective.rs | 673 ------------------------------- vendor/p384/src/arithmetic/scalar.rs | 182 ++++++--- vendor/p384/src/ecdh.rs | 8 +- vendor/p384/src/ecdsa.rs | 81 +++- vendor/p384/src/lib.rs | 53 ++- 10 files changed, 670 insertions(+), 1241 deletions(-) delete mode 100644 vendor/p384/src/arithmetic/affine.rs create mode 100644 vendor/p384/src/arithmetic/hash2curve.rs delete mode 100644 vendor/p384/src/arithmetic/projective.rs (limited to 'vendor/p384/src') diff --git a/vendor/p384/src/arithmetic.rs b/vendor/p384/src/arithmetic.rs index 6ffbcb7b3..09163d445 100644 --- a/vendor/p384/src/arithmetic.rs +++ b/vendor/p384/src/arithmetic.rs @@ -1,32 +1,64 @@ //! Pure Rust implementation of group operations on secp384r1. //! -//! Curve parameters can be found in FIPS 186-4: Digital Signature Standard -//! (DSS): +//! Curve parameters can be found in [NIST SP 800-186] § G.1.3: Curve P-384. //! -//! See section D.1.2.4: Curve P-384. +//! [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final #[macro_use] mod macros; -pub(crate) mod affine; pub(crate) mod field; -pub(crate) mod projective; +#[cfg(feature = "hash2curve")] +mod hash2curve; pub(crate) mod scalar; -use self::{ - affine::AffinePoint, - field::{FieldElement, MODULUS}, - projective::ProjectivePoint, - scalar::Scalar, -}; - -/// a = -3 (0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc) -const CURVE_EQUATION_A: FieldElement = FieldElement::ZERO - .sub(&FieldElement::ONE) - .sub(&FieldElement::ONE) - .sub(&FieldElement::ONE); - -/// b = b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 -/// 0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef -const CURVE_EQUATION_B: FieldElement = - FieldElement::from_be_hex("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"); +use self::{field::FieldElement, scalar::Scalar}; +use crate::NistP384; +use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; +use primeorder::{point_arithmetic, PrimeCurveParams}; + +/// Elliptic curve point in affine coordinates. +pub type AffinePoint = primeorder::AffinePoint; + +/// Elliptic curve point in projective coordinates. +pub type ProjectivePoint = primeorder::ProjectivePoint; + +impl CurveArithmetic for NistP384 { + type AffinePoint = AffinePoint; + type ProjectivePoint = ProjectivePoint; + type Scalar = Scalar; +} + +impl PrimeCurveArithmetic for NistP384 { + type CurveGroup = ProjectivePoint; +} + +/// Adapted from [NIST SP 800-186] § G.1.3: Curve P-384. +/// +/// [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final +impl PrimeCurveParams for NistP384 { + type FieldElement = FieldElement; + type PointArithmetic = point_arithmetic::EquationAIsMinusThree; + + /// a = -3 (0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc) + const EQUATION_A: FieldElement = FieldElement::from_u64(3).neg(); + + /// b = b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 + /// 0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef + const EQUATION_B: FieldElement = FieldElement::from_hex("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"); + + /// Base point of P-384. + /// + /// Defined in NIST SP 800-186 § G.1.3: Curve P-384. + /// + /// ```text + /// Gₓ = aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 + /// 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7 + /// Gᵧ = 3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c + /// e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f + /// ``` + const GENERATOR: (FieldElement, FieldElement) = ( + FieldElement::from_hex("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"), + FieldElement::from_hex("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"), + ); +} diff --git a/vendor/p384/src/arithmetic/affine.rs b/vendor/p384/src/arithmetic/affine.rs deleted file mode 100644 index 5f4a3f3fa..000000000 --- a/vendor/p384/src/arithmetic/affine.rs +++ /dev/null @@ -1,415 +0,0 @@ -//! Affine points on the NIST P-384 elliptic curve. - -#![allow(clippy::op_ref)] - -use core::ops::{Mul, Neg}; - -use super::{FieldElement, ProjectivePoint, CURVE_EQUATION_A, CURVE_EQUATION_B, MODULUS}; -use crate::{CompressedPoint, EncodedPoint, FieldBytes, NistP384, PublicKey, Scalar}; -use elliptic_curve::{ - group::{prime::PrimeCurveAffine, GroupEncoding}, - sec1::{self, FromEncodedPoint, ToEncodedPoint}, - subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, - zeroize::DefaultIsZeroes, - AffineArithmetic, AffineXCoordinate, DecompressPoint, Error, Result, -}; - -#[cfg(feature = "serde")] -use serdect::serde::{de, ser, Deserialize, Serialize}; - -impl AffineArithmetic for NistP384 { - type AffinePoint = AffinePoint; -} - -/// NIST P-384 (secp384r1) curve point expressed in affine coordinates. -/// -/// # `serde` support -/// -/// When the `serde` feature of this crate is enabled, the `Serialize` and -/// `Deserialize` traits are impl'd for this type. -/// -/// The serialization uses the [SEC1] `Elliptic-Curve-Point-to-Octet-String` -/// encoding, serialized as binary. -/// -/// When serialized with a text-based format, the SEC1 representation is -/// subsequently hex encoded. -/// -/// [SEC1]: https://www.secg.org/sec1-v2.pdf -#[derive(Clone, Copy, Debug)] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub struct AffinePoint { - /// x-coordinate - pub x: FieldElement, - - /// y-coordinate - pub y: FieldElement, - - /// Is this point the point at infinity? 0 = no, 1 = yes - /// - /// This is a proxy for [`Choice`], but uses `u8` instead to permit `const` - /// constructors for `IDENTITY` and `GENERATOR`. - pub infinity: u8, -} - -impl AffinePoint { - /// Base point of P-384. - /// - /// Defined in FIPS 186-4 § D.1.2.4: - /// - /// ```text - /// Gₓ = aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 - /// 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7 - /// Gᵧ = 3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c - /// e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f - /// ``` - /// - /// NOTE: coordinate field elements have been translated into the Montgomery - /// domain. - pub const GENERATOR: Self = Self { - x: FieldElement::from_be_hex("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"), - y: FieldElement::from_be_hex("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"), - infinity: 0, - }; - - /// Additive identity of the group: the point at infinity. - pub const IDENTITY: Self = Self { - x: FieldElement::ZERO, - y: FieldElement::ZERO, - infinity: 1, - }; -} - -impl PrimeCurveAffine for AffinePoint { - type Curve = ProjectivePoint; - type Scalar = Scalar; - - fn identity() -> AffinePoint { - Self::IDENTITY - } - - fn generator() -> AffinePoint { - Self::GENERATOR - } - - fn is_identity(&self) -> Choice { - Choice::from(self.infinity) - } - - fn to_curve(&self) -> ProjectivePoint { - ProjectivePoint::from(*self) - } -} - -impl AffineXCoordinate for AffinePoint { - fn x(&self) -> FieldBytes { - self.x.to_sec1() - } -} - -impl ConditionallySelectable for AffinePoint { - fn conditional_select(a: &AffinePoint, b: &AffinePoint, choice: Choice) -> AffinePoint { - AffinePoint { - x: FieldElement::conditional_select(&a.x, &b.x, choice), - y: FieldElement::conditional_select(&a.y, &b.y, choice), - infinity: u8::conditional_select(&a.infinity, &b.infinity, choice), - } - } -} - -impl ConstantTimeEq for AffinePoint { - fn ct_eq(&self, other: &AffinePoint) -> Choice { - self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y) & self.infinity.ct_eq(&other.infinity) - } -} - -impl Default for AffinePoint { - fn default() -> Self { - Self::IDENTITY - } -} - -impl DefaultIsZeroes for AffinePoint {} - -impl Eq for AffinePoint {} - -impl PartialEq for AffinePoint { - fn eq(&self, other: &AffinePoint) -> bool { - self.ct_eq(other).into() - } -} - -impl Mul for AffinePoint { - type Output = ProjectivePoint; - - fn mul(self, scalar: Scalar) -> ProjectivePoint { - ProjectivePoint::from(self) * scalar - } -} - -impl Mul<&Scalar> for AffinePoint { - type Output = ProjectivePoint; - - fn mul(self, scalar: &Scalar) -> ProjectivePoint { - ProjectivePoint::from(self) * scalar - } -} - -impl Neg for AffinePoint { - type Output = AffinePoint; - - fn neg(self) -> Self::Output { - AffinePoint { - x: self.x, - y: -self.y, - infinity: self.infinity, - } - } -} - -impl DecompressPoint for AffinePoint { - fn decompress(x_bytes: &FieldBytes, y_is_odd: Choice) -> CtOption { - FieldElement::from_sec1(*x_bytes).and_then(|x| { - let alpha = x * &x * &x + &(CURVE_EQUATION_A * &x) + &CURVE_EQUATION_B; - let beta = alpha.sqrt(); - - beta.map(|beta| { - let y = FieldElement::conditional_select( - &(FieldElement(MODULUS) - &beta), - &beta, - beta.is_odd().ct_eq(&y_is_odd), - ); - - Self { x, y, infinity: 0 } - }) - }) - } -} - -impl GroupEncoding for AffinePoint { - type Repr = CompressedPoint; - - /// NOTE: not constant-time with respect to identity point - fn from_bytes(bytes: &Self::Repr) -> CtOption { - EncodedPoint::from_bytes(bytes) - .map(|point| CtOption::new(point, Choice::from(1))) - .unwrap_or_else(|_| { - // SEC1 identity encoding is technically 1-byte 0x00, but the - // `GroupEncoding` API requires a fixed-width `Repr` - let is_identity = bytes.ct_eq(&Self::Repr::default()); - CtOption::new(EncodedPoint::identity(), is_identity) - }) - .and_then(|point| Self::from_encoded_point(&point)) - } - - fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { - // No unchecked conversion possible for compressed points - Self::from_bytes(bytes) - } - - fn to_bytes(&self) -> Self::Repr { - let encoded = self.to_encoded_point(true); - let mut result = CompressedPoint::default(); - result[..encoded.len()].copy_from_slice(encoded.as_bytes()); - result - } -} - -impl FromEncodedPoint for AffinePoint { - /// Attempts to parse the given [`EncodedPoint`] as an SEC1-encoded - /// [`AffinePoint`]. - /// - /// # Returns - /// - /// `None` value if `encoded_point` is not on the secp384r1 curve. - fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption { - match encoded_point.coordinates() { - sec1::Coordinates::Identity => CtOption::new(Self::identity(), 1.into()), - // TODO(tarcieri): point decompaction support - sec1::Coordinates::Compact { .. } => CtOption::new(AffinePoint::IDENTITY, 0.into()), - sec1::Coordinates::Compressed { x, y_is_odd } => { - AffinePoint::decompress(x, Choice::from(y_is_odd as u8)) - } - sec1::Coordinates::Uncompressed { x, y } => { - let x = FieldElement::from_sec1(*x); - let y = FieldElement::from_sec1(*y); - - x.and_then(|x| { - y.and_then(|y| { - // Check that the point is on the curve - let lhs = y * &y; - let rhs = x * &x * &x + &(CURVE_EQUATION_A * &x) + &CURVE_EQUATION_B; - let point = AffinePoint { x, y, infinity: 0 }; - CtOption::new(point, lhs.ct_eq(&rhs)) - }) - }) - } - } - } -} - -impl ToEncodedPoint for AffinePoint { - fn to_encoded_point(&self, compress: bool) -> EncodedPoint { - EncodedPoint::conditional_select( - &EncodedPoint::from_affine_coordinates(&self.x.to_sec1(), &self.y.to_sec1(), compress), - &EncodedPoint::identity(), - self.is_identity(), - ) - } -} - -impl TryFrom for AffinePoint { - type Error = Error; - - fn try_from(point: EncodedPoint) -> Result { - AffinePoint::try_from(&point) - } -} - -impl TryFrom<&EncodedPoint> for AffinePoint { - type Error = Error; - - fn try_from(point: &EncodedPoint) -> Result { - Option::from(AffinePoint::from_encoded_point(point)).ok_or(Error) - } -} - -impl From for EncodedPoint { - fn from(affine_point: AffinePoint) -> EncodedPoint { - affine_point.to_encoded_point(false) - } -} - -impl From for AffinePoint { - fn from(public_key: PublicKey) -> AffinePoint { - *public_key.as_affine() - } -} - -impl From<&PublicKey> for AffinePoint { - fn from(public_key: &PublicKey) -> AffinePoint { - AffinePoint::from(*public_key) - } -} - -impl TryFrom for PublicKey { - type Error = Error; - - fn try_from(affine_point: AffinePoint) -> Result { - PublicKey::from_affine(affine_point) - } -} - -impl TryFrom<&AffinePoint> for PublicKey { - type Error = Error; - - fn try_from(affine_point: &AffinePoint) -> Result { - PublicKey::try_from(*affine_point) - } -} - -#[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] -impl Serialize for AffinePoint { - fn serialize(&self, serializer: S) -> core::result::Result - where - S: ser::Serializer, - { - self.to_encoded_point(true).serialize(serializer) - } -} - -#[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] -impl<'de> Deserialize<'de> for AffinePoint { - fn deserialize(deserializer: D) -> core::result::Result - where - D: de::Deserializer<'de>, - { - EncodedPoint::deserialize(deserializer)? - .try_into() - .map_err(de::Error::custom) - } -} - -#[cfg(test)] -mod tests { - use elliptic_curve::{ - group::{prime::PrimeCurveAffine, GroupEncoding}, - sec1::{FromEncodedPoint, ToEncodedPoint}, - }; - use hex_literal::hex; - - use super::AffinePoint; - use crate::EncodedPoint; - - const UNCOMPRESSED_BASEPOINT: &[u8] = &hex!( - "04 aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 - 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7 - 3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c - e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f" - ); - - const COMPRESSED_BASEPOINT: &[u8] = &hex!( - "03 aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 - 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7" - ); - - #[test] - fn uncompressed_round_trip() { - let pubkey = EncodedPoint::from_bytes(UNCOMPRESSED_BASEPOINT).unwrap(); - let point = AffinePoint::from_encoded_point(&pubkey).unwrap(); - assert_eq!(point, AffinePoint::generator()); - - let res: EncodedPoint = point.into(); - assert_eq!(res, pubkey); - } - - #[test] - fn compressed_round_trip() { - let pubkey = EncodedPoint::from_bytes(COMPRESSED_BASEPOINT).unwrap(); - let point = AffinePoint::from_encoded_point(&pubkey).unwrap(); - assert_eq!(point, AffinePoint::generator()); - - let res: EncodedPoint = point.to_encoded_point(true); - assert_eq!(res, pubkey); - } - - #[test] - fn uncompressed_to_compressed() { - let encoded = EncodedPoint::from_bytes(UNCOMPRESSED_BASEPOINT).unwrap(); - - let res = AffinePoint::from_encoded_point(&encoded) - .unwrap() - .to_encoded_point(true); - - assert_eq!(res.as_bytes(), COMPRESSED_BASEPOINT); - } - - #[test] - fn compressed_to_uncompressed() { - let encoded = EncodedPoint::from_bytes(COMPRESSED_BASEPOINT).unwrap(); - - let res = AffinePoint::from_encoded_point(&encoded) - .unwrap() - .to_encoded_point(false); - - assert_eq!(res.as_bytes(), UNCOMPRESSED_BASEPOINT); - } - - #[test] - fn affine_negation() { - let basepoint = AffinePoint::generator(); - assert_eq!(-(-basepoint), basepoint); - } - - #[test] - fn identity_encoding() { - // This is technically an invalid SEC1 encoding, but is preferable to panicking. - assert_eq!([0; 49], AffinePoint::IDENTITY.to_bytes().as_slice()); - assert!(bool::from( - AffinePoint::from_bytes(&AffinePoint::IDENTITY.to_bytes()) - .unwrap() - .is_identity() - )) - } -} diff --git a/vendor/p384/src/arithmetic/field.rs b/vendor/p384/src/arithmetic/field.rs index 858bac927..355e88df1 100644 --- a/vendor/p384/src/arithmetic/field.rs +++ b/vendor/p384/src/arithmetic/field.rs @@ -25,22 +25,27 @@ mod field_impl; use self::field_impl::*; -use crate::FieldBytes; -use core::ops::{AddAssign, MulAssign, Neg, SubAssign}; +use crate::{FieldBytes, NistP384}; +use core::{ + iter::{Product, Sum}, + ops::{AddAssign, MulAssign, Neg, SubAssign}, +}; use elliptic_curve::{ - bigint::{self, Encoding, Limb, U384}, + bigint::{self, Limb, U384}, + ff::PrimeField, subtle::{Choice, ConstantTimeEq, CtOption}, }; /// Constant representing the modulus /// p = 2^{384} − 2^{128} − 2^{96} + 2^{32} − 1 -pub(crate) const MODULUS: U384 = U384::from_be_hex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"); +pub(crate) const MODULUS: U384 = U384::from_be_hex(FieldElement::MODULUS); /// Element of the secp384r1 base field used for curve coordinates. #[derive(Clone, Copy, Debug)] pub struct FieldElement(pub(super) U384); -elliptic_curve::impl_field_element!( +primeorder::impl_mont_field_element!( + NistP384, FieldElement, FieldBytes, U384, @@ -56,26 +61,20 @@ elliptic_curve::impl_field_element!( ); impl FieldElement { - /// Parse the given byte array as an SEC1-encoded field element. - /// - /// Returns `None` if the byte array does not contain a big-endian integer in - /// the range `[0, p)`. - pub fn from_sec1(bytes: FieldBytes) -> CtOption { - Self::from_be_bytes(bytes) - } - - /// Returns the SEC1 encoding of this field element. - pub fn to_sec1(self) -> FieldBytes { - self.to_be_bytes() - } - /// Compute [`FieldElement`] inversion: `1 / self`. pub fn invert(&self) -> CtOption { - let ret = impl_field_invert!( - self.to_canonical().to_words(), + CtOption::new(self.invert_unchecked(), !self.is_zero()) + } + + /// Returns the multiplicative inverse of self. + /// + /// Does not check that self is non-zero. + const fn invert_unchecked(&self) -> Self { + let words = impl_field_invert!( + self.to_canonical().as_words(), Self::ONE.0.to_words(), - Limb::BIT_SIZE, - bigint::nlimbs!(U384::BIT_SIZE), + Limb::BITS, + bigint::nlimbs!(U384::BITS), fiat_p384_mul, fiat_p384_opp, fiat_p384_divstep_precomp, @@ -83,7 +82,8 @@ impl FieldElement { fiat_p384_msat, fiat_p384_selectznz, ); - CtOption::new(Self(ret.into()), !self.is_zero()) + + Self(U384::from_words(words)) } /// Returns the square root of self mod p, or `None` if no square root @@ -122,9 +122,52 @@ impl FieldElement { } } +impl PrimeField for FieldElement { + type Repr = FieldBytes; + + const MODULUS: &'static str = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"; + const NUM_BITS: u32 = 384; + const CAPACITY: u32 = 383; + const TWO_INV: Self = Self::from_u64(2).invert_unchecked(); + const MULTIPLICATIVE_GENERATOR: Self = Self::from_u64(19); + const S: u32 = 1; + const ROOT_OF_UNITY: Self = Self::from_hex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffe"); + const ROOT_OF_UNITY_INV: Self = Self::ROOT_OF_UNITY.invert_unchecked(); + const DELTA: Self = Self::from_u64(49); + + #[inline] + fn from_repr(bytes: FieldBytes) -> CtOption { + Self::from_bytes(&bytes) + } + + #[inline] + fn to_repr(&self) -> FieldBytes { + self.to_bytes() + } + + #[inline] + fn is_odd(&self) -> Choice { + self.is_odd() + } +} + #[cfg(test)] mod tests { use super::FieldElement; + use elliptic_curve::ff::PrimeField; + use primeorder::impl_primefield_tests; + + /// t = (modulus - 1) >> S + const T: [u64; 6] = [ + 0x000000007fffffff, + 0x7fffffff80000000, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0x7fffffffffffffff, + ]; + + impl_primefield_tests!(FieldElement, T); /// Basic tests that field inversion works. #[test] diff --git a/vendor/p384/src/arithmetic/hash2curve.rs b/vendor/p384/src/arithmetic/hash2curve.rs new file mode 100644 index 000000000..5f3efcaa9 --- /dev/null +++ b/vendor/p384/src/arithmetic/hash2curve.rs @@ -0,0 +1,326 @@ +use super::FieldElement; +use crate::{AffinePoint, FieldBytes, NistP384, ProjectivePoint, Scalar}; +use elliptic_curve::{ + bigint::{ArrayEncoding, U384}, + consts::U72, + generic_array::GenericArray, + hash2curve::{FromOkm, GroupDigest, MapToCurve, OsswuMap, OsswuMapParams, Sgn0}, + ops::Reduce, + point::DecompressPoint, + subtle::Choice, +}; + +impl GroupDigest for NistP384 { + type FieldElement = FieldElement; +} + +impl FromOkm for FieldElement { + type Length = U72; + + fn from_okm(data: &GenericArray) -> Self { + const F_2_288: FieldElement = FieldElement::from_hex( + "000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000", + ); + + let mut d0 = FieldBytes::default(); + d0[12..].copy_from_slice(&data[0..36]); + let d0 = FieldElement::from_uint_unchecked(U384::from_be_byte_array(d0)); + + let mut d1 = FieldBytes::default(); + d1[12..].copy_from_slice(&data[36..]); + let d1 = FieldElement::from_uint_unchecked(U384::from_be_byte_array(d1)); + + d0 * F_2_288 + d1 + } +} + +impl Sgn0 for FieldElement { + fn sgn0(&self) -> Choice { + self.is_odd() + } +} + +impl OsswuMap for FieldElement { + const PARAMS: OsswuMapParams = OsswuMapParams { + c1: &[ + 0x0000_0000_3fff_ffff, + 0xbfff_ffff_c000_0000, + 0xffff_ffff_ffff_ffff, + 0xffff_ffff_ffff_ffff, + 0xffff_ffff_ffff_ffff, + 0x3fff_ffff_ffff_ffff, + ], + c2: FieldElement::from_hex( + "019877cc1041b7555743c0ae2e3a3e61fb2aaa2e0e87ea557a563d8b598a0940d0a697a9e0b9e92cfaa314f583c9d066", + ), + map_a: FieldElement::from_hex( + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc", + ), + map_b: FieldElement::from_hex( + "b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", + ), + z: FieldElement::from_hex( + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffff3", + ), + }; +} + +impl MapToCurve for FieldElement { + type Output = ProjectivePoint; + + fn map_to_curve(&self) -> Self::Output { + let (qx, qy) = self.osswu(); + + // TODO(tarcieri): assert that `qy` is correct? less circuitous conversion? + AffinePoint::decompress(&qx.to_bytes(), qy.is_odd()) + .unwrap() + .into() + } +} + +impl FromOkm for Scalar { + type Length = U72; + + fn from_okm(data: &GenericArray) -> Self { + const F_2_288: Scalar = Scalar::from_hex( + "000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000", + ); + + let mut d0 = FieldBytes::default(); + d0[12..].copy_from_slice(&data[0..36]); + let d0 = Scalar::reduce(U384::from_be_byte_array(d0)); + + let mut d1 = FieldBytes::default(); + d1[12..].copy_from_slice(&data[36..]); + let d1 = Scalar::reduce(U384::from_be_byte_array(d1)); + + d0 * F_2_288 + d1 + } +} + +#[cfg(test)] +mod tests { + use crate::{FieldElement, NistP384, Scalar}; + use elliptic_curve::{ + bigint::{ArrayEncoding, NonZero, U384, U576}, + consts::U72, + generic_array::GenericArray, + group::cofactor::CofactorGroup, + hash2curve::{self, ExpandMsgXmd, FromOkm, GroupDigest, MapToCurve}, + ops::Reduce, + sec1::{self, ToEncodedPoint}, + Curve, + }; + use hex_literal::hex; + use proptest::{num::u64::ANY, prelude::ProptestConfig, proptest}; + use sha2::Sha384; + + #[test] + fn hash_to_curve() { + struct TestVector { + msg: &'static [u8], + p_x: [u8; 48], + p_y: [u8; 48], + u_0: [u8; 48], + u_1: [u8; 48], + q0_x: [u8; 48], + q0_y: [u8; 48], + q1_x: [u8; 48], + q1_y: [u8; 48], + } + + const DST: &[u8] = b"QUUX-V01-CS02-with-P384_XMD:SHA-384_SSWU_RO_"; + + const TEST_VECTORS: &[TestVector] = &[ + TestVector { + msg: b"", + p_x: hex!("eb9fe1b4f4e14e7140803c1d99d0a93cd823d2b024040f9c067a8eca1f5a2eeac9ad604973527a356f3fa3aeff0e4d83"), + p_y: hex!("0c21708cff382b7f4643c07b105c2eaec2cead93a917d825601e63c8f21f6abd9abc22c93c2bed6f235954b25048bb1a"), + u_0: hex!("25c8d7dc1acd4ee617766693f7f8829396065d1b447eedb155871feffd9c6653279ac7e5c46edb7010a0e4ff64c9f3b4"), + u_1: hex!("59428be4ed69131df59a0c6a8e188d2d4ece3f1b2a3a02602962b47efa4d7905945b1e2cc80b36aa35c99451073521ac"), + q0_x: hex!("e4717e29eef38d862bee4902a7d21b44efb58c464e3e1f0d03894d94de310f8ffc6de86786dd3e15a1541b18d4eb2846"), + q0_y: hex!("6b95a6e639822312298a47526bb77d9cd7bcf76244c991c8cd70075e2ee6e8b9a135c4a37e3c0768c7ca871c0ceb53d4"), + q1_x: hex!("509527cfc0750eedc53147e6d5f78596c8a3b7360e0608e2fab0563a1670d58d8ae107c9f04bcf90e89489ace5650efd"), + q1_y: hex!("33337b13cb35e173fdea4cb9e8cce915d836ff57803dbbeb7998aa49d17df2ff09b67031773039d09fbd9305a1566bc4"), + }, + TestVector { + msg: b"abc", + p_x: hex!("e02fc1a5f44a7519419dd314e29863f30df55a514da2d655775a81d413003c4d4e7fd59af0826dfaad4200ac6f60abe1"), + p_y: hex!("01f638d04d98677d65bef99aef1a12a70a4cbb9270ec55248c04530d8bc1f8f90f8a6a859a7c1f1ddccedf8f96d675f6"), + u_0: hex!("53350214cb6bef0b51abb791b1c4209a2b4c16a0c67e1ab1401017fad774cd3b3f9a8bcdf7f6229dd8dd5a075cb149a0"), + u_1: hex!("c0473083898f63e03f26f14877a2407bd60c75ad491e7d26cbc6cc5ce815654075ec6b6898c7a41d74ceaf720a10c02e"), + q0_x: hex!("fc853b69437aee9a19d5acf96a4ee4c5e04cf7b53406dfaa2afbdd7ad2351b7f554e4bbc6f5db4177d4d44f933a8f6ee"), + q0_y: hex!("7e042547e01834c9043b10f3a8221c4a879cb156f04f72bfccab0c047a304e30f2aa8b2e260d34c4592c0c33dd0c6482"), + q1_x: hex!("57912293709b3556b43a2dfb137a315d256d573b82ded120ef8c782d607c05d930d958e50cb6dc1cc480b9afc38c45f1"), + q1_y: hex!("de9387dab0eef0bda219c6f168a92645a84665c4f2137c14270fb424b7532ff84843c3da383ceea24c47fa343c227bb8"), + }, + TestVector { + msg: b"abcdef0123456789", + p_x: hex!("bdecc1c1d870624965f19505be50459d363c71a699a496ab672f9a5d6b78676400926fbceee6fcd1780fe86e62b2aa89"), + p_y: hex!("57cf1f99b5ee00f3c201139b3bfe4dd30a653193778d89a0accc5e0f47e46e4e4b85a0595da29c9494c1814acafe183c"), + u_0: hex!("aab7fb87238cf6b2ab56cdcca7e028959bb2ea599d34f68484139dde85ec6548a6e48771d17956421bdb7790598ea52e"), + u_1: hex!("26e8d833552d7844d167833ca5a87c35bcfaa5a0d86023479fb28e5cd6075c18b168bf1f5d2a0ea146d057971336d8d1"), + q0_x: hex!("0ceece45b73f89844671df962ad2932122e878ad2259e650626924e4e7f132589341dec1480ebcbbbe3509d11fb570b7"), + q0_y: hex!("fafd71a3115298f6be4ae5c6dfc96c400cfb55760f185b7b03f3fa45f3f91eb65d27628b3c705cafd0466fafa54883ce"), + q1_x: hex!("dea1be8d3f9be4cbf4fab9d71d549dde76875b5d9b876832313a083ec81e528cbc2a0a1d0596b3bcb0ba77866b129776"), + q1_y: hex!("eb15fe71662214fb03b65541f40d3eb0f4cf5c3b559f647da138c9f9b7484c48a08760e02c16f1992762cb7298fa52cf"), + }, + TestVector { + msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + p_x: hex!("03c3a9f401b78c6c36a52f07eeee0ec1289f178adf78448f43a3850e0456f5dd7f7633dd31676d990eda32882ab486c0"), + p_y: hex!("cc183d0d7bdfd0a3af05f50e16a3f2de4abbc523215bf57c848d5ea662482b8c1f43dc453a93b94a8026db58f3f5d878"), + u_0: hex!("04c00051b0de6e726d228c85bf243bf5f4789efb512b22b498cde3821db9da667199b74bd5a09a79583c6d353a3bb41c"), + u_1: hex!("97580f218255f899f9204db64cd15e6a312cb4d8182375d1e5157c8f80f41d6a1a4b77fb1ded9dce56c32058b8d5202b"), + q0_x: hex!("051a22105e0817a35d66196338c8d85bd52690d79bba373ead8a86dd9899411513bb9f75273f6483395a7847fb21edb4"), + q0_y: hex!("f168295c1bbcff5f8b01248e9dbc885335d6d6a04aea960f7384f746ba6502ce477e624151cc1d1392b00df0f5400c06"), + q1_x: hex!("6ad7bc8ed8b841efd8ad0765c8a23d0b968ec9aa360a558ff33500f164faa02bee6c704f5f91507c4c5aad2b0dc5b943"), + q1_y: hex!("47313cc0a873ade774048338fc34ca5313f96bbf6ae22ac6ef475d85f03d24792dc6afba8d0b4a70170c1b4f0f716629"), + }, + TestVector { + msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + p_x: hex!("7b18d210b1f090ac701f65f606f6ca18fb8d081e3bc6cbd937c5604325f1cdea4c15c10a54ef303aabf2ea58bd9947a4"), + p_y: hex!("ea857285a33abb516732915c353c75c576bf82ccc96adb63c094dde580021eddeafd91f8c0bfee6f636528f3d0c47fd2"), + u_0: hex!("480cb3ac2c389db7f9dac9c396d2647ae946db844598971c26d1afd53912a1491199c0a5902811e4b809c26fcd37a014"), + u_1: hex!("d28435eb34680e148bf3908536e42231cba9e1f73ae2c6902a222a89db5c49c97db2f8fa4d4cd6e424b17ac60bdb9bb6"), + q0_x: hex!("42e6666f505e854187186bad3011598d9278b9d6e3e4d2503c3d236381a56748dec5d139c223129b324df53fa147c4df"), + q0_y: hex!("8ee51dbda46413bf621838cc935d18d617881c6f33f3838a79c767a1e5618e34b22f79142df708d2432f75c7366c8512"), + q1_x: hex!("4ff01ceeba60484fa1bc0d825fe1e5e383d8f79f1e5bb78e5fb26b7a7ef758153e31e78b9d60ce75c5e32e43869d4e12"), + q1_y: hex!("0f84b978fac8ceda7304b47e229d6037d32062e597dc7a9b95bcd9af441f3c56c619a901d21635f9ec6ab4710b9fcd0e"), + }, + ]; + + for test_vector in TEST_VECTORS { + // in parts + let mut u = [FieldElement::default(), FieldElement::default()]; + hash2curve::hash_to_field::, FieldElement>( + &[test_vector.msg], + &[DST], + &mut u, + ) + .unwrap(); + + /// Assert that the provided projective point matches the given test vector. + // TODO(tarcieri): use coordinate APIs. See zkcrypto/group#30 + macro_rules! assert_point_eq { + ($actual:expr, $expected_x:expr, $expected_y:expr) => { + let point = $actual.to_affine().to_encoded_point(false); + let (actual_x, actual_y) = match point.coordinates() { + sec1::Coordinates::Uncompressed { x, y } => (x, y), + _ => unreachable!(), + }; + + assert_eq!(&$expected_x, actual_x.as_slice()); + assert_eq!(&$expected_y, actual_y.as_slice()); + }; + } + + assert_eq!(u[0].to_bytes().as_slice(), test_vector.u_0); + assert_eq!(u[1].to_bytes().as_slice(), test_vector.u_1); + + let q0 = u[0].map_to_curve(); + assert_point_eq!(q0, test_vector.q0_x, test_vector.q0_y); + + let q1 = u[1].map_to_curve(); + assert_point_eq!(q1, test_vector.q1_x, test_vector.q1_y); + + let p = q0.clear_cofactor() + q1.clear_cofactor(); + assert_point_eq!(p, test_vector.p_x, test_vector.p_y); + + // complete run + let pt = NistP384::hash_from_bytes::>(&[test_vector.msg], &[DST]) + .unwrap(); + assert_point_eq!(pt, test_vector.p_x, test_vector.p_y); + } + } + + /// Taken from . + #[test] + fn hash_to_scalar_voprf() { + struct TestVector { + dst: &'static [u8], + key_info: &'static [u8], + seed: &'static [u8], + sk_sm: &'static [u8], + } + + const TEST_VECTORS: &[TestVector] = &[ + TestVector { + dst: b"DeriveKeyPairVOPRF10-\x00\x00\x04", + key_info: b"test key", + seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"), + sk_sm: &hex!("c0503759ddd1e31d8c7eae9304c9b1c16f83d1f6d962e3e7b789cd85fd581800e96c5c4256131aafcff9a76919abbd55"), + }, + TestVector { + dst: b"DeriveKeyPairVOPRF10-\x01\x00\x04", + key_info: b"test key", + seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"), + sk_sm: &hex!("514fb6fe2e66af1383840759d56f71730331280f062930ee2a2f7ea42f935acf94087355699d788abfdf09d19a5c85ac"), + }, + TestVector { + dst: b"DeriveKeyPairVOPRF10-\x02\x00\x04", + key_info: b"test key", + seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"), + sk_sm: &hex!("0fcba4a204f67d6c13f780e613915f755319aaa3cb03cd20a5a4a6c403a4812a4fff5d3223e2c309aa66b05cb7611fd4"), + }, + ]; + + 'outer: for test_vector in TEST_VECTORS { + let key_info_len = u16::try_from(test_vector.key_info.len()) + .unwrap() + .to_be_bytes(); + + for counter in 0_u8..=u8::MAX { + let scalar = NistP384::hash_to_scalar::>( + &[ + test_vector.seed, + &key_info_len, + test_vector.key_info, + &counter.to_be_bytes(), + ], + &[test_vector.dst], + ) + .unwrap(); + + if !bool::from(scalar.is_zero()) { + assert_eq!(scalar.to_bytes().as_slice(), test_vector.sk_sm); + continue 'outer; + } + } + + panic!("deriving key failed"); + } + } + + #[test] + fn from_okm_fuzz() { + let mut wide_order = GenericArray::default(); + wide_order[24..].copy_from_slice(&NistP384::ORDER.to_be_byte_array()); + let wide_order = NonZero::new(U576::from_be_byte_array(wide_order)).unwrap(); + + let simple_from_okm = move |data: GenericArray| -> Scalar { + let data = U576::from_be_slice(&data); + + let scalar = data % wide_order; + let reduced_scalar = U384::from_be_slice(&scalar.to_be_byte_array()[24..]); + + Scalar::reduce(reduced_scalar) + }; + + proptest!(ProptestConfig::with_cases(1000), |(b0 in ANY, b1 in ANY, b2 in ANY, b3 in ANY, b4 in ANY, b5 in ANY, b6 in ANY, b7 in ANY, b8 in ANY)| { + let mut data = GenericArray::default(); + data[..8].copy_from_slice(&b0.to_be_bytes()); + data[8..16].copy_from_slice(&b1.to_be_bytes()); + data[16..24].copy_from_slice(&b2.to_be_bytes()); + data[24..32].copy_from_slice(&b3.to_be_bytes()); + data[32..40].copy_from_slice(&b4.to_be_bytes()); + data[40..48].copy_from_slice(&b5.to_be_bytes()); + data[48..56].copy_from_slice(&b6.to_be_bytes()); + data[56..64].copy_from_slice(&b7.to_be_bytes()); + data[64..].copy_from_slice(&b8.to_be_bytes()); + + let from_okm = Scalar::from_okm(&data); + let simple_from_okm = simple_from_okm(data); + assert_eq!(from_okm, simple_from_okm); + }); + } +} diff --git a/vendor/p384/src/arithmetic/macros.rs b/vendor/p384/src/arithmetic/macros.rs index 62789f245..88c4629e8 100644 --- a/vendor/p384/src/arithmetic/macros.rs +++ b/vendor/p384/src/arithmetic/macros.rs @@ -17,11 +17,15 @@ macro_rules! impl_field_invert { let mut d = 1; let mut f = $msat(); let mut g = [0; $nlimbs + 1]; - let mut v = Default::default(); + let mut v = [0; $nlimbs]; let mut r = $one; let mut i = 0; + let mut j = 0; - g[..$nlimbs].copy_from_slice($a.as_ref()); + while j < $nlimbs { + g[j] = $a[j]; + j += 1; + } while i < ITERATIONS - ITERATIONS % 2 { let (out1, out2, out3, out4, out5) = $divstep(d, &f, &g, &v, &r); diff --git a/vendor/p384/src/arithmetic/projective.rs b/vendor/p384/src/arithmetic/projective.rs deleted file mode 100644 index 2da22232d..000000000 --- a/vendor/p384/src/arithmetic/projective.rs +++ /dev/null @@ -1,673 +0,0 @@ -//! Projective points - -#![allow(clippy::needless_range_loop, clippy::op_ref)] - -use core::{ - iter::Sum, - ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, -}; - -use elliptic_curve::{ - group::{ - ff::Field, - prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup}, - Curve, Group, GroupEncoding, - }, - ops::LinearCombination, - rand_core::RngCore, - sec1::{FromEncodedPoint, ToEncodedPoint}, - subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, - weierstrass, - zeroize::DefaultIsZeroes, - Error, PrimeCurveArithmetic, ProjectiveArithmetic, Result, -}; - -use super::{AffinePoint, FieldElement, Scalar, CURVE_EQUATION_B}; -use crate::{CompressedPoint, EncodedPoint, NistP384, PublicKey}; - -impl ProjectiveArithmetic for NistP384 { - type ProjectivePoint = ProjectivePoint; -} - -impl PrimeCurveArithmetic for NistP384 { - type CurveGroup = ProjectivePoint; -} - -/// A point on the secp384r1 curve in projective coordinates. -#[derive(Clone, Copy, Debug)] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub struct ProjectivePoint { - x: FieldElement, - y: FieldElement, - z: FieldElement, -} - -impl ProjectivePoint { - /// Base point of P-384. - pub const GENERATOR: Self = Self { - x: AffinePoint::GENERATOR.x, - y: AffinePoint::GENERATOR.y, - z: FieldElement::ONE, - }; - /// Additive identity of the group: the point at infinity. - pub const IDENTITY: Self = Self { - x: FieldElement::ZERO, - y: FieldElement::ONE, - z: FieldElement::ZERO, - }; - - /// Returns the additive identity of P-384, also known as the "neutral - /// element" or "point at infinity". - #[deprecated(since = "0.10.1", note = "use `ProjectivePoint::IDENTITY` instead")] - pub const fn identity() -> ProjectivePoint { - Self::IDENTITY - } - - /// Returns the base point of P-384. - #[deprecated(since = "0.10.1", note = "use `ProjectivePoint::GENERATOR` instead")] - pub fn generator() -> ProjectivePoint { - Self::GENERATOR - } - - /// Returns the affine representation of this point, or `None` if it is the - /// identity. - pub fn to_affine(&self) -> AffinePoint { - self.z - .invert() - .map(|zinv| AffinePoint { - x: self.x * &zinv, - y: self.y * &zinv, - infinity: 0, - }) - .unwrap_or(AffinePoint::IDENTITY) - } - - /// Returns `-self`. - fn neg(&self) -> ProjectivePoint { - ProjectivePoint { - x: self.x, - y: self.y.neg(), - z: self.z, - } - } - - /// Returns `self + other`. - fn add(&self, other: &ProjectivePoint) -> ProjectivePoint { - weierstrass::add( - (self.x, self.y, self.z), - (other.x, other.y, other.z), - CURVE_EQUATION_B, - ) - .into() - } - - /// Returns `self + other`. - fn add_mixed(&self, other: &AffinePoint) -> ProjectivePoint { - let ret = Self::from(weierstrass::add_mixed( - (self.x, self.y, self.z), - (other.x, other.y), - CURVE_EQUATION_B, - )); - - Self::conditional_select(&ret, self, other.is_identity()) - } - - /// Doubles this point. - pub fn double(&self) -> ProjectivePoint { - weierstrass::double((self.x, self.y, self.z), CURVE_EQUATION_B).into() - } - - /// Returns `self - other`. - fn sub(&self, other: &ProjectivePoint) -> ProjectivePoint { - self.add(&other.neg()) - } - - /// Returns `self - other`. - fn sub_mixed(&self, other: &AffinePoint) -> ProjectivePoint { - self.add_mixed(&other.neg()) - } - - /// Returns `[k] self`. - fn mul(&self, k: &Scalar) -> ProjectivePoint { - let mut pc = [ProjectivePoint::default(); 16]; - pc[0] = ProjectivePoint::IDENTITY; - pc[1] = *self; - for i in 2..16 { - pc[i] = if i % 2 == 0 { - pc[i / 2].double() - } else { - pc[i - 1].add(self) - }; - } - let mut q = ProjectivePoint::IDENTITY; - let k = k.to_le_bytes(); - let mut pos = 384 - 4; - loop { - let slot = (k[(pos >> 3) as usize] >> (pos & 7)) & 0xf; - let mut t = ProjectivePoint::IDENTITY; - for i in 1..16 { - t.conditional_assign( - &pc[i], - Choice::from(((slot as usize ^ i).wrapping_sub(1) >> 8) as u8 & 1), - ); - } - q = q.add(&t); - if pos == 0 { - break; - } - q = q.double().double().double().double(); - pos -= 4; - } - q - } -} - -impl Group for ProjectivePoint { - type Scalar = Scalar; - - fn random(mut rng: impl RngCore) -> Self { - Self::GENERATOR * Scalar::random(&mut rng) - } - - fn identity() -> Self { - Self::IDENTITY - } - - fn generator() -> Self { - Self::GENERATOR - } - - fn is_identity(&self) -> Choice { - self.ct_eq(&Self::IDENTITY) - } - - #[must_use] - fn double(&self) -> Self { - ProjectivePoint::double(self) - } -} - -impl GroupEncoding for ProjectivePoint { - type Repr = CompressedPoint; - - fn from_bytes(bytes: &Self::Repr) -> CtOption { - ::from_bytes(bytes).map(Into::into) - } - - fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { - // No unchecked conversion possible for compressed points - Self::from_bytes(bytes) - } - - fn to_bytes(&self) -> Self::Repr { - self.to_affine().to_bytes() - } -} - -impl PrimeGroup for ProjectivePoint {} - -impl Curve for ProjectivePoint { - type AffineRepr = AffinePoint; - - fn to_affine(&self) -> AffinePoint { - ProjectivePoint::to_affine(self) - } -} - -impl PrimeCurve for ProjectivePoint { - type Affine = AffinePoint; -} - -impl LinearCombination for ProjectivePoint {} - -impl From for ProjectivePoint { - fn from(p: AffinePoint) -> Self { - let projective = ProjectivePoint { - x: p.x, - y: p.y, - z: FieldElement::ONE, - }; - Self::conditional_select(&projective, &Self::IDENTITY, p.is_identity()) - } -} - -impl From<&AffinePoint> for ProjectivePoint { - fn from(p: &AffinePoint) -> Self { - Self::from(*p) - } -} - -impl From for AffinePoint { - fn from(p: ProjectivePoint) -> AffinePoint { - p.to_affine() - } -} - -impl From<&ProjectivePoint> for AffinePoint { - fn from(p: &ProjectivePoint) -> AffinePoint { - p.to_affine() - } -} - -impl From> for ProjectivePoint { - #[inline] - fn from((x, y, z): weierstrass::ProjectivePoint) -> ProjectivePoint { - Self { x, y, z } - } -} - -impl FromEncodedPoint for ProjectivePoint { - fn from_encoded_point(p: &EncodedPoint) -> CtOption { - AffinePoint::from_encoded_point(p).map(ProjectivePoint::from) - } -} - -impl ToEncodedPoint for ProjectivePoint { - fn to_encoded_point(&self, compress: bool) -> EncodedPoint { - self.to_affine().to_encoded_point(compress) - } -} - -impl ConditionallySelectable for ProjectivePoint { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - ProjectivePoint { - x: FieldElement::conditional_select(&a.x, &b.x, choice), - y: FieldElement::conditional_select(&a.y, &b.y, choice), - z: FieldElement::conditional_select(&a.z, &b.z, choice), - } - } -} - -impl ConstantTimeEq for ProjectivePoint { - fn ct_eq(&self, other: &Self) -> Choice { - self.to_affine().ct_eq(&other.to_affine()) - } -} - -impl DefaultIsZeroes for ProjectivePoint {} - -impl Eq for ProjectivePoint {} - -impl PartialEq for ProjectivePoint { - fn eq(&self, other: &Self) -> bool { - self.ct_eq(other).into() - } -} - -impl Default for ProjectivePoint { - fn default() -> Self { - Self::IDENTITY - } -} - -impl Add for ProjectivePoint { - type Output = ProjectivePoint; - - fn add(self, other: ProjectivePoint) -> ProjectivePoint { - ProjectivePoint::add(&self, &other) - } -} - -impl Add<&ProjectivePoint> for &ProjectivePoint { - type Output = ProjectivePoint; - - fn add(self, other: &ProjectivePoint) -> ProjectivePoint { - ProjectivePoint::add(self, other) - } -} - -impl Add<&ProjectivePoint> for ProjectivePoint { - type Output = ProjectivePoint; - - fn add(self, other: &ProjectivePoint) -> ProjectivePoint { - ProjectivePoint::add(&self, other) - } -} - -impl AddAssign for ProjectivePoint { - fn add_assign(&mut self, rhs: ProjectivePoint) { - *self = ProjectivePoint::add(self, &rhs); - } -} - -impl AddAssign<&ProjectivePoint> for ProjectivePoint { - fn add_assign(&mut self, rhs: &ProjectivePoint) { - *self = ProjectivePoint::add(self, rhs); - } -} - -impl Add for ProjectivePoint { - type Output = ProjectivePoint; - - fn add(self, other: AffinePoint) -> ProjectivePoint { - ProjectivePoint::add_mixed(&self, &other) - } -} - -impl Add<&AffinePoint> for &ProjectivePoint { - type Output = ProjectivePoint; - - fn add(self, other: &AffinePoint) -> ProjectivePoint { - ProjectivePoint::add_mixed(self, other) - } -} - -impl Add<&AffinePoint> for ProjectivePoint { - type Output = ProjectivePoint; - - fn add(self, other: &AffinePoint) -> ProjectivePoint { - ProjectivePoint::add_mixed(&self, other) - } -} - -impl AddAssign for ProjectivePoint { - fn add_assign(&mut self, rhs: AffinePoint) { - *self = ProjectivePoint::add_mixed(self, &rhs); - } -} - -impl AddAssign<&AffinePoint> for ProjectivePoint { - fn add_assign(&mut self, rhs: &AffinePoint) { - *self = ProjectivePoint::add_mixed(self, rhs); - } -} - -impl Sum for ProjectivePoint { - fn sum>(iter: I) -> Self { - iter.fold(ProjectivePoint::IDENTITY, |a, b| a + b) - } -} - -impl<'a> Sum<&'a ProjectivePoint> for ProjectivePoint { - fn sum>(iter: I) -> Self { - iter.cloned().sum() - } -} - -impl Sub for ProjectivePoint { - type Output = ProjectivePoint; - - fn sub(self, other: ProjectivePoint) -> ProjectivePoint { - ProjectivePoint::sub(&self, &other) - } -} - -impl Sub<&ProjectivePoint> for &ProjectivePoint { - type Output = ProjectivePoint; - - fn sub(self, other: &ProjectivePoint) -> ProjectivePoint { - ProjectivePoint::sub(self, other) - } -} - -impl Sub<&ProjectivePoint> for ProjectivePoint { - type Output = ProjectivePoint; - - fn sub(self, other: &ProjectivePoint) -> ProjectivePoint { - ProjectivePoint::sub(&self, other) - } -} - -impl SubAssign for ProjectivePoint { - fn sub_assign(&mut self, rhs: ProjectivePoint) { - *self = ProjectivePoint::sub(self, &rhs); - } -} - -impl SubAssign<&ProjectivePoint> for ProjectivePoint { - fn sub_assign(&mut self, rhs: &ProjectivePoint) { - *self = ProjectivePoint::sub(self, rhs); - } -} - -impl Sub for ProjectivePoint { - type Output = ProjectivePoint; - - fn sub(self, other: AffinePoint) -> ProjectivePoint { - ProjectivePoint::sub_mixed(&self, &other) - } -} - -impl Sub<&AffinePoint> for &ProjectivePoint { - type Output = ProjectivePoint; - - fn sub(self, other: &AffinePoint) -> ProjectivePoint { - ProjectivePoint::sub_mixed(self, other) - } -} - -impl Sub<&AffinePoint> for ProjectivePoint { - type Output = ProjectivePoint; - - fn sub(self, other: &AffinePoint) -> ProjectivePoint { - ProjectivePoint::sub_mixed(&self, other) - } -} - -impl SubAssign for ProjectivePoint { - fn sub_assign(&mut self, rhs: AffinePoint) { - *self = ProjectivePoint::sub_mixed(self, &rhs); - } -} - -impl SubAssign<&AffinePoint> for ProjectivePoint { - fn sub_assign(&mut self, rhs: &AffinePoint) { - *self = ProjectivePoint::sub_mixed(self, rhs); - } -} - -impl Mul for ProjectivePoint { - type Output = ProjectivePoint; - - fn mul(self, other: Scalar) -> ProjectivePoint { - ProjectivePoint::mul(&self, &other) - } -} - -impl Mul<&Scalar> for &ProjectivePoint { - type Output = ProjectivePoint; - - fn mul(self, other: &Scalar) -> ProjectivePoint { - ProjectivePoint::mul(self, other) - } -} - -impl Mul<&Scalar> for ProjectivePoint { - type Output = ProjectivePoint; - - fn mul(self, other: &Scalar) -> ProjectivePoint { - ProjectivePoint::mul(&self, other) - } -} - -impl MulAssign for ProjectivePoint { - fn mul_assign(&mut self, rhs: Scalar) { - *self = ProjectivePoint::mul(self, &rhs); - } -} - -impl MulAssign<&Scalar> for ProjectivePoint { - fn mul_assign(&mut self, rhs: &Scalar) { - *self = ProjectivePoint::mul(self, rhs); - } -} - -impl Neg for ProjectivePoint { - type Output = ProjectivePoint; - - fn neg(self) -> ProjectivePoint { - ProjectivePoint::neg(&self) - } -} - -impl<'a> Neg for &'a ProjectivePoint { - type Output = ProjectivePoint; - - fn neg(self) -> ProjectivePoint { - ProjectivePoint::neg(self) - } -} - -impl From for ProjectivePoint { - fn from(public_key: PublicKey) -> ProjectivePoint { - AffinePoint::from(public_key).into() - } -} - -impl From<&PublicKey> for ProjectivePoint { - fn from(public_key: &PublicKey) -> ProjectivePoint { - AffinePoint::from(public_key).into() - } -} - -impl TryFrom for PublicKey { - type Error = Error; - - fn try_from(point: ProjectivePoint) -> Result { - AffinePoint::from(point).try_into() - } -} - -impl TryFrom<&ProjectivePoint> for PublicKey { - type Error = Error; - - fn try_from(point: &ProjectivePoint) -> Result { - AffinePoint::from(point).try_into() - } -} - -#[cfg(test)] -mod tests { - use super::{AffinePoint, ProjectivePoint, Scalar}; - use crate::test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}; - use elliptic_curve::{group::prime::PrimeCurveAffine, PrimeField}; - - #[test] - fn affine_to_projective() { - let basepoint_affine = AffinePoint::GENERATOR; - let basepoint_projective = ProjectivePoint::GENERATOR; - - assert_eq!( - ProjectivePoint::from(basepoint_affine), - basepoint_projective, - ); - assert_eq!(basepoint_projective.to_affine(), basepoint_affine); - assert!(!bool::from(basepoint_projective.to_affine().is_identity())); - assert!(bool::from( - ProjectivePoint::IDENTITY.to_affine().is_identity() - )); - } - - #[test] - fn projective_identity_addition() { - let identity = ProjectivePoint::IDENTITY; - let generator = ProjectivePoint::GENERATOR; - - assert_eq!(identity + &generator, generator); - assert_eq!(generator + &identity, generator); - } - - #[test] - fn test_vector_repeated_add() { - let generator = ProjectivePoint::GENERATOR; - let mut p = generator; - - for i in 0..ADD_TEST_VECTORS.len() { - let affine = p.to_affine(); - - let (expected_x, expected_y) = ADD_TEST_VECTORS[i]; - assert_eq!(affine.x.to_sec1(), expected_x.into()); - assert_eq!(affine.y.to_sec1(), expected_y.into()); - - p += &generator; - } - } - - #[test] - fn test_vector_repeated_add_mixed() { - let generator = AffinePoint::GENERATOR; - let mut p = ProjectivePoint::GENERATOR; - - for i in 0..ADD_TEST_VECTORS.len() { - let affine = p.to_affine(); - - let (expected_x, expected_y) = ADD_TEST_VECTORS[i]; - assert_eq!(affine.x.to_sec1(), expected_x.into()); - assert_eq!(affine.y.to_sec1(), expected_y.into()); - - p += &generator; - } - } - - #[test] - fn test_vector_add_mixed_identity() { - let generator = ProjectivePoint::GENERATOR; - let p0 = generator + ProjectivePoint::IDENTITY; - let p1 = generator + AffinePoint::IDENTITY; - assert_eq!(p0, p1); - } - - #[test] - fn test_vector_double_generator() { - let generator = ProjectivePoint::GENERATOR; - let mut p = generator; - - for i in 0..2 { - let affine = p.to_affine(); - - let (expected_x, expected_y) = ADD_TEST_VECTORS[i]; - assert_eq!(affine.x.to_sec1(), expected_x.into()); - assert_eq!(affine.y.to_sec1(), expected_y.into()); - - p = p.double(); - } - } - - #[test] - fn projective_add_vs_double() { - let generator = ProjectivePoint::GENERATOR; - assert_eq!(generator + &generator, generator.double()); - } - - #[test] - fn projective_add_and_sub() { - let basepoint_affine = AffinePoint::GENERATOR; - let basepoint_projective = ProjectivePoint::GENERATOR; - - assert_eq!( - (basepoint_projective + &basepoint_projective) - &basepoint_projective, - basepoint_projective - ); - assert_eq!( - (basepoint_projective + &basepoint_affine) - &basepoint_affine, - basepoint_projective - ); - } - - #[test] - fn projective_double_and_sub() { - let generator = ProjectivePoint::GENERATOR; - assert_eq!(generator.double() - &generator, generator); - } - - #[test] - fn test_vector_scalar_mult() { - let generator = ProjectivePoint::GENERATOR; - - for (k, coords) in ADD_TEST_VECTORS - .iter() - .enumerate() - .map(|(k, coords)| (Scalar::from(k as u64 + 1), *coords)) - .chain( - MUL_TEST_VECTORS - .iter() - .cloned() - .map(|(k, x, y)| (Scalar::from_repr(k.into()).unwrap(), (x, y))), - ) - { - let res = (generator * &k).to_affine(); - assert_eq!(res.x.to_sec1(), coords.0.into()); - assert_eq!(res.y.to_sec1(), coords.1.into()); - } - } -} diff --git a/vendor/p384/src/arithmetic/scalar.rs b/vendor/p384/src/arithmetic/scalar.rs index db7994e20..7f33ec66b 100644 --- a/vendor/p384/src/arithmetic/scalar.rs +++ b/vendor/p384/src/arithmetic/scalar.rs @@ -12,14 +12,18 @@ mod scalar_impl; use self::scalar_impl::*; -use crate::{FieldBytes, NistP384, SecretKey, U384}; -use core::ops::{AddAssign, MulAssign, Neg, SubAssign}; +use crate::{FieldBytes, NistP384, SecretKey, ORDER_HEX, U384}; +use core::{ + iter::{Product, Sum}, + ops::{AddAssign, MulAssign, Neg, Shr, ShrAssign, SubAssign}, +}; use elliptic_curve::{ - bigint::{self, Encoding, Limb}, + bigint::{self, ArrayEncoding, Limb}, ff::PrimeField, - ops::Reduce, + ops::{Invert, Reduce}, + scalar::{FromUintUnchecked, IsHigh}, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption}, - Curve as _, Error, IsHigh, Result, ScalarArithmetic, ScalarCore, + Curve as _, Error, Result, ScalarPrimitive, }; #[cfg(feature = "bits")] @@ -31,10 +35,6 @@ use serdect::serde::{de, ser, Deserialize, Serialize}; #[cfg(doc)] use core::ops::{Add, Mul, Sub}; -impl ScalarArithmetic for NistP384 { - type Scalar = Scalar; -} - /// Scalars are elements in the finite field modulo `n`. /// /// # Trait impls @@ -66,11 +66,11 @@ impl ScalarArithmetic for NistP384 { /// /// The serialization is a fixed-width big endian encoding. When used with /// textual formats, the binary data is encoded as hexadecimal. -#[derive(Clone, Copy, Debug)] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +#[derive(Clone, Copy, Debug, PartialOrd, Ord)] pub struct Scalar(U384); -elliptic_curve::impl_field_element!( +primeorder::impl_mont_field_element!( + NistP384, Scalar, FieldBytes, U384, @@ -86,16 +86,20 @@ elliptic_curve::impl_field_element!( ); impl Scalar { - /// `2^s` root of unity. - pub const ROOT_OF_UNITY: Self = Self::from_be_hex("ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972"); - /// Compute [`Scalar`] inversion: `1 / self`. pub fn invert(&self) -> CtOption { - let ret = impl_field_invert!( - self.to_canonical().to_words(), + CtOption::new(self.invert_unchecked(), !self.is_zero()) + } + + /// Returns the multiplicative inverse of self. + /// + /// Does not check that self is non-zero. + const fn invert_unchecked(&self) -> Self { + let words = impl_field_invert!( + self.to_canonical().as_words(), Self::ONE.0.to_words(), - Limb::BIT_SIZE, - bigint::nlimbs!(U384::BIT_SIZE), + Limb::BITS, + bigint::nlimbs!(U384::BITS), fiat_p384_scalar_mul, fiat_p384_scalar_opp, fiat_p384_scalar_divstep_precomp, @@ -103,7 +107,8 @@ impl Scalar { fiat_p384_scalar_msat, fiat_p384_scalar_selectznz, ); - CtOption::new(Self(ret.into()), !self.is_zero()) + + Self(U384::from_words(words)) } /// Compute modular square root. @@ -155,12 +160,33 @@ impl Scalar { x } - /// Returns the SEC1 encoding of this scalar. + /// Right shifts the scalar. /// - /// Required for running test vectors. - #[cfg(test)] - pub fn to_bytes(&self) -> FieldBytes { - self.to_be_bytes() + /// Note: not constant-time with respect to the `shift` parameter. + pub const fn shr_vartime(&self, shift: usize) -> Scalar { + Self(self.0.shr_vartime(shift)) + } +} + +impl AsRef for Scalar { + fn as_ref(&self) -> &Scalar { + self + } +} + +impl FromUintUnchecked for Scalar { + type Uint = U384; + + fn from_uint_unchecked(uint: Self::Uint) -> Self { + Self::from_uint_unchecked(uint) + } +} + +impl Invert for Scalar { + type Output = CtOption; + + fn invert(&self) -> CtOption { + self.invert() } } @@ -171,36 +197,58 @@ impl IsHigh for Scalar { } } +impl Shr for Scalar { + type Output = Self; + + fn shr(self, rhs: usize) -> Self::Output { + self.shr_vartime(rhs) + } +} + +impl Shr for &Scalar { + type Output = Scalar; + + fn shr(self, rhs: usize) -> Self::Output { + self.shr_vartime(rhs) + } +} + +impl ShrAssign for Scalar { + fn shr_assign(&mut self, rhs: usize) { + *self = *self >> rhs; + } +} + impl PrimeField for Scalar { type Repr = FieldBytes; + const MODULUS: &'static str = ORDER_HEX; const CAPACITY: u32 = 383; const NUM_BITS: u32 = 384; + const TWO_INV: Self = Self::from_u64(2).invert_unchecked(); + const MULTIPLICATIVE_GENERATOR: Self = Self::from_u64(2); const S: u32 = 1; + const ROOT_OF_UNITY: Self = Self::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52972"); + const ROOT_OF_UNITY_INV: Self = Self::ROOT_OF_UNITY.invert_unchecked(); + const DELTA: Self = Self::from_u64(4); + #[inline] fn from_repr(bytes: FieldBytes) -> CtOption { - Self::from_be_bytes(bytes) + Self::from_bytes(&bytes) } + #[inline] fn to_repr(&self) -> FieldBytes { - self.to_be_bytes() + self.to_bytes() } + #[inline] fn is_odd(&self) -> Choice { self.is_odd() } - - fn multiplicative_generator() -> Self { - 2u64.into() - } - - fn root_of_unity() -> Self { - Self::ROOT_OF_UNITY - } } #[cfg(feature = "bits")] -#[cfg_attr(docsrs, doc(cfg(feature = "bits")))] impl PrimeFieldBits for Scalar { type ReprBits = fiat_p384_scalar_montgomery_domain_field_element; @@ -214,40 +262,41 @@ impl PrimeFieldBits for Scalar { } impl Reduce for Scalar { - fn from_uint_reduced(w: U384) -> Self { + type Bytes = FieldBytes; + + fn reduce(w: U384) -> Self { let (r, underflow) = w.sbb(&NistP384::ORDER, Limb::ZERO); - let underflow = Choice::from((underflow.0 >> (Limb::BIT_SIZE - 1)) as u8); + let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8); Self::from_uint_unchecked(U384::conditional_select(&w, &r, !underflow)) } -} -impl From for Scalar { - fn from(n: u64) -> Scalar { - Self::from_uint_unchecked(U384::from(n)) + #[inline] + fn reduce_bytes(bytes: &FieldBytes) -> Self { + Self::reduce(U384::from_be_byte_array(*bytes)) } } -impl From> for Scalar { - fn from(w: ScalarCore) -> Self { +impl From> for Scalar { + fn from(w: ScalarPrimitive) -> Self { Scalar::from(&w) } } -impl From<&ScalarCore> for Scalar { - fn from(w: &ScalarCore) -> Scalar { +impl From<&ScalarPrimitive> for Scalar { + fn from(w: &ScalarPrimitive) -> Scalar { Scalar::from_uint_unchecked(*w.as_uint()) } } -impl From for ScalarCore { - fn from(scalar: Scalar) -> ScalarCore { - ScalarCore::from(&scalar) +impl From for ScalarPrimitive { + fn from(scalar: Scalar) -> ScalarPrimitive { + ScalarPrimitive::from(&scalar) } } -impl From<&Scalar> for ScalarCore { - fn from(scalar: &Scalar) -> ScalarCore { - ScalarCore::new(scalar.into()).unwrap() +impl From<&Scalar> for ScalarPrimitive { + fn from(scalar: &Scalar) -> ScalarPrimitive { + ScalarPrimitive::new(scalar.into()).unwrap() } } @@ -290,24 +339,22 @@ impl TryFrom for Scalar { } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for Scalar { fn serialize(&self, serializer: S) -> core::result::Result where S: ser::Serializer, { - ScalarCore::from(self).serialize(serializer) + ScalarPrimitive::from(self).serialize(serializer) } } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for Scalar { fn deserialize(deserializer: D) -> core::result::Result where D: de::Deserializer<'de>, { - Ok(ScalarCore::deserialize(deserializer)?.into()) + Ok(ScalarPrimitive::deserialize(deserializer)?.into()) } } @@ -315,22 +362,35 @@ impl<'de> Deserialize<'de> for Scalar { mod tests { use super::Scalar; use crate::FieldBytes; - use elliptic_curve::ff::{Field, PrimeField}; + use elliptic_curve::ff::PrimeField; + use primeorder::impl_primefield_tests; + + /// t = (modulus - 1) >> S + const T: [u64; 6] = [ + 0x76760cb5666294b9, + 0xac0d06d9245853bd, + 0xe3b1a6c0fa1b96ef, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0x7fffffffffffffff, + ]; + + impl_primefield_tests!(Scalar, T); #[test] fn from_to_bytes_roundtrip() { let k: u64 = 42; let mut bytes = FieldBytes::default(); - bytes[40..].copy_from_slice(k.to_le_bytes().as_ref()); + bytes[40..].copy_from_slice(k.to_be_bytes().as_ref()); let scalar = Scalar::from_repr(bytes).unwrap(); - assert_eq!(bytes, scalar.to_be_bytes()); + assert_eq!(bytes, scalar.to_bytes()); } /// Basic tests that multiplication works. #[test] fn multiply() { - let one = Scalar::one(); + let one = Scalar::ONE; let two = one + one; let three = two + one; let six = three + three; @@ -347,7 +407,7 @@ mod tests { /// Basic tests that scalar inversion works. #[test] fn invert() { - let one = Scalar::one(); + let one = Scalar::ONE; let three = one + one + one; let inv_three = three.invert().unwrap(); assert_eq!(three * inv_three, one); diff --git a/vendor/p384/src/ecdh.rs b/vendor/p384/src/ecdh.rs index 622bfaa42..1e9ec85c3 100644 --- a/vendor/p384/src/ecdh.rs +++ b/vendor/p384/src/ecdh.rs @@ -38,16 +38,10 @@ pub use elliptic_curve::ecdh::diffie_hellman; -use crate::{AffinePoint, NistP384}; +use crate::NistP384; /// NIST P-384 Ephemeral Diffie-Hellman Secret. pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret; /// Shared secret value computed via ECDH key agreement. pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; - -impl From<&AffinePoint> for SharedSecret { - fn from(affine: &AffinePoint) -> SharedSecret { - affine.x.to_sec1().into() - } -} diff --git a/vendor/p384/src/ecdsa.rs b/vendor/p384/src/ecdsa.rs index efa9868e0..0de2ed678 100644 --- a/vendor/p384/src/ecdsa.rs +++ b/vendor/p384/src/ecdsa.rs @@ -27,7 +27,7 @@ //! // Signing //! let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()` //! let message = b"ECDSA proves knowledge of a secret number in the context of a single message"; -//! let signature = signing_key.sign(message); +//! let signature: Signature = signing_key.sign(message); //! //! // Verification //! use p384::ecdsa::{signature::Verifier, VerifyingKey}; @@ -54,16 +54,13 @@ pub type DerSignature = ecdsa_core::der::Signature; /// ECDSA/P-384 signing key #[cfg(feature = "ecdsa")] -#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))] pub type SigningKey = ecdsa_core::SigningKey; /// ECDSA/P-384 verification key (i.e. public key) #[cfg(feature = "ecdsa")] -#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))] pub type VerifyingKey = ecdsa_core::VerifyingKey; #[cfg(feature = "sha384")] -#[cfg_attr(docsrs, doc(cfg(feature = "sha384")))] impl ecdsa_core::hazmat::DigestPrimitive for NistP384 { type Digest = sha2::Sha384; } @@ -77,33 +74,83 @@ impl VerifyPrimitive for AffinePoint {} #[cfg(all(test, feature = "ecdsa"))] mod tests { use crate::{ - ecdsa::{signature::Signer, SigningKey}, - SecretKey, + ecdsa::{ + signature::hazmat::{PrehashSigner, PrehashVerifier}, + signature::Signer, + Signature, SigningKey, VerifyingKey, + }, + AffinePoint, EncodedPoint, SecretKey, }; + + use elliptic_curve::{generic_array::GenericArray, sec1::FromEncodedPoint}; use hex_literal::hex; + use sha2::Digest; // Test vector from RFC 6979 Appendix 2.6 (NIST P-384 + SHA-384) // #[test] fn rfc6979() { - let x = &hex!("6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d896d5724e4c70a825f872c9ea60d2edf5"); - let signer = SigningKey::from_bytes(x).unwrap(); - let signature = signer.sign(b"sample"); + let x = hex!("6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d896d5724e4c70a825f872c9ea60d2edf5"); + let signer = SigningKey::from_bytes(&x.into()).unwrap(); + let signature: Signature = signer.sign(b"sample"); assert_eq!( - signature.as_ref(), + signature.to_bytes().as_slice(), &hex!( "94edbb92a5ecb8aad4736e56c691916b3f88140666ce9fa73d64c4ea95ad133c81a648152e44acf96e36dd1e80fabe46 99ef4aeb15f178cea1fe40db2603138f130e740a19624526203b6351d0a3a94fa329c145786e679e7b82c71a38628ac8" - )[..] + ) ); - let signature = signer.sign(b"test"); + + let signature: Signature = signer.sign(b"test"); assert_eq!( - signature.as_ref(), + signature.to_bytes().as_slice(), &hex!( "8203b63d3c853e8d77227fb377bcf7b7b772e97892a80f36ab775d509d7a5feb0542a7f0812998da8f1dd3ca3cf023db ddd0760448d42d8a43af45af836fce4de8be06b485e9b61b827c2f13173923e06a739f040649a667bf3b828246baa5a5" - )[..] + ) + ); + } + + // Test signing with PrehashSigner using SHA-256 which output is smaller than P-384 field size. + #[test] + fn prehash_signer_signing_with_sha256() { + let x = hex!("6b9d3dad2e1b8c1c05b19875b6659f4de23c3b667bf297ba9aa47740787137d896d5724e4c70a825f872c9ea60d2edf5"); + let signer = SigningKey::from_bytes(&x.into()).unwrap(); + let digest = sha2::Sha256::digest(b"test"); + let signature: Signature = signer.sign_prehash(&digest).unwrap(); + assert_eq!( + signature.to_bytes().as_slice(), + &hex!( + "010c3ab1a300f8c9d63eafa9a41813f0c5416c08814bdfc0236458d6c2603d71c4941f4696e60aff5717476170bb6ab4 + 03c4ad6274c61691346b2178def879424726909af308596ffb6355a042f48a114e2eb28eaa6918592b4727961057c0c1" + ) + ); + } + + // Test verifying with PrehashVerifier using SHA-256 which output is smaller than P-384 field size. + #[test] + fn prehash_signer_verification_with_sha256() { + // The following test vector adapted from the FIPS 186-4 ECDSA test vectors + // (P-384, SHA-256, from `SigGen.txt` in `186-4ecdsatestvectors.zip`) + // + let verifier = VerifyingKey::from_affine( + AffinePoint::from_encoded_point( + &EncodedPoint::from_affine_coordinates( + GenericArray::from_slice(&hex!("0400193b21f07cd059826e9453d3e96dd145041c97d49ff6b7047f86bb0b0439e909274cb9c282bfab88674c0765bc75")), + GenericArray::from_slice(&hex!("f70d89c52acbc70468d2c5ae75c76d7f69b76af62dcf95e99eba5dd11adf8f42ec9a425b0c5ec98e2f234a926b82a147")), + false, + ), + ).unwrap() + ).unwrap(); + let signature = Signature::from_scalars( + GenericArray::clone_from_slice(&hex!("b11db00cdaf53286d4483f38cd02785948477ed7ebc2ad609054551da0ab0359978c61851788aa2ec3267946d440e878")), + GenericArray::clone_from_slice(&hex!("16007873c5b0604ce68112a8fee973e8e2b6e3319c683a762ff5065a076512d7c98b27e74b7887671048ac027df8cbf2")), + ).unwrap(); + let result = verifier.verify_prehash( + &hex!("bbbd0a5f645d3fda10e288d172b299455f9dff00e0fbc2833e18cd017d7f3ed1"), + &signature, ); + assert!(result.is_ok()); } #[test] @@ -114,11 +161,11 @@ mod tests { 102, 30, 237, 90, 198, 36, 97, 52, 12, 234, 150, ]; - let sigk = SigningKey::from_bytes(raw_sk.as_slice()).unwrap(); - let seck = SecretKey::from_be_bytes(raw_sk.as_slice()).unwrap(); + let seck = SecretKey::from_bytes(&raw_sk.into()).unwrap(); + let sigk = SigningKey::from_bytes(&raw_sk.into()).unwrap(); + assert_eq!(seck.to_bytes().as_slice(), &raw_sk); assert_eq!(sigk.to_bytes().as_slice(), &raw_sk); - assert_eq!(sigk.to_bytes(), seck.to_be_bytes()); } mod sign { diff --git a/vendor/p384/src/lib.rs b/vendor/p384/src/lib.rs index 627b44c32..0544d0614 100644 --- a/vendor/p384/src/lib.rs +++ b/vendor/p384/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" @@ -23,57 +23,60 @@ mod arithmetic; #[cfg(feature = "ecdh")] -#[cfg_attr(docsrs, doc(cfg(feature = "ecdh")))] pub mod ecdh; #[cfg(feature = "ecdsa-core")] -#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa-core")))] pub mod ecdsa; #[cfg(any(feature = "test-vectors", test))] -#[cfg_attr(docsrs, doc(cfg(feature = "test-vectors")))] pub mod test_vectors; -pub use elliptic_curve::{self, bigint::U384}; +pub use elliptic_curve::{self, bigint::U384, consts::U48}; #[cfg(feature = "arithmetic")] -pub use arithmetic::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; +pub use arithmetic::{scalar::Scalar, AffinePoint, ProjectivePoint}; #[cfg(feature = "expose-field")] pub use arithmetic::field::FieldElement; #[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] pub use elliptic_curve::pkcs8; -use elliptic_curve::{consts::U49, generic_array::GenericArray}; +use elliptic_curve::{ + bigint::ArrayEncoding, consts::U49, generic_array::GenericArray, FieldBytesEncoding, +}; + +/// Order of NIST P-384's elliptic curve group (i.e. scalar modulus) in hexadecimal. +const ORDER_HEX: &str = "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973"; /// NIST P-384 elliptic curve. #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub struct NistP384; impl elliptic_curve::Curve for NistP384 { + /// 48-byte serialized field elements. + type FieldBytesSize = U48; + /// 384-bit integer type used for internally representing field elements. - type UInt = U384; + type Uint = U384; /// Order of NIST P-384's elliptic curve group (i.e. scalar modulus). - const ORDER: U384 = U384::from_be_hex("ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973"); + const ORDER: U384 = U384::from_be_hex(ORDER_HEX); } impl elliptic_curve::PrimeCurve for NistP384 {} -impl elliptic_curve::PointCompression for NistP384 { +impl elliptic_curve::point::PointCompression for NistP384 { /// NIST P-384 points are typically uncompressed. const COMPRESS_POINTS: bool = false; } -impl elliptic_curve::PointCompaction for NistP384 { +impl elliptic_curve::point::PointCompaction for NistP384 { /// NIST P-384 points are typically uncompressed. const COMPACT_POINTS: bool = false; } #[cfg(feature = "jwk")] -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] impl elliptic_curve::JwkParameters for NistP384 { const CRV: &'static str = "P-384"; } @@ -86,14 +89,24 @@ impl pkcs8::AssociatedOid for NistP384 { /// Compressed SEC1-encoded NIST P-384 curve point. pub type CompressedPoint = GenericArray; +/// NIST P-384 SEC1 encoded point. +pub type EncodedPoint = elliptic_curve::sec1::EncodedPoint; + /// NIST P-384 field element serialized as bytes. /// /// Byte array containing a serialized field element value (base field or /// scalar). pub type FieldBytes = elliptic_curve::FieldBytes; -/// NIST P-384 SEC1 encoded point. -pub type EncodedPoint = elliptic_curve::sec1::EncodedPoint; +impl FieldBytesEncoding for U384 { + fn decode_field_bytes(field_bytes: &FieldBytes) -> Self { + U384::from_be_byte_array(*field_bytes) + } + + fn encode_field_bytes(&self) -> FieldBytes { + self.to_be_byte_array() + } +} /// Non-zero NIST P-384 scalar field element. #[cfg(feature = "arithmetic")] @@ -111,15 +124,13 @@ impl elliptic_curve::sec1::ValidatePublicKey for NistP384 {} /// Bit representation of a NIST P-384 scalar field element. #[cfg(feature = "bits")] -#[cfg_attr(docsrs, doc(cfg(feature = "bits")))] -pub type ScalarBits = elliptic_curve::ScalarBits; +pub type ScalarBits = elliptic_curve::scalar::ScalarBits; #[cfg(feature = "voprf")] -#[cfg_attr(docsrs, doc(cfg(feature = "voprf")))] impl elliptic_curve::VoprfParameters for NistP384 { + /// See . + const ID: &'static str = "P384-SHA384"; + /// See . type Hash = sha2::Sha384; - - /// See . - const ID: u16 = 0x0004; } -- cgit v1.2.3