diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/elliptic-curve/src | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/elliptic-curve/src')
26 files changed, 1582 insertions, 1312 deletions
diff --git a/vendor/elliptic-curve/src/arithmetic.rs b/vendor/elliptic-curve/src/arithmetic.rs index fa445f1bc..7ef7fc53d 100644 --- a/vendor/elliptic-curve/src/arithmetic.rs +++ b/vendor/elliptic-curve/src/arithmetic.rs @@ -1,20 +1,21 @@ //! Elliptic curve arithmetic traits. use crate::{ - ops::LinearCombination, AffineXCoordinate, Curve, FieldBytes, IsHigh, PrimeCurve, ScalarCore, + ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign}, + point::AffineCoordinates, + scalar::{FromUintUnchecked, IsHigh}, + Curve, FieldBytes, PrimeCurve, ScalarPrimitive, }; use core::fmt::Debug; -use subtle::{ConditionallySelectable, ConstantTimeEq}; +use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption}; use zeroize::DefaultIsZeroes; -/// Elliptic curve with affine arithmetic implementation. -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub trait AffineArithmetic: Curve + ScalarArithmetic { +/// Elliptic curve with an arithmetic implementation. +pub trait CurveArithmetic: Curve { /// Elliptic curve point in affine coordinates. type AffinePoint: 'static - + AffineXCoordinate<Self> + + AffineCoordinates<FieldRepr = FieldBytes<Self>> + Copy - + Clone + ConditionallySelectable + ConstantTimeEq + Debug @@ -25,20 +26,7 @@ pub trait AffineArithmetic: Curve + ScalarArithmetic { + Sized + Send + Sync; -} - -/// Prime order elliptic curve with projective arithmetic implementation. -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub trait PrimeCurveArithmetic: - PrimeCurve + ProjectiveArithmetic<ProjectivePoint = Self::CurveGroup> -{ - /// Prime order elliptic curve group. - type CurveGroup: group::prime::PrimeCurve<Affine = <Self as AffineArithmetic>::AffinePoint>; -} -/// Elliptic curve with projective arithmetic implementation. -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub trait ProjectiveArithmetic: Curve + AffineArithmetic { /// Elliptic curve point in projective coordinates. /// /// Note: the following bounds are provided by [`group::Group`]: @@ -57,15 +45,11 @@ pub trait ProjectiveArithmetic: Curve + AffineArithmetic { + From<Self::AffinePoint> + Into<Self::AffinePoint> + LinearCombination + + MulByGenerator + group::Curve<AffineRepr = Self::AffinePoint> + group::Group<Scalar = Self::Scalar>; -} -/// Scalar arithmetic. -#[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub trait ScalarArithmetic: Curve { - /// Scalar field type. + /// Scalar field modulo this curve's order. /// /// Note: the following bounds are provided by [`ff::Field`]: /// - `'static` @@ -77,11 +61,26 @@ pub trait ScalarArithmetic: Curve { /// - [`Default`] /// - [`Send`] /// - [`Sync`] - type Scalar: DefaultIsZeroes - + From<ScalarCore<Self>> + type Scalar: AsRef<Self::Scalar> + + DefaultIsZeroes + + From<ScalarPrimitive<Self>> + + FromUintUnchecked<Uint = Self::Uint> + Into<FieldBytes<Self>> - + Into<Self::UInt> + + Into<ScalarPrimitive<Self>> + + Into<Self::Uint> + + Invert<Output = CtOption<Self::Scalar>> + IsHigh + + PartialOrd + + Reduce<Self::Uint, Bytes = FieldBytes<Self>> + + ShrAssign<usize> + ff::Field + ff::PrimeField<Repr = FieldBytes<Self>>; } + +/// Prime order elliptic curve with projective arithmetic implementation. +pub trait PrimeCurveArithmetic: + PrimeCurve + CurveArithmetic<ProjectivePoint = Self::CurveGroup> +{ + /// Prime order elliptic curve group. + type CurveGroup: group::prime::PrimeCurve<Affine = <Self as CurveArithmetic>::AffinePoint>; +} diff --git a/vendor/elliptic-curve/src/dev.rs b/vendor/elliptic-curve/src/dev.rs index be0c156e5..36c684ad4 100644 --- a/vendor/elliptic-curve/src/dev.rs +++ b/vendor/elliptic-curve/src/dev.rs @@ -6,26 +6,27 @@ use crate::{ bigint::{Limb, U256}, error::{Error, Result}, - ops::{LinearCombination, Reduce}, + generic_array::typenum::U32, + ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign}, pkcs8, + point::AffineCoordinates, rand_core::RngCore, - sec1::{FromEncodedPoint, ToEncodedPoint}, + scalar::{FromUintUnchecked, IsHigh}, + sec1::{CompressedPoint, FromEncodedPoint, ToEncodedPoint}, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::DefaultIsZeroes, - AffineArithmetic, AffineXCoordinate, Curve, IsHigh, PrimeCurve, ProjectiveArithmetic, - ScalarArithmetic, + Curve, CurveArithmetic, FieldBytesEncoding, PrimeCurve, }; use core::{ - iter::Sum, + iter::{Product, Sum}, ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; use ff::{Field, PrimeField}; -use generic_array::arr; use hex_literal::hex; use pkcs8::AssociatedOid; #[cfg(feature = "bits")] -use crate::group::ff::PrimeFieldBits; +use ff::PrimeFieldBits; #[cfg(feature = "jwk")] use crate::JwkParameters; @@ -49,13 +50,13 @@ pub type PublicKey = crate::PublicKey<MockCurve>; /// Secret key. pub type SecretKey = crate::SecretKey<MockCurve>; -/// Scalar core. -// TODO(tarcieri): make this the scalar type -pub type ScalarCore = crate::ScalarCore<MockCurve>; +/// Scalar primitive type. +// TODO(tarcieri): make this the scalar type when it's more capable +pub type ScalarPrimitive = crate::ScalarPrimitive<MockCurve>; /// Scalar bits. #[cfg(feature = "bits")] -pub type ScalarBits = crate::ScalarBits<MockCurve>; +pub type ScalarBits = crate::scalar::ScalarBits<MockCurve>; /// Mock elliptic curve type useful for writing tests which require a concrete /// curve type. @@ -66,7 +67,8 @@ pub type ScalarBits = crate::ScalarBits<MockCurve>; pub struct MockCurve; impl Curve for MockCurve { - type UInt = U256; + type FieldBytesSize = U32; + type Uint = U256; const ORDER: U256 = U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); @@ -74,15 +76,9 @@ impl Curve for MockCurve { impl PrimeCurve for MockCurve {} -impl AffineArithmetic for MockCurve { +impl CurveArithmetic for MockCurve { type AffinePoint = AffinePoint; -} - -impl ProjectiveArithmetic for MockCurve { type ProjectivePoint = ProjectivePoint; -} - -impl ScalarArithmetic for MockCurve { type Scalar = Scalar; } @@ -92,16 +88,18 @@ impl AssociatedOid for MockCurve { } #[cfg(feature = "jwk")] -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] impl JwkParameters for MockCurve { const CRV: &'static str = "P-256"; } /// Example scalar type -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct Scalar(ScalarCore); +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct Scalar(ScalarPrimitive); impl Field for Scalar { + const ZERO: Self = Self(ScalarPrimitive::ZERO); + const ONE: Self = Self(ScalarPrimitive::ONE); + fn random(mut rng: impl RngCore) -> Self { let mut bytes = FieldBytes::default(); @@ -113,14 +111,6 @@ impl Field for Scalar { } } - fn zero() -> Self { - Self(ScalarCore::ZERO) - } - - fn one() -> Self { - Self(ScalarCore::ONE) - } - fn is_zero(&self) -> Choice { self.0.is_zero() } @@ -142,39 +132,37 @@ impl Field for Scalar { fn sqrt(&self) -> CtOption<Self> { unimplemented!(); } + + fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { + unimplemented!(); + } } impl PrimeField for Scalar { type Repr = FieldBytes; + const MODULUS: &'static str = + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"; const NUM_BITS: u32 = 256; const CAPACITY: u32 = 255; + const TWO_INV: Self = Self::ZERO; // BOGUS! + const MULTIPLICATIVE_GENERATOR: Self = Self::ZERO; // BOGUS! Should be 7 const S: u32 = 4; + const ROOT_OF_UNITY: Self = Self::ZERO; // BOGUS! Should be 0xffc97f062a770992ba807ace842a3dfc1546cad004378daf0592d7fbb41e6602 + const ROOT_OF_UNITY_INV: Self = Self::ZERO; // BOGUS! + const DELTA: Self = Self::ZERO; // BOGUS! fn from_repr(bytes: FieldBytes) -> CtOption<Self> { - ScalarCore::from_be_bytes(bytes).map(Self) + ScalarPrimitive::from_bytes(&bytes).map(Self) } fn to_repr(&self) -> FieldBytes { - self.0.to_be_bytes() + self.0.to_bytes() } fn is_odd(&self) -> Choice { self.0.is_odd() } - - fn multiplicative_generator() -> Self { - 7u64.into() - } - - fn root_of_unity() -> Self { - Self::from_repr(arr![u8; - 0xff, 0xc9, 0x7f, 0x06, 0x2a, 0x77, 0x09, 0x92, 0xba, 0x80, 0x7a, 0xce, 0x84, 0x2a, - 0x3d, 0xfc, 0x15, 0x46, 0xca, 0xd0, 0x04, 0x37, 0x8d, 0xaf, 0x05, 0x92, 0xd7, 0xfb, - 0xb4, 0x1e, 0x66, 0x02, - ]) - .unwrap() - } } #[cfg(feature = "bits")] @@ -194,23 +182,15 @@ impl PrimeFieldBits for Scalar { } } -impl TryFrom<U256> for Scalar { - type Error = Error; - - fn try_from(w: U256) -> Result<Self> { - Option::from(ScalarCore::new(w)).map(Self).ok_or(Error) - } -} - -impl From<Scalar> for U256 { - fn from(scalar: Scalar) -> U256 { - *scalar.0.as_uint() +impl AsRef<Scalar> for Scalar { + fn as_ref(&self) -> &Scalar { + self } } impl ConditionallySelectable for Scalar { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Self(ScalarCore::conditional_select(&a.0, &b.0, choice)) + Self(ScalarPrimitive::conditional_select(&a.0, &b.0, choice)) } } @@ -314,27 +294,102 @@ impl Neg for Scalar { } } +impl ShrAssign<usize> for Scalar { + fn shr_assign(&mut self, rhs: usize) { + self.0 >>= rhs; + } +} + +impl Sum for Scalar { + fn sum<I: Iterator<Item = Self>>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl<'a> Sum<&'a Scalar> for Scalar { + fn sum<I: Iterator<Item = &'a Scalar>>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl Product for Scalar { + fn product<I: Iterator<Item = Self>>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl<'a> Product<&'a Scalar> for Scalar { + fn product<I: Iterator<Item = &'a Scalar>>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl Invert for Scalar { + type Output = CtOption<Scalar>; + + fn invert(&self) -> CtOption<Scalar> { + unimplemented!(); + } +} + impl Reduce<U256> for Scalar { - fn from_uint_reduced(w: U256) -> Self { + type Bytes = FieldBytes; + + #[allow(clippy::integer_arithmetic)] + fn reduce(w: U256) -> Self { let (r, underflow) = w.sbb(&MockCurve::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); let reduced = U256::conditional_select(&w, &r, !underflow); - Self(ScalarCore::new(reduced).unwrap()) + Self(ScalarPrimitive::new(reduced).unwrap()) + } + + fn reduce_bytes(_: &FieldBytes) -> Self { + todo!() } } +impl FieldBytesEncoding<MockCurve> for U256 {} + impl From<u64> for Scalar { fn from(n: u64) -> Scalar { Self(n.into()) } } -impl From<ScalarCore> for Scalar { - fn from(scalar: ScalarCore) -> Scalar { +impl From<ScalarPrimitive> for Scalar { + fn from(scalar: ScalarPrimitive) -> Scalar { Self(scalar) } } +impl From<Scalar> for ScalarPrimitive { + fn from(scalar: Scalar) -> ScalarPrimitive { + scalar.0 + } +} + +impl From<Scalar> for U256 { + fn from(scalar: Scalar) -> U256 { + scalar.0.to_uint() + } +} + +impl TryFrom<U256> for Scalar { + type Error = Error; + + fn try_from(w: U256) -> Result<Self> { + Option::from(ScalarPrimitive::new(w)).map(Self).ok_or(Error) + } +} + +impl FromUintUnchecked for Scalar { + type Uint = U256; + + fn from_uint_unchecked(uint: U256) -> Self { + Self(ScalarPrimitive::from_uint_unchecked(uint)) + } +} + impl From<Scalar> for FieldBytes { fn from(scalar: Scalar) -> Self { Self::from(&scalar) @@ -369,15 +424,28 @@ pub enum AffinePoint { Other(EncodedPoint), } -impl AffineXCoordinate<MockCurve> for AffinePoint { +impl AffineCoordinates for AffinePoint { + type FieldRepr = FieldBytes; + fn x(&self) -> FieldBytes { unimplemented!(); } + + fn y_is_odd(&self) -> Choice { + unimplemented!(); + } } impl ConstantTimeEq for AffinePoint { - fn ct_eq(&self, _other: &Self) -> Choice { - unimplemented!(); + fn ct_eq(&self, other: &Self) -> Choice { + match (self, other) { + (Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => { + scalar.ct_eq(other_scalar) + } + (Self::Identity, Self::Identity) | (Self::Generator, Self::Generator) => 1.into(), + (Self::Other(point), Self::Other(other_point)) => u8::from(point == other_point).into(), + _ => 0.into(), + } } } @@ -457,14 +525,25 @@ pub enum ProjectivePoint { } impl ConstantTimeEq for ProjectivePoint { - fn ct_eq(&self, _other: &Self) -> Choice { - unimplemented!(); + fn ct_eq(&self, other: &Self) -> Choice { + match (self, other) { + (Self::FixedBaseOutput(scalar), Self::FixedBaseOutput(other_scalar)) => { + scalar.ct_eq(other_scalar) + } + (Self::Identity, Self::Identity) | (Self::Generator, Self::Generator) => 1.into(), + (Self::Other(point), Self::Other(other_point)) => point.ct_eq(other_point), + _ => 0.into(), + } } } impl ConditionallySelectable for ProjectivePoint { - fn conditional_select(_a: &Self, _b: &Self, _choice: Choice) -> Self { - unimplemented!(); + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + if choice.into() { + *b + } else { + *a + } } } @@ -521,7 +600,7 @@ impl group::Group for ProjectivePoint { } fn is_identity(&self) -> Choice { - Choice::from((self == &Self::Identity) as u8) + Choice::from(u8::from(self == &Self::Identity)) } #[must_use] @@ -530,6 +609,47 @@ impl group::Group for ProjectivePoint { } } +impl group::GroupEncoding for AffinePoint { + type Repr = CompressedPoint<MockCurve>; + + fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> { + EncodedPoint::from_bytes(bytes) + .map(|point| CtOption::new(point, Choice::from(1))) + .unwrap_or_else(|_| { + 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<Self> { + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + let encoded = self.to_encoded_point(true); + let mut result = CompressedPoint::<MockCurve>::default(); + result[..encoded.len()].copy_from_slice(encoded.as_bytes()); + result + } +} + +impl group::GroupEncoding for ProjectivePoint { + type Repr = CompressedPoint<MockCurve>; + + fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> { + <AffinePoint as group::GroupEncoding>::from_bytes(bytes).map(Into::into) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> { + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + group::Curve::to_affine(self).to_bytes() + } +} + impl group::Curve for ProjectivePoint { type AffineRepr = AffinePoint; @@ -699,6 +819,8 @@ impl MulAssign<&Scalar> for ProjectivePoint { } } +impl MulByGenerator for ProjectivePoint {} + impl Neg for ProjectivePoint { type Output = ProjectivePoint; @@ -707,78 +829,6 @@ impl Neg for ProjectivePoint { } } -/// Constant representing the base field modulus -/// p = 2^{224}(2^{32} − 1) + 2^{192} + 2^{96} − 1 -pub const MODULUS: U256 = - U256::from_be_hex("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff"); - -/// Example base field element. -#[derive(Clone, Copy, Debug)] -pub struct FieldElement(pub(crate) U256); - -/// Internal field element representation. -#[cfg(target_pointer_width = "32")] -type FeWords = [u32; 8]; - -/// Internal field element representation. -#[cfg(target_pointer_width = "64")] -type FeWords = [u64; 4]; - -impl_field_element!( - FieldElement, - FieldBytes, - U256, - MODULUS, - FeWords, - p256_from_montgomery, - p256_to_montgomery, - p256_add, - p256_sub, - p256_mul, - p256_opp, - p256_square -); - -impl FieldElement { - /// Returns the multiplicative inverse of self, if self is non-zero. - pub fn invert(&self) -> CtOption<Self> { - unimplemented!() - } - - /// Returns the square root of self mod p, or `None` if no square root exists. - pub fn sqrt(&self) -> CtOption<Self> { - unimplemented!() - } -} - -const fn p256_from_montgomery(_: &FeWords) -> FeWords { - unimplemented!() -} - -const fn p256_to_montgomery(w: &FeWords) -> FeWords { - *w -} - -const fn p256_add(_: &FeWords, _: &FeWords) -> FeWords { - unimplemented!() -} - -const fn p256_sub(_: &FeWords, _: &FeWords) -> FeWords { - unimplemented!() -} - -const fn p256_mul(_: &FeWords, _: &FeWords) -> FeWords { - unimplemented!() -} - -const fn p256_opp(_: &FeWords) -> FeWords { - unimplemented!() -} - -const fn p256_square(_: &FeWords) -> FeWords { - unimplemented!() -} - #[cfg(test)] mod tests { use super::Scalar; diff --git a/vendor/elliptic-curve/src/ecdh.rs b/vendor/elliptic-curve/src/ecdh.rs index 1e9f7bc31..c64a696aa 100644 --- a/vendor/elliptic-curve/src/ecdh.rs +++ b/vendor/elliptic-curve/src/ecdh.rs @@ -1,7 +1,7 @@ //! Elliptic Curve Diffie-Hellman Support. //! //! This module contains a generic ECDH implementation which is usable with -//! any elliptic curve which implements the [`ProjectiveArithmetic`] trait (presently +//! any elliptic curve which implements the [`CurveArithmetic`] trait (presently //! the `k256` and `p256` crates) //! //! # ECDH Ephemeral (ECDHE) Usage @@ -27,14 +27,14 @@ //! [SIGMA]: https://webee.technion.ac.il/~hugo/sigma-pdf.pdf use crate::{ - AffineArithmetic, AffinePoint, AffineXCoordinate, Curve, FieldBytes, NonZeroScalar, - ProjectiveArithmetic, ProjectivePoint, PublicKey, + point::AffineCoordinates, AffinePoint, Curve, CurveArithmetic, FieldBytes, NonZeroScalar, + ProjectivePoint, PublicKey, }; use core::borrow::Borrow; use digest::{crypto_common::BlockSizeUser, Digest}; use group::Curve as _; use hkdf::{hmac::SimpleHmac, Hkdf}; -use rand_core::{CryptoRng, RngCore}; +use rand_core::CryptoRngCore; use zeroize::{Zeroize, ZeroizeOnDrop}; /// Low-level Elliptic Curve Diffie-Hellman (ECDH) function. @@ -62,7 +62,7 @@ pub fn diffie_hellman<C>( public_key: impl Borrow<AffinePoint<C>>, ) -> SharedSecret<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { let public_point = ProjectivePoint::<C>::from(*public_key.borrow()); let secret_point = (public_point * secret_key.borrow().as_ref()).to_affine(); @@ -92,17 +92,17 @@ where /// takes further steps to authenticate the peers in a key exchange. pub struct EphemeralSecret<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { scalar: NonZeroScalar<C>, } impl<C> EphemeralSecret<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { /// Generate a cryptographically random [`EphemeralSecret`]. - pub fn random(rng: impl CryptoRng + RngCore) -> Self { + pub fn random(rng: &mut impl CryptoRngCore) -> Self { Self { scalar: NonZeroScalar::random(rng), } @@ -118,13 +118,13 @@ where /// Compute a Diffie-Hellman shared secret from an ephemeral secret and the /// public key of the other participant in the exchange. pub fn diffie_hellman(&self, public_key: &PublicKey<C>) -> SharedSecret<C> { - diffie_hellman(&self.scalar, public_key.as_affine()) + diffie_hellman(self.scalar, public_key.as_affine()) } } impl<C> From<&EphemeralSecret<C>> for PublicKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { fn from(ephemeral_secret: &EphemeralSecret<C>) -> Self { ephemeral_secret.public_key() @@ -133,18 +133,18 @@ where impl<C> Zeroize for EphemeralSecret<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { fn zeroize(&mut self) { self.scalar.zeroize() } } -impl<C> ZeroizeOnDrop for EphemeralSecret<C> where C: Curve + ProjectiveArithmetic {} +impl<C> ZeroizeOnDrop for EphemeralSecret<C> where C: CurveArithmetic {} impl<C> Drop for EphemeralSecret<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { fn drop(&mut self) { self.zeroize(); @@ -162,7 +162,7 @@ impl<C: Curve> SharedSecret<C> { #[inline] fn new(point: AffinePoint<C>) -> Self where - C: AffineArithmetic, + C: CurveArithmetic, { Self { secret_bytes: point.x(), diff --git a/vendor/elliptic-curve/src/field.rs b/vendor/elliptic-curve/src/field.rs new file mode 100644 index 000000000..66055abc2 --- /dev/null +++ b/vendor/elliptic-curve/src/field.rs @@ -0,0 +1,51 @@ +//! Field elements. + +use crate::{ + bigint::{ArrayEncoding, ByteArray, Integer}, + Curve, +}; +use generic_array::{typenum::Unsigned, GenericArray}; + +/// Size of serialized field elements of this elliptic curve. +pub type FieldBytesSize<C> = <C as Curve>::FieldBytesSize; + +/// Byte representation of a base/scalar field element of a given curve. +pub type FieldBytes<C> = GenericArray<u8, FieldBytesSize<C>>; + +/// Trait for decoding/encoding `Curve::Uint` from/to [`FieldBytes`] using +/// curve-specific rules. +/// +/// Namely a curve's modulus may be smaller than the big integer type used to +/// internally represent field elements (since the latter are multiples of the +/// limb size), such as in the case of curves like NIST P-224 and P-521, and so +/// it may need to be padded/truncated to the right length. +/// +/// Additionally, different curves have different endianness conventions, also +/// captured here. +pub trait FieldBytesEncoding<C>: ArrayEncoding + Integer +where + C: Curve, +{ + /// Decode unsigned integer from serialized field element. + /// + /// The default implementation assumes a big endian encoding. + fn decode_field_bytes(field_bytes: &FieldBytes<C>) -> Self { + debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE); + let mut byte_array = ByteArray::<Self>::default(); + let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len()); + byte_array[offset..].copy_from_slice(field_bytes); + Self::from_be_byte_array(byte_array) + } + + /// Encode unsigned integer into serialized field element. + /// + /// The default implementation assumes a big endian encoding. + fn encode_field_bytes(&self) -> FieldBytes<C> { + let mut field_bytes = FieldBytes::<C>::default(); + debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE); + + let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len()); + field_bytes.copy_from_slice(&self.to_be_byte_array()[offset..]); + field_bytes + } +} diff --git a/vendor/elliptic-curve/src/hash2curve/group_digest.rs b/vendor/elliptic-curve/src/hash2curve/group_digest.rs index dbcb1512b..ea7f0471f 100644 --- a/vendor/elliptic-curve/src/hash2curve/group_digest.rs +++ b/vendor/elliptic-curve/src/hash2curve/group_digest.rs @@ -1,11 +1,11 @@ //! Traits for handling hash to curve. use super::{hash_to_field, ExpandMsg, FromOkm, MapToCurve}; -use crate::{ProjectiveArithmetic, ProjectivePoint, Result}; +use crate::{CurveArithmetic, ProjectivePoint, Result}; use group::cofactor::CofactorGroup; /// Adds hashing arbitrary byte sequences to a valid group element -pub trait GroupDigest: ProjectiveArithmetic +pub trait GroupDigest: CurveArithmetic where ProjectivePoint<Self>: CofactorGroup, { @@ -48,10 +48,10 @@ where /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof fn hash_from_bytes<'a, X: ExpandMsg<'a>>( msgs: &[&[u8]], - dst: &'a [u8], + dsts: &'a [&'a [u8]], ) -> Result<ProjectivePoint<Self>> { let mut u = [Self::FieldElement::default(), Self::FieldElement::default()]; - hash_to_field::<X, _>(msgs, dst, &mut u)?; + hash_to_field::<X, _>(msgs, dsts, &mut u)?; let q0 = u[0].map_to_curve(); let q1 = u[1].map_to_curve(); // Ideally we could add and then clear cofactor once @@ -88,10 +88,10 @@ where /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof fn encode_from_bytes<'a, X: ExpandMsg<'a>>( msgs: &[&[u8]], - dst: &'a [u8], + dsts: &'a [&'a [u8]], ) -> Result<ProjectivePoint<Self>> { let mut u = [Self::FieldElement::default()]; - hash_to_field::<X, _>(msgs, dst, &mut u)?; + hash_to_field::<X, _>(msgs, dsts, &mut u)?; let q0 = u[0].map_to_curve(); Ok(q0.clear_cofactor().into()) } @@ -109,12 +109,15 @@ where /// /// [`ExpandMsgXmd`]: crate::hash2curve::ExpandMsgXmd /// [`ExpandMsgXof`]: crate::hash2curve::ExpandMsgXof - fn hash_to_scalar<'a, X: ExpandMsg<'a>>(msgs: &[&[u8]], dst: &'a [u8]) -> Result<Self::Scalar> + fn hash_to_scalar<'a, X: ExpandMsg<'a>>( + msgs: &[&[u8]], + dsts: &'a [&'a [u8]], + ) -> Result<Self::Scalar> where Self::Scalar: FromOkm, { let mut u = [Self::Scalar::default()]; - hash_to_field::<X, _>(msgs, dst, &mut u)?; + hash_to_field::<X, _>(msgs, dsts, &mut u)?; Ok(u[0]) } } diff --git a/vendor/elliptic-curve/src/hash2curve/hash2field.rs b/vendor/elliptic-curve/src/hash2curve/hash2field.rs index 6cd0723aa..67ede111c 100644 --- a/vendor/elliptic-curve/src/hash2curve/hash2field.rs +++ b/vendor/elliptic-curve/src/hash2curve/hash2field.rs @@ -6,7 +6,7 @@ mod expand_msg; pub use expand_msg::{xmd::*, xof::*, *}; -use crate::Result; +use crate::{Error, Result}; use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; /// The trait for helping to convert to a field element. @@ -32,12 +32,12 @@ pub trait FromOkm { /// [`ExpandMsgXmd`]: crate::hash2field::ExpandMsgXmd /// [`ExpandMsgXof`]: crate::hash2field::ExpandMsgXof #[doc(hidden)] -pub fn hash_to_field<'a, E, T>(data: &[&[u8]], domain: &'a [u8], out: &mut [T]) -> Result<()> +pub fn hash_to_field<'a, E, T>(data: &[&[u8]], domain: &'a [&'a [u8]], out: &mut [T]) -> Result<()> where E: ExpandMsg<'a>, T: FromOkm + Default, { - let len_in_bytes = T::Length::to_usize() * out.len(); + let len_in_bytes = T::Length::to_usize().checked_mul(out.len()).ok_or(Error)?; let mut tmp = GenericArray::<u8, <T as FromOkm>::Length>::default(); let mut expander = E::expand_message(data, domain, len_in_bytes)?; for o in out.iter_mut() { diff --git a/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs index dfb3bab9c..96a659b9a 100644 --- a/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs +++ b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg.rs @@ -25,8 +25,11 @@ pub trait ExpandMsg<'a> { /// /// Returns an expander that can be used to call `read` until enough /// bytes have been consumed - fn expand_message(msgs: &[&[u8]], dst: &'a [u8], len_in_bytes: usize) - -> Result<Self::Expander>; + fn expand_message( + msgs: &[&[u8]], + dsts: &'a [&'a [u8]], + len_in_bytes: usize, + ) -> Result<Self::Expander>; } /// Expander that, call `read` until enough bytes have been consumed. @@ -47,54 +50,66 @@ where /// > 255 Hashed(GenericArray<u8, L>), /// <= 255 - Array(&'a [u8]), + Array(&'a [&'a [u8]]), } impl<'a, L> Domain<'a, L> where L: ArrayLength<u8> + IsLess<U256>, { - pub fn xof<X>(dst: &'a [u8]) -> Result<Self> + pub fn xof<X>(dsts: &'a [&'a [u8]]) -> Result<Self> where X: Default + ExtendableOutput + Update, { - if dst.is_empty() { + if dsts.is_empty() { Err(Error) - } else if dst.len() > MAX_DST_LEN { + } else if dsts.iter().map(|dst| dst.len()).sum::<usize>() > MAX_DST_LEN { let mut data = GenericArray::<u8, L>::default(); - X::default() - .chain(OVERSIZE_DST_SALT) - .chain(dst) - .finalize_xof() - .read(&mut data); + let mut hash = X::default(); + hash.update(OVERSIZE_DST_SALT); + + for dst in dsts { + hash.update(dst); + } + + hash.finalize_xof().read(&mut data); + Ok(Self::Hashed(data)) } else { - Ok(Self::Array(dst)) + Ok(Self::Array(dsts)) } } - pub fn xmd<X>(dst: &'a [u8]) -> Result<Self> + pub fn xmd<X>(dsts: &'a [&'a [u8]]) -> Result<Self> where X: Digest<OutputSize = L>, { - if dst.is_empty() { + if dsts.is_empty() { Err(Error) - } else if dst.len() > MAX_DST_LEN { + } else if dsts.iter().map(|dst| dst.len()).sum::<usize>() > MAX_DST_LEN { Ok(Self::Hashed({ let mut hash = X::new(); hash.update(OVERSIZE_DST_SALT); - hash.update(dst); + + for dst in dsts { + hash.update(dst); + } + hash.finalize() })) } else { - Ok(Self::Array(dst)) + Ok(Self::Array(dsts)) } } - pub fn data(&self) -> &[u8] { + pub fn update_hash<HashT: Update>(&self, hash: &mut HashT) { match self { - Self::Hashed(d) => &d[..], - Self::Array(d) => *d, + Self::Hashed(d) => hash.update(d), + Self::Array(d) => { + for d in d.iter() { + hash.update(d) + } + } } } @@ -103,13 +118,28 @@ where // Can't overflow because it's enforced on a type level. Self::Hashed(_) => L::to_u8(), // Can't overflow because it's checked on creation. - Self::Array(d) => u8::try_from(d.len()).expect("length overflow"), + Self::Array(d) => { + u8::try_from(d.iter().map(|d| d.len()).sum::<usize>()).expect("length overflow") + } } } #[cfg(test)] pub fn assert(&self, bytes: &[u8]) { - assert_eq!(self.data(), &bytes[..bytes.len() - 1]); + let data = match self { + Domain::Hashed(d) => d.to_vec(), + Domain::Array(d) => d.iter().copied().flatten().copied().collect(), + }; + assert_eq!(data, bytes); + } + + #[cfg(test)] + pub fn assert_dst(&self, bytes: &[u8]) { + let data = match self { + Domain::Hashed(d) => d.to_vec(), + Domain::Array(d) => d.iter().copied().flatten().copied().collect(), + }; + assert_eq!(data, &bytes[..bytes.len() - 1]); assert_eq!(self.len(), bytes[bytes.len() - 1]); } } diff --git a/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs index 876b012f5..50edb648b 100644 --- a/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs +++ b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xmd.rs @@ -1,5 +1,8 @@ //! `expand_message_xmd` based on a hash function. +// TODO(tarcieri): checked arithmetic +#![allow(clippy::integer_arithmetic)] + use core::marker::PhantomData; use super::{Domain, ExpandMsg, Expander}; @@ -10,7 +13,7 @@ use digest::{ typenum::{IsLess, IsLessOrEqual, Unsigned, U256}, GenericArray, }, - Digest, + FixedOutput, HashMarker, }; /// Placeholder type for implementing `expand_message_xmd` based on a hash function @@ -22,14 +25,14 @@ use digest::{ /// - `len_in_bytes > 255 * HashT::OutputSize` pub struct ExpandMsgXmd<HashT>(PhantomData<HashT>) where - HashT: Digest + BlockSizeUser, + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess<U256>, HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>; /// ExpandMsgXmd implements expand_message_xmd for the ExpandMsg trait impl<'a, HashT> ExpandMsg<'a> for ExpandMsgXmd<HashT> where - HashT: Digest + BlockSizeUser, + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, // If `len_in_bytes` is bigger then 256, length of the `DST` will depend on // the output size of the hash, which is still not allowed to be bigger then 256: // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-13.html#section-5.4.1-6 @@ -42,7 +45,7 @@ where fn expand_message( msgs: &[&[u8]], - dst: &'a [u8], + dsts: &'a [&'a [u8]], len_in_bytes: usize, ) -> Result<Self::Expander> { if len_in_bytes == 0 { @@ -54,26 +57,26 @@ where let b_in_bytes = HashT::OutputSize::to_usize(); let ell = u8::try_from((len_in_bytes + b_in_bytes - 1) / b_in_bytes).map_err(|_| Error)?; - let domain = Domain::xmd::<HashT>(dst)?; - let mut b_0 = HashT::new(); - b_0.update(GenericArray::<u8, HashT::BlockSize>::default()); + let domain = Domain::xmd::<HashT>(dsts)?; + let mut b_0 = HashT::default(); + b_0.update(&GenericArray::<u8, HashT::BlockSize>::default()); for msg in msgs { b_0.update(msg); } - b_0.update(len_in_bytes_u16.to_be_bytes()); - b_0.update([0]); - b_0.update(domain.data()); - b_0.update([domain.len()]); - let b_0 = b_0.finalize(); + b_0.update(&len_in_bytes_u16.to_be_bytes()); + b_0.update(&[0]); + domain.update_hash(&mut b_0); + b_0.update(&[domain.len()]); + let b_0 = b_0.finalize_fixed(); - let mut b_vals = HashT::new(); + let mut b_vals = HashT::default(); b_vals.update(&b_0[..]); - b_vals.update([1u8]); - b_vals.update(domain.data()); - b_vals.update([domain.len()]); - let b_vals = b_vals.finalize(); + b_vals.update(&[1u8]); + domain.update_hash(&mut b_vals); + b_vals.update(&[domain.len()]); + let b_vals = b_vals.finalize_fixed(); Ok(ExpanderXmd { b_0, @@ -89,7 +92,7 @@ where /// [`Expander`] type for [`ExpandMsgXmd`]. pub struct ExpanderXmd<'a, HashT> where - HashT: Digest + BlockSizeUser, + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess<U256>, HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>, { @@ -103,7 +106,7 @@ where impl<'a, HashT> ExpanderXmd<'a, HashT> where - HashT: Digest + BlockSizeUser, + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess<U256>, HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>, { @@ -118,12 +121,12 @@ where .zip(&self.b_vals[..]) .enumerate() .for_each(|(j, (b0val, bi1val))| tmp[j] = b0val ^ bi1val); - let mut b_vals = HashT::new(); - b_vals.update(tmp); - b_vals.update([self.index]); - b_vals.update(self.domain.data()); - b_vals.update([self.domain.len()]); - self.b_vals = b_vals.finalize(); + let mut b_vals = HashT::default(); + b_vals.update(&tmp); + b_vals.update(&[self.index]); + self.domain.update_hash(&mut b_vals); + b_vals.update(&[self.domain.len()]); + self.b_vals = b_vals.finalize_fixed(); true } else { false @@ -133,7 +136,7 @@ where impl<'a, HashT> Expander for ExpanderXmd<'a, HashT> where - HashT: Digest + BlockSizeUser, + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess<U256>, HashT::OutputSize: IsLessOrEqual<HashT::BlockSize>, { @@ -165,7 +168,7 @@ mod test { len_in_bytes: u16, bytes: &[u8], ) where - HashT: Digest + BlockSizeUser, + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess<U256>, { let block = HashT::BlockSize::to_usize(); @@ -183,8 +186,8 @@ mod test { let pad = l + mem::size_of::<u8>(); assert_eq!([0], &bytes[l..pad]); - let dst = pad + domain.data().len(); - assert_eq!(domain.data(), &bytes[pad..dst]); + let dst = pad + usize::from(domain.len()); + domain.assert(&bytes[pad..dst]); let dst_len = dst + mem::size_of::<u8>(); assert_eq!([domain.len()], &bytes[dst..dst_len]); @@ -205,13 +208,14 @@ mod test { domain: &Domain<'_, HashT::OutputSize>, ) -> Result<()> where - HashT: Digest + BlockSizeUser, + HashT: BlockSizeUser + Default + FixedOutput + HashMarker, HashT::OutputSize: IsLess<U256> + IsLessOrEqual<HashT::BlockSize>, { assert_message::<HashT>(self.msg, domain, L::to_u16(), self.msg_prime); + let dst = [dst]; let mut expander = - ExpandMsgXmd::<HashT>::expand_message(&[self.msg], dst, L::to_usize())?; + ExpandMsgXmd::<HashT>::expand_message(&[self.msg], &dst, L::to_usize())?; let mut uniform_bytes = GenericArray::<u8, L>::default(); expander.fill_bytes(&mut uniform_bytes); @@ -227,8 +231,8 @@ mod test { const DST_PRIME: &[u8] = &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348413235362d31323826"); - let dst_prime = Domain::xmd::<Sha256>(DST)?; - dst_prime.assert(DST_PRIME); + let dst_prime = Domain::xmd::<Sha256>(&[DST])?; + dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { @@ -299,8 +303,8 @@ mod test { const DST_PRIME: &[u8] = &hex!("412717974da474d0f8c420f320ff81e8432adb7c927d9bd082b4fb4d16c0a23620"); - let dst_prime = Domain::xmd::<Sha256>(DST)?; - dst_prime.assert(DST_PRIME); + let dst_prime = Domain::xmd::<Sha256>(&[DST])?; + dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { @@ -377,8 +381,8 @@ mod test { const DST_PRIME: &[u8] = &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348413531322d32353626"); - let dst_prime = Domain::xmd::<Sha512>(DST)?; - dst_prime.assert(DST_PRIME); + let dst_prime = Domain::xmd::<Sha512>(&[DST])?; + dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { diff --git a/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs index 107ac5e06..9a5ff19e9 100644 --- a/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs +++ b/vendor/elliptic-curve/src/hash2curve/hash2field/expand_msg/xof.rs @@ -27,7 +27,7 @@ where fn expand_message( msgs: &[&[u8]], - dst: &'a [u8], + dsts: &'a [&'a [u8]], len_in_bytes: usize, ) -> Result<Self::Expander> { if len_in_bytes == 0 { @@ -36,18 +36,17 @@ where let len_in_bytes = u16::try_from(len_in_bytes).map_err(|_| Error)?; - let domain = Domain::<U32>::xof::<HashT>(dst)?; + let domain = Domain::<U32>::xof::<HashT>(dsts)?; let mut reader = HashT::default(); for msg in msgs { reader = reader.chain(msg); } - let reader = reader - .chain(len_in_bytes.to_be_bytes()) - .chain(domain.data()) - .chain([domain.len()]) - .finalize_xof(); + reader.update(&len_in_bytes.to_be_bytes()); + domain.update_hash(&mut reader); + reader.update(&[domain.len()]); + let reader = reader.finalize_xof(); Ok(Self { reader }) } } @@ -87,8 +86,8 @@ mod test { &bytes[msg_len..len_in_bytes_len] ); - let dst = len_in_bytes_len + domain.data().len(); - assert_eq!(domain.data(), &bytes[len_in_bytes_len..dst]); + let dst = len_in_bytes_len + usize::from(domain.len()); + domain.assert(&bytes[len_in_bytes_len..dst]); let dst_len = dst + mem::size_of::<u8>(); assert_eq!([domain.len()], &bytes[dst..dst_len]); @@ -111,7 +110,7 @@ mod test { assert_message::<HashT>(self.msg, domain, L::to_u16(), self.msg_prime); let mut expander = - ExpandMsgXof::<HashT>::expand_message(&[self.msg], dst, L::to_usize())?; + ExpandMsgXof::<HashT>::expand_message(&[self.msg], &[dst], L::to_usize())?; let mut uniform_bytes = GenericArray::<u8, L>::default(); expander.fill_bytes(&mut uniform_bytes); @@ -127,8 +126,8 @@ mod test { const DST_PRIME: &[u8] = &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348414b4531323824"); - let dst_prime = Domain::<U32>::xof::<Shake128>(DST)?; - dst_prime.assert(DST_PRIME); + let dst_prime = Domain::<U32>::xof::<Shake128>(&[DST])?; + dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { @@ -203,8 +202,8 @@ mod test { const DST_PRIME: &[u8] = &hex!("acb9736c0867fdfbd6385519b90fc8c034b5af04a958973212950132d035792f20"); - let dst_prime = Domain::<U32>::xof::<Shake128>(DST)?; - dst_prime.assert(DST_PRIME); + let dst_prime = Domain::<U32>::xof::<Shake128>(&[DST])?; + dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { @@ -281,8 +280,8 @@ mod test { const DST_PRIME: &[u8] = &hex!("515555582d5630312d435330322d776974682d657870616e6465722d5348414b4532353624"); - let dst_prime = Domain::<U32>::xof::<Shake256>(DST)?; - dst_prime.assert(DST_PRIME); + let dst_prime = Domain::<U32>::xof::<Shake256>(&[DST])?; + dst_prime.assert_dst(DST_PRIME); const TEST_VECTORS_32: &[TestVector] = &[ TestVector { diff --git a/vendor/elliptic-curve/src/hash2curve/isogeny.rs b/vendor/elliptic-curve/src/hash2curve/isogeny.rs index fc197246a..7a28983dd 100644 --- a/vendor/elliptic-curve/src/hash2curve/isogeny.rs +++ b/vendor/elliptic-curve/src/hash2curve/isogeny.rs @@ -26,9 +26,10 @@ pub trait Isogeny: Field + AddAssign + Mul<Output = Self> { const COEFFICIENTS: IsogenyCoefficients<Self>; /// Map from the isogeny points to the main curve + #[allow(clippy::integer_arithmetic)] fn isogeny(x: Self, y: Self) -> (Self, Self) { let mut xs = GenericArray::<Self, Self::Degree>::default(); - xs[0] = Self::one(); + xs[0] = Self::ONE; xs[1] = x; xs[2] = x.square(); for i in 3..Self::Degree::to_usize() { @@ -48,7 +49,7 @@ pub trait Isogeny: Field + AddAssign + Mul<Output = Self> { /// Compute the ISO transform fn compute_iso(xxs: &[Self], k: &[Self]) -> Self { - let mut xx = Self::zero(); + let mut xx = Self::ZERO; for (xi, ki) in xxs.iter().zip(k.iter()) { xx += *xi * ki; } diff --git a/vendor/elliptic-curve/src/hash2curve/osswu.rs b/vendor/elliptic-curve/src/hash2curve/osswu.rs index f803863b1..3c3669ac3 100644 --- a/vendor/elliptic-curve/src/hash2curve/osswu.rs +++ b/vendor/elliptic-curve/src/hash2curve/osswu.rs @@ -1,9 +1,11 @@ //! Optimized simplified Shallue-van de Woestijne-Ulas methods. //! -//! <https://eprint.iacr.org/2009/340.pdf> +//! <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-sswu> use ff::Field; use subtle::Choice; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; /// The Optimized Simplified Shallue-van de Woestijne-Ulas parameters pub struct OsswuMapParams<F> @@ -11,7 +13,7 @@ where F: Field, { /// The first constant term - pub c1: [u64; 4], + pub c1: &'static [u64], /// The second constant term pub c2: F, /// The ISO A variable or Curve A variable @@ -38,50 +40,91 @@ pub trait OsswuMap: Field + Sgn0 { /// should be for isogeny where A≠0 and B≠0. const PARAMS: OsswuMapParams<Self>; + /// Optimized sqrt_ratio for q = 3 mod 4. + fn sqrt_ratio_3mod4(u: Self, v: Self) -> (Choice, Self) { + // 1. tv1 = v^2 + let tv1 = v.square(); + // 2. tv2 = u * v + let tv2 = u * v; + // 3. tv1 = tv1 * tv2 + let tv1 = tv1 * tv2; + // 4. y1 = tv1^c1 + let y1 = tv1.pow_vartime(Self::PARAMS.c1); + // 5. y1 = y1 * tv2 + let y1 = y1 * tv2; + // 6. y2 = y1 * c2 + let y2 = y1 * Self::PARAMS.c2; + // 7. tv3 = y1^2 + let tv3 = y1.square(); + // 8. tv3 = tv3 * v + let tv3 = tv3 * v; + // 9. isQR = tv3 == u + let is_qr = tv3.ct_eq(&u); + // 10. y = CMOV(y2, y1, isQR) + let y = ConditionallySelectable::conditional_select(&y2, &y1, is_qr); + // 11. return (isQR, y) + (is_qr, y) + } + /// Convert this field element into an affine point on the elliptic curve /// returning (X, Y). For Weierstrass curves having A==0 or B==0 /// the result is a point on an isogeny. fn osswu(&self) -> (Self, Self) { - let tv1 = self.square(); // u^2 - let tv3 = Self::PARAMS.z * tv1; // Z * u^2 - let mut tv2 = tv3.square(); // tv3^2 - let mut xd = tv2 + tv3; // tv3^2 + tv3 - let x1n = Self::PARAMS.map_b * (xd + Self::one()); // B * (xd + 1) - xd *= -Self::PARAMS.map_a; // -A * xd - - let tv = Self::PARAMS.z * Self::PARAMS.map_a; - xd.conditional_assign(&tv, xd.is_zero()); - - tv2 = xd.square(); //xd^2 - let gxd = tv2 * xd; // xd^3 - tv2 *= Self::PARAMS.map_a; // A * tv2 - - let mut gx1 = x1n * (tv2 + x1n.square()); //x1n *(tv2 + x1n^2) - tv2 = gxd * Self::PARAMS.map_b; // B * gxd - gx1 += tv2; // gx1 + tv2 - - let mut tv4 = gxd.square(); // gxd^2 - tv2 = gx1 * gxd; // gx1 * gxd - tv4 *= tv2; - - let y1 = tv4.pow_vartime(&Self::PARAMS.c1) * tv2; // tv4^C1 * tv2 - let x2n = tv3 * x1n; // tv3 * x1n - - let y2 = y1 * Self::PARAMS.c2 * tv1 * self; // y1 * c2 * tv1 * u - - tv2 = y1.square() * gxd; //y1^2 * gxd - - let e2 = tv2.ct_eq(&gx1); - - // if e2 , x = x1, else x = x2 - let mut x = Self::conditional_select(&x2n, &x1n, e2); - // xn / xd - x *= xd.invert().unwrap(); - - // if e2, y = y1, else y = y2 - let mut y = Self::conditional_select(&y2, &y1, e2); - - y.conditional_assign(&-y, self.sgn0() ^ y.sgn0()); + // 1. tv1 = u^2 + let tv1 = self.square(); + // 2. tv1 = Z * tv1 + let tv1 = Self::PARAMS.z * tv1; + // 3. tv2 = tv1^2 + let tv2 = tv1.square(); + // 4. tv2 = tv2 + tv1 + let tv2 = tv2 + tv1; + // 5. tv3 = tv2 + 1 + let tv3 = tv2 + Self::ONE; + // 6. tv3 = B * tv3 + let tv3 = Self::PARAMS.map_b * tv3; + // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) + let tv4 = ConditionallySelectable::conditional_select( + &Self::PARAMS.z, + &-tv2, + !Field::is_zero(&tv2), + ); + // 8. tv4 = A * tv4 + let tv4 = Self::PARAMS.map_a * tv4; + // 9. tv2 = tv3^2 + let tv2 = tv3.square(); + // 10. tv6 = tv4^2 + let tv6 = tv4.square(); + // 11. tv5 = A * tv6 + let tv5 = Self::PARAMS.map_a * tv6; + // 12. tv2 = tv2 + tv5 + let tv2 = tv2 + tv5; + // 13. tv2 = tv2 * tv3 + let tv2 = tv2 * tv3; + // 14. tv6 = tv6 * tv4 + let tv6 = tv6 * tv4; + // 15. tv5 = B * tv6 + let tv5 = Self::PARAMS.map_b * tv6; + // 16. tv2 = tv2 + tv5 + let tv2 = tv2 + tv5; + // 17. x = tv1 * tv3 + let x = tv1 * tv3; + // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) + let (is_gx1_square, y1) = Self::sqrt_ratio_3mod4(tv2, tv6); + // 19. y = tv1 * u + let y = tv1 * self; + // 20. y = y * y1 + let y = y * y1; + // 21. x = CMOV(x, tv3, is_gx1_square) + let x = ConditionallySelectable::conditional_select(&x, &tv3, is_gx1_square); + // 22. y = CMOV(y, y1, is_gx1_square) + let y = ConditionallySelectable::conditional_select(&y, &y1, is_gx1_square); + // 23. e1 = sgn0(u) == sgn0(y) + let e1 = self.sgn0().ct_eq(&y.sgn0()); + // 24. y = CMOV(-y, y, e1) + let y = ConditionallySelectable::conditional_select(&-y, &y, e1); + // 25. x = x / tv4 + let x = x * tv4.invert().unwrap(); + // 26. return (x, y) (x, y) } } diff --git a/vendor/elliptic-curve/src/jwk.rs b/vendor/elliptic-curve/src/jwk.rs index ff5e6e638..e0233cc00 100644 --- a/vendor/elliptic-curve/src/jwk.rs +++ b/vendor/elliptic-curve/src/jwk.rs @@ -6,7 +6,7 @@ use crate::{ sec1::{Coordinates, EncodedPoint, ModulusSize, ValidatePublicKey}, secret_key::SecretKey, - Curve, Error, FieldBytes, FieldSize, Result, + Curve, Error, FieldBytes, FieldBytesSize, Result, }; use alloc::{ borrow::ToOwned, @@ -26,7 +26,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::{ public_key::PublicKey, sec1::{FromEncodedPoint, ToEncodedPoint}, - AffinePoint, ProjectiveArithmetic, + AffinePoint, CurveArithmetic, }; /// Key Type (`kty`) for elliptic curve keys. @@ -42,7 +42,6 @@ const JWK_TYPE_NAME: &str = "JwkEcKey"; const FIELDS: &[&str] = &["kty", "crv", "x", "y", "d"]; /// Elliptic curve parameters used by JSON Web Keys. -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] pub trait JwkParameters: Curve { /// The `crv` parameter which identifies a particular elliptic curve /// as defined in RFC 7518 Section 6.2.1.1: @@ -64,7 +63,6 @@ pub trait JwkParameters: Curve { /// [1]: https://tools.ietf.org/html/rfc7518#section-6 // TODO(tarcieri): eagerly decode or validate `x`, `y`, and `d` as Base64 #[derive(Clone)] -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] pub struct JwkEcKey { /// The `crv` parameter which identifies a particular elliptic curve /// as defined in RFC 7518 Section 6.2.1.1: @@ -110,12 +108,11 @@ impl JwkEcKey { /// Decode a JWK into a [`PublicKey`]. #[cfg(feature = "arithmetic")] - #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] pub fn to_public_key<C>(&self) -> Result<PublicKey<C>> where - C: Curve + JwkParameters + ProjectiveArithmetic, + C: CurveArithmetic + JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { PublicKey::from_sec1_bytes(self.to_encoded_point::<C>()?.as_bytes()) } @@ -124,7 +121,7 @@ impl JwkEcKey { pub fn from_encoded_point<C>(point: &EncodedPoint<C>) -> Option<Self> where C: Curve + JwkParameters, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { match point.coordinates() { Coordinates::Uncompressed { x, y } => Some(JwkEcKey { @@ -141,7 +138,7 @@ impl JwkEcKey { pub fn to_encoded_point<C>(&self) -> Result<EncodedPoint<C>> where C: Curve + JwkParameters, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { if self.crv != C::CRV { return Err(Error); @@ -154,11 +151,10 @@ impl JwkEcKey { /// Decode a JWK into a [`SecretKey`]. #[cfg(feature = "arithmetic")] - #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] pub fn to_secret_key<C>(&self) -> Result<SecretKey<C>> where C: Curve + JwkParameters + ValidatePublicKey, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { self.try_into() } @@ -178,11 +174,10 @@ impl ToString for JwkEcKey { } } -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] impl<C> TryFrom<JwkEcKey> for SecretKey<C> where C: Curve + JwkParameters + ValidatePublicKey, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { type Error = Error; @@ -191,11 +186,10 @@ where } } -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] impl<C> TryFrom<&JwkEcKey> for SecretKey<C> where C: Curve + JwkParameters + ValidatePublicKey, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { type Error = Error; @@ -203,7 +197,7 @@ where if let Some(d_base64) = &jwk.d { let pk = jwk.to_encoded_point::<C>()?; let mut d_bytes = decode_base64url_fe::<C>(d_base64)?; - let result = SecretKey::from_be_bytes(&d_bytes); + let result = SecretKey::from_slice(&d_bytes); d_bytes.zeroize(); result.and_then(|secret_key| { @@ -217,13 +211,11 @@ where } #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] impl<C> From<SecretKey<C>> for JwkEcKey where - C: Curve + JwkParameters + ProjectiveArithmetic, + C: CurveArithmetic + JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn from(sk: SecretKey<C>) -> JwkEcKey { (&sk).into() @@ -231,17 +223,15 @@ where } #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] impl<C> From<&SecretKey<C>> for JwkEcKey where - C: Curve + JwkParameters + ProjectiveArithmetic, + C: CurveArithmetic + JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn from(sk: &SecretKey<C>) -> JwkEcKey { let mut jwk = sk.public_key().to_jwk(); - let mut d = sk.to_be_bytes(); + let mut d = sk.to_bytes(); jwk.d = Some(Base64Url::encode_string(&d)); d.zeroize(); jwk @@ -249,13 +239,11 @@ where } #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] impl<C> TryFrom<JwkEcKey> for PublicKey<C> where - C: Curve + JwkParameters + ProjectiveArithmetic, + C: CurveArithmetic + JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { type Error = Error; @@ -265,13 +253,11 @@ where } #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] impl<C> TryFrom<&JwkEcKey> for PublicKey<C> where - C: Curve + JwkParameters + ProjectiveArithmetic, + C: CurveArithmetic + JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { type Error = Error; @@ -281,13 +267,11 @@ where } #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] impl<C> From<PublicKey<C>> for JwkEcKey where - C: Curve + JwkParameters + ProjectiveArithmetic, + C: CurveArithmetic + JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn from(pk: PublicKey<C>) -> JwkEcKey { (&pk).into() @@ -295,13 +279,11 @@ where } #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -#[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] impl<C> From<&PublicKey<C>> for JwkEcKey where - C: Curve + JwkParameters + ProjectiveArithmetic, + C: CurveArithmetic + JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn from(pk: &PublicKey<C>) -> JwkEcKey { Self::from_encoded_point::<C>(&pk.to_encoded_point(false)).expect("JWK encoding error") @@ -458,7 +440,7 @@ impl<'de> Deserialize<'de> for JwkEcKey { .ok_or_else(|| de::Error::invalid_length(0, &DE_ERROR_MSG))?; if kty != EC_KTY { - return Err(de::Error::custom(format!("unsupported JWK kty: {:?}", kty))); + return Err(de::Error::custom(format!("unsupported JWK kty: {kty:?}"))); } let crv = de::SeqAccess::next_element::<String>(&mut seq)? @@ -530,7 +512,7 @@ impl<'de> Deserialize<'de> for JwkEcKey { let kty = kty.ok_or_else(|| de::Error::missing_field("kty"))?; if kty != EC_KTY { - return Err(de::Error::custom(format!("unsupported JWK kty: {}", kty))); + return Err(de::Error::custom(format!("unsupported JWK kty: {kty}"))); } let crv = crv.ok_or_else(|| de::Error::missing_field("crv"))?; diff --git a/vendor/elliptic-curve/src/lib.rs b/vendor/elliptic-curve/src/lib.rs index 62ac7856b..5f2a6c62e 100644 --- a/vendor/elliptic-curve/src/lib.rs +++ b/vendor/elliptic-curve/src/lib.rs @@ -1,12 +1,29 @@ #![no_std] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" )] -#![forbid(unsafe_code, clippy::unwrap_used)] -#![warn(missing_docs, rust_2018_idioms, unused_qualifications)] +#![forbid(unsafe_code)] +#![warn( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + clippy::checked_conversions, + clippy::implicit_saturating_sub, + clippy::integer_arithmetic, + clippy::mod_module_files, + clippy::panic, + clippy::panic_in_result_fn, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] //! ## Usage //! @@ -20,8 +37,10 @@ //! - [`bp256`]: brainpoolP256r1 and brainpoolP256t1 //! - [`bp384`]: brainpoolP384r1 and brainpoolP384t1 //! - [`k256`]: secp256k1 a.k.a. K-256 +//! - [`p224`]: NIST P-224 a.k.a. secp224r1 //! - [`p256`]: NIST P-256 a.k.a secp256r1, prime256v1 //! - [`p384`]: NIST P-384 a.k.a. secp384r1 +//! - [`p521`]: NIST P-521 a.k.a. secp521r1 //! //! The [`ecdsa`] crate provides a generic implementation of the //! Elliptic Curve Digital Signature Algorithm which can be used with any of @@ -42,7 +61,7 @@ //! //! - [`JwkEcKey`] //! - [`PublicKey`] -//! - [`ScalarCore`] +//! - [`ScalarPrimitive`] //! //! Please see type-specific documentation for more information. //! @@ -50,50 +69,37 @@ //! [`bp256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp256 //! [`bp384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/bp384 //! [`k256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/k256 +//! [`p224`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p224 //! [`p256`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p256 //! [`p384`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p384 +//! [`p521`]: https://github.com/RustCrypto/elliptic-curves/tree/master/p521 //! [`ecdsa`]: https://github.com/RustCrypto/signatures/tree/master/ecdsa #[cfg(feature = "alloc")] #[allow(unused_imports)] #[macro_use] extern crate alloc; - #[cfg(feature = "std")] extern crate std; -#[cfg(feature = "rand_core")] -#[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] -pub use rand_core; - -#[macro_use] -mod macros; - -pub mod ops; +pub mod point; +pub mod scalar; #[cfg(feature = "dev")] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] pub mod dev; - #[cfg(feature = "ecdh")] -#[cfg_attr(docsrs, doc(cfg(feature = "ecdh")))] pub mod ecdh; - #[cfg(feature = "hash2curve")] -#[cfg_attr(docsrs, doc(cfg(feature = "hash2curve")))] pub mod hash2curve; - +#[cfg(feature = "arithmetic")] +pub mod ops; #[cfg(feature = "sec1")] -#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] pub mod sec1; - #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] pub mod weierstrass; mod error; -mod point; -mod scalar; +mod field; mod secret_key; #[cfg(feature = "arithmetic")] @@ -104,12 +110,13 @@ mod public_key; #[cfg(feature = "jwk")] mod jwk; +#[cfg(feature = "voprf")] +mod voprf; + pub use crate::{ error::{Error, Result}, - point::{ - AffineXCoordinate, DecompactPoint, DecompressPoint, PointCompaction, PointCompression, - }, - scalar::{core::ScalarCore, IsHigh}, + field::{FieldBytes, FieldBytesEncoding, FieldBytesSize}, + scalar::ScalarPrimitive, secret_key::SecretKey, }; pub use crypto_bigint as bigint; @@ -121,34 +128,35 @@ pub use zeroize; #[cfg(feature = "arithmetic")] pub use { crate::{ - arithmetic::{ - AffineArithmetic, PrimeCurveArithmetic, ProjectiveArithmetic, ScalarArithmetic, - }, + arithmetic::{CurveArithmetic, PrimeCurveArithmetic}, + point::{AffinePoint, ProjectivePoint}, public_key::PublicKey, - scalar::{nonzero::NonZeroScalar, Scalar}, + scalar::{NonZeroScalar, Scalar}, }, ff::{self, Field, PrimeField}, group::{self, Group}, }; -#[cfg(feature = "bits")] -pub use crate::scalar::ScalarBits; - #[cfg(feature = "jwk")] pub use crate::jwk::{JwkEcKey, JwkParameters}; #[cfg(feature = "pkcs8")] pub use pkcs8; -use core::fmt::Debug; -use generic_array::GenericArray; +#[cfg(feature = "voprf")] +pub use crate::voprf::VoprfParameters; + +use core::{ + fmt::Debug, + ops::{Add, ShrAssign}, +}; +use generic_array::ArrayLength; /// Algorithm [`ObjectIdentifier`][`pkcs8::ObjectIdentifier`] for elliptic /// curve public key cryptography (`id-ecPublicKey`). /// /// <http://oid-info.com/get/1.2.840.10045.2.1> #[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] pub const ALGORITHM_OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.2.1"); @@ -161,60 +169,29 @@ pub const ALGORITHM_OID: pkcs8::ObjectIdentifier = /// be impl'd by these ZSTs, facilitating types which are generic over elliptic /// curves (e.g. [`SecretKey`]). pub trait Curve: 'static + Copy + Clone + Debug + Default + Eq + Ord + Send + Sync { + /// Size of a serialized field element in bytes. + /// + /// This is typically the same as `Self::Uint::ByteSize` but for curves + /// with an unusual field modulus (e.g. P-224, P-521) it may be different. + type FieldBytesSize: ArrayLength<u8> + Add + Eq; + /// Integer type used to represent field elements of this elliptic curve. - // TODO(tarcieri): replace this with an e.g. `const Curve::MODULUS: UInt`. - // Requires rust-lang/rust#60551, i.e. `const_evaluatable_checked` - type UInt: bigint::AddMod<Output = Self::UInt> - + bigint::ArrayEncoding + type Uint: bigint::ArrayEncoding + + bigint::AddMod<Output = Self::Uint> + bigint::Encoding + bigint::Integer - + bigint::NegMod<Output = Self::UInt> + + bigint::NegMod<Output = Self::Uint> + bigint::Random + bigint::RandomMod - + bigint::SubMod<Output = Self::UInt> - + zeroize::Zeroize; - - /// Order constant. - /// - /// Subdivided into either 32-bit or 64-bit "limbs" (depending on the - /// target CPU's word size), specified from least to most significant. - const ORDER: Self::UInt; + + bigint::SubMod<Output = Self::Uint> + + zeroize::Zeroize + + FieldBytesEncoding<Self> + + ShrAssign<usize>; + + /// Order of this elliptic curve, i.e. number of elements in the scalar + /// field. + const ORDER: Self::Uint; } /// Marker trait for elliptic curves with prime order. pub trait PrimeCurve: Curve {} - -/// Size of field elements of this elliptic curve. -pub type FieldSize<C> = <<C as Curve>::UInt as bigint::ArrayEncoding>::ByteSize; - -/// Byte representation of a base/scalar field element of a given curve. -pub type FieldBytes<C> = GenericArray<u8, FieldSize<C>>; - -/// Affine point type for a given curve with a [`ProjectiveArithmetic`] -/// implementation. -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -#[cfg(feature = "arithmetic")] -pub type AffinePoint<C> = <C as AffineArithmetic>::AffinePoint; - -/// Projective point type for a given curve with a [`ProjectiveArithmetic`] -/// implementation. -#[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub type ProjectivePoint<C> = <C as ProjectiveArithmetic>::ProjectivePoint; - -/// Elliptic curve parameters used by VOPRF. -#[cfg(feature = "voprf")] -#[cfg_attr(docsrs, doc(cfg(feature = "voprf")))] -pub trait VoprfParameters: Curve { - /// The `ID` parameter which identifies a particular elliptic curve - /// as defined in [section 4 of `draft-irtf-cfrg-voprf-08`][voprf]. - /// - /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-4 - const ID: u16; - - /// The `Hash` parameter which assigns a particular hash function to this - /// ciphersuite as defined in [section 4 of `draft-irtf-cfrg-voprf-08`][voprf]. - /// - /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-4 - type Hash: digest::Digest; -} diff --git a/vendor/elliptic-curve/src/macros.rs b/vendor/elliptic-curve/src/macros.rs deleted file mode 100644 index 6ceadc833..000000000 --- a/vendor/elliptic-curve/src/macros.rs +++ /dev/null @@ -1,440 +0,0 @@ -/// 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_export] -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) -> $crate::subtle::CtOption<Self> { - use $crate::bigint::ArrayEncoding as _; - 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]) -> $crate::Result<Self> { - <$uint as $crate::bigint::Encoding>::Repr::try_from(slice) - .ok() - .and_then(|array| Self::from_be_bytes(array.into()).into()) - .ok_or($crate::Error) - } - - /// Create a [` - #[doc = stringify!($fe)] - /// `] from a canonical little-endian representation. - pub fn from_le_bytes(repr: $bytes) -> $crate::subtle::CtOption<Self> { - use $crate::bigint::ArrayEncoding as _; - 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]) -> $crate::Result<Self> { - <$uint as $crate::bigint::Encoding>::Repr::try_from(slice) - .ok() - .and_then(|array| Self::from_le_bytes(array.into()).into()) - .ok_or($crate::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) -> $crate::subtle::CtOption<Self> { - use $crate::subtle::ConstantTimeLess as _; - let is_some = uint.ct_lt(&$modulus); - $crate::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! - pub(crate) const fn from_uint_unchecked(w: $uint) -> Self { - Self(<$uint>::from_words($to_mont(w.as_words()))) - } - - /// Returns the big-endian encoding of this [` - #[doc = stringify!($fe)] - /// `]. - pub fn to_be_bytes(self) -> $bytes { - use $crate::bigint::ArrayEncoding as _; - self.to_canonical().to_be_byte_array() - } - - /// Returns the little-endian encoding of this [` - #[doc = stringify!($fe)] - /// `]. - pub fn to_le_bytes(self) -> $bytes { - use $crate::bigint::ArrayEncoding as _; - 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_words($from_mont(self.0.as_words())) - } - - /// 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 { - use $crate::bigint::Integer; - self.to_canonical().is_odd() - } - - /// Determine if this [` - #[doc = stringify!($fe)] - /// `] is even in the SEC1 sense: `self mod 2 == 0`. - /// - /// # Returns - /// - /// If even, return `Choice(1)`. Otherwise, return `Choice(0)`. - pub fn is_even(&self) -> Choice { - !self.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_words($add( - self.0.as_words(), - rhs.0.as_words(), - ))) - } - - /// 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_words($sub( - self.0.as_words(), - rhs.0.as_words(), - ))) - } - - /// Multiply elements. - pub const fn mul(&self, rhs: &Self) -> Self { - Self(<$uint>::from_words($mul( - self.0.as_words(), - rhs.0.as_words(), - ))) - } - - /// Negate element. - pub const fn neg(&self) -> Self { - Self(<$uint>::from_words($neg(self.0.as_words()))) - } - - /// Compute modular square. - #[must_use] - pub const fn square(&self) -> Self { - Self(<$uint>::from_words($square(self.0.as_words()))) - } - } - - 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 $crate::subtle::ConditionallySelectable for $fe { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - Self(<$uint>::conditional_select(&a.0, &b.0, choice)) - } - } - - impl $crate::subtle::ConstantTimeEq for $fe { - fn ct_eq(&self, other: &Self) -> $crate::subtle::Choice { - self.0.ct_eq(&other.0) - } - } - - impl $crate::subtle::ConstantTimeGreater for $fe { - fn ct_gt(&self, other: &Self) -> $crate::subtle::Choice { - self.0.ct_gt(&other.0) - } - } - - impl $crate::subtle::ConstantTimeLess for $fe { - fn ct_lt(&self, other: &Self) -> $crate::subtle::Choice { - self.0.ct_lt(&other.0) - } - } - - impl $crate::zeroize::DefaultIsZeroes for $fe {} - - impl $crate::ff::Field for $fe { - fn random(mut rng: impl $crate::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> { - self.invert() - } - - fn sqrt(&self) -> CtOption<Self> { - self.sqrt() - } - } - - $crate::impl_field_op!($fe, $uint, Add, add, $add); - $crate::impl_field_op!($fe, $uint, Sub, sub, $sub); - $crate::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_export] -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()) - } - } - }; -} diff --git a/vendor/elliptic-curve/src/ops.rs b/vendor/elliptic-curve/src/ops.rs index 580c5aefc..b7e9e3d46 100644 --- a/vendor/elliptic-curve/src/ops.rs +++ b/vendor/elliptic-curve/src/ops.rs @@ -1,14 +1,9 @@ //! Traits for arithmetic operations on elliptic curve field elements. -pub use core::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign}; +pub use core::ops::{Add, AddAssign, Mul, Neg, Shr, ShrAssign, Sub, SubAssign}; -use crypto_bigint::{ArrayEncoding, ByteArray, Integer}; - -#[cfg(feature = "arithmetic")] -use {group::Group, subtle::CtOption}; - -#[cfg(feature = "digest")] -use digest::FixedOutput; +use crypto_bigint::Integer; +use group::Group; /// Perform an inversion on a field element (i.e. base field element or scalar) pub trait Invert { @@ -17,14 +12,16 @@ pub trait Invert { /// Invert a field element. fn invert(&self) -> Self::Output; -} - -#[cfg(feature = "arithmetic")] -impl<F: ff::Field> Invert for F { - type Output = CtOption<F>; - fn invert(&self) -> CtOption<F> { - ff::Field::invert(self) + /// Invert a field element in variable time. + /// + /// ⚠️ WARNING! + /// + /// This method should not be used with secret values, as its variable-time + /// operation can potentially leak secrets through sidechannels. + fn invert_vartime(&self) -> Self::Output { + // Fall back on constant-time implementation by default. + self.invert() } } @@ -34,8 +31,6 @@ impl<F: ff::Field> Invert for F { /// linear combinations (e.g. Shamir's Trick), or otherwise provides a default /// non-optimized implementation. // TODO(tarcieri): replace this with a trait from the `group` crate? (see zkcrypto/group#25) -#[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] pub trait LinearCombination: Group { /// Calculates `x * k + y * l`. fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self { @@ -43,44 +38,28 @@ pub trait LinearCombination: Group { } } -/// Modular reduction. -pub trait Reduce<UInt: Integer + ArrayEncoding>: Sized { - /// Perform a modular reduction, returning a field element. - fn from_uint_reduced(n: UInt) -> Self; - - /// Interpret the given byte array as a big endian integer and perform - /// a modular reduction. - fn from_be_bytes_reduced(bytes: ByteArray<UInt>) -> Self { - Self::from_uint_reduced(UInt::from_be_byte_array(bytes)) +/// Multiplication by the generator. +/// +/// May use optimizations (e.g. precomputed tables) when available. +// TODO(tarcieri): replace this with `Group::mul_by_generator``? (see zkcrypto/group#44) +pub trait MulByGenerator: Group { + /// Multiply by the generator of the prime-order subgroup. + #[must_use] + fn mul_by_generator(scalar: &Self::Scalar) -> Self { + Self::generator() * scalar } +} - /// Interpret the given byte array as a little endian integer and perform a - /// modular reduction. - fn from_le_bytes_reduced(bytes: ByteArray<UInt>) -> Self { - Self::from_uint_reduced(UInt::from_le_byte_array(bytes)) - } +/// Modular reduction. +pub trait Reduce<Uint: Integer>: Sized { + /// Bytes used as input to [`Reduce::reduce_bytes`]. + type Bytes: AsRef<[u8]>; - /// Interpret a digest as a big endian integer and perform a modular - /// reduction. - #[cfg(feature = "digest")] - #[cfg_attr(docsrs, doc(cfg(feature = "digest")))] - fn from_be_digest_reduced<D>(digest: D) -> Self - where - D: FixedOutput<OutputSize = UInt::ByteSize>, - { - Self::from_be_bytes_reduced(digest.finalize_fixed()) - } + /// Perform a modular reduction, returning a field element. + fn reduce(n: Uint) -> Self; - /// Interpret a digest as a little endian integer and perform a modular - /// reduction. - #[cfg(feature = "digest")] - #[cfg_attr(docsrs, doc(cfg(feature = "digest")))] - fn from_le_digest_reduced<D>(digest: D) -> Self - where - D: FixedOutput<OutputSize = UInt::ByteSize>, - { - Self::from_le_bytes_reduced(digest.finalize_fixed()) - } + /// Interpret the given bytes as an integer and perform a modular reduction. + fn reduce_bytes(bytes: &Self::Bytes) -> Self; } /// Modular reduction to a non-zero output. @@ -90,7 +69,11 @@ pub trait Reduce<UInt: Integer + ArrayEncoding>: Sized { /// /// End users should use the [`Reduce`] impl on /// [`NonZeroScalar`][`crate::NonZeroScalar`] instead. -pub trait ReduceNonZero<UInt: Integer + ArrayEncoding>: Sized { +pub trait ReduceNonZero<Uint: Integer>: Reduce<Uint> + Sized { /// Perform a modular reduction, returning a field element. - fn from_uint_reduced_nonzero(n: UInt) -> Self; + fn reduce_nonzero(n: Uint) -> Self; + + /// Interpret the given bytes as an integer and perform a modular reduction + /// to a non-zero output. + fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self; } diff --git a/vendor/elliptic-curve/src/point.rs b/vendor/elliptic-curve/src/point.rs index 7257be66c..25b872a0e 100644 --- a/vendor/elliptic-curve/src/point.rs +++ b/vendor/elliptic-curve/src/point.rs @@ -1,12 +1,41 @@ //! Traits for elliptic curve points. +#[cfg(feature = "arithmetic")] +mod non_identity; + +#[cfg(feature = "arithmetic")] +pub use {self::non_identity::NonIdentity, crate::CurveArithmetic}; + use crate::{Curve, FieldBytes}; use subtle::{Choice, CtOption}; -/// Obtain the affine x-coordinate of an elliptic curve point. -pub trait AffineXCoordinate<C: Curve> { +/// Affine point type for a given curve with a [`CurveArithmetic`] +/// implementation. +#[cfg(feature = "arithmetic")] +pub type AffinePoint<C> = <C as CurveArithmetic>::AffinePoint; + +/// Projective point type for a given curve with a [`CurveArithmetic`] +/// implementation. +#[cfg(feature = "arithmetic")] +pub type ProjectivePoint<C> = <C as CurveArithmetic>::ProjectivePoint; + +/// Access to the affine coordinates of an elliptic curve point. +// TODO: use zkcrypto/group#30 coordinate API when available +pub trait AffineCoordinates { + /// Field element representation. + type FieldRepr: AsRef<[u8]>; + /// Get the affine x-coordinate as a serialized field element. - fn x(&self) -> FieldBytes<C>; + fn x(&self) -> Self::FieldRepr; + + /// Is the affine y-coordinate odd? + fn y_is_odd(&self) -> Choice; +} + +/// Double a point (i.e. add it to itself) +pub trait Double { + /// Double this point. + fn double(&self) -> Self; } /// Decompress an elliptic curve point. diff --git a/vendor/elliptic-curve/src/point/non_identity.rs b/vendor/elliptic-curve/src/point/non_identity.rs new file mode 100644 index 000000000..81c31cd19 --- /dev/null +++ b/vendor/elliptic-curve/src/point/non_identity.rs @@ -0,0 +1,237 @@ +//! Non-identity point type. + +use core::ops::{Deref, Mul}; + +use group::{prime::PrimeCurveAffine, Curve, GroupEncoding}; +use rand_core::{CryptoRng, RngCore}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +use crate::{CurveArithmetic, NonZeroScalar, Scalar}; + +/// Non-identity point type. +/// +/// This type ensures that its value is not the identity point, ala `core::num::NonZero*`. +/// +/// In the context of ECC, it's useful for ensuring that certain arithmetic +/// cannot result in the identity point. +#[derive(Clone, Copy)] +pub struct NonIdentity<P> { + point: P, +} + +impl<P> NonIdentity<P> +where + P: ConditionallySelectable + ConstantTimeEq + Default, +{ + /// Create a [`NonIdentity`] from a point. + pub fn new(point: P) -> CtOption<Self> { + CtOption::new(Self { point }, !point.ct_eq(&P::default())) + } + + pub(crate) fn new_unchecked(point: P) -> Self { + Self { point } + } +} + +impl<P> NonIdentity<P> +where + P: ConditionallySelectable + ConstantTimeEq + Default + GroupEncoding, +{ + /// Decode a [`NonIdentity`] from its encoding. + pub fn from_repr(repr: &P::Repr) -> CtOption<Self> { + Self::from_bytes(repr) + } +} + +impl<P: Copy> NonIdentity<P> { + /// Return wrapped point. + pub fn to_point(self) -> P { + self.point + } +} + +impl<P> NonIdentity<P> +where + P: ConditionallySelectable + ConstantTimeEq + Curve + Default, +{ + /// Generate a random `NonIdentity<ProjectivePoint>`. + pub fn random(mut rng: impl CryptoRng + RngCore) -> Self { + loop { + if let Some(point) = Self::new(P::random(&mut rng)).into() { + break point; + } + } + } + + /// Converts this element into its affine representation. + pub fn to_affine(self) -> NonIdentity<P::AffineRepr> { + NonIdentity { + point: self.point.to_affine(), + } + } +} + +impl<P> NonIdentity<P> +where + P: PrimeCurveAffine, +{ + /// Converts this element to its curve representation. + pub fn to_curve(self) -> NonIdentity<P::Curve> { + NonIdentity { + point: self.point.to_curve(), + } + } +} + +impl<P> AsRef<P> for NonIdentity<P> { + fn as_ref(&self) -> &P { + &self.point + } +} + +impl<P> ConditionallySelectable for NonIdentity<P> +where + P: ConditionallySelectable, +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + point: P::conditional_select(&a.point, &b.point, choice), + } + } +} + +impl<P> ConstantTimeEq for NonIdentity<P> +where + P: ConstantTimeEq, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.point.ct_eq(&other.point) + } +} + +impl<P> Deref for NonIdentity<P> { + type Target = P; + + fn deref(&self) -> &Self::Target { + &self.point + } +} + +impl<P> GroupEncoding for NonIdentity<P> +where + P: ConditionallySelectable + ConstantTimeEq + Default + GroupEncoding, +{ + type Repr = P::Repr; + + fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> { + let point = P::from_bytes(bytes); + point.and_then(|point| CtOption::new(Self { point }, !point.ct_eq(&P::default()))) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> { + P::from_bytes_unchecked(bytes).map(|point| Self { point }) + } + + fn to_bytes(&self) -> Self::Repr { + self.point.to_bytes() + } +} + +impl<C, P> Mul<NonZeroScalar<C>> for NonIdentity<P> +where + C: CurveArithmetic, + P: Copy + Mul<Scalar<C>, Output = P>, +{ + type Output = NonIdentity<P>; + + fn mul(self, rhs: NonZeroScalar<C>) -> Self::Output { + &self * &rhs + } +} + +impl<C, P> Mul<&NonZeroScalar<C>> for &NonIdentity<P> +where + C: CurveArithmetic, + P: Copy + Mul<Scalar<C>, Output = P>, +{ + type Output = NonIdentity<P>; + + fn mul(self, rhs: &NonZeroScalar<C>) -> Self::Output { + NonIdentity { + point: self.point * *rhs.as_ref(), + } + } +} + +#[cfg(feature = "serde")] +impl<P> Serialize for NonIdentity<P> +where + P: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + self.point.serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, P> Deserialize<'de> for NonIdentity<P> +where + P: ConditionallySelectable + ConstantTimeEq + Default + Deserialize<'de> + GroupEncoding, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + Option::from(Self::new(P::deserialize(deserializer)?)) + .ok_or_else(|| de::Error::custom("expected non-identity point")) + } +} + +#[cfg(all(test, feature = "dev"))] +mod tests { + use super::NonIdentity; + use crate::dev::{AffinePoint, ProjectivePoint}; + use group::GroupEncoding; + use hex_literal::hex; + + #[test] + fn new_success() { + let point = ProjectivePoint::from_bytes( + &hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721").into(), + ) + .unwrap(); + + assert!(bool::from(NonIdentity::new(point).is_some())); + + assert!(bool::from( + NonIdentity::new(AffinePoint::from(point)).is_some() + )); + } + + #[test] + fn new_fail() { + assert!(bool::from( + NonIdentity::new(ProjectivePoint::default()).is_none() + )); + assert!(bool::from( + NonIdentity::new(AffinePoint::default()).is_none() + )); + } + + #[test] + fn round_trip() { + let bytes = hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let point = NonIdentity::<ProjectivePoint>::from_repr(&bytes.into()).unwrap(); + assert_eq!(&bytes, point.to_bytes().as_slice()); + + let bytes = hex!("02c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let point = NonIdentity::<AffinePoint>::from_repr(&bytes.into()).unwrap(); + assert_eq!(&bytes, point.to_bytes().as_slice()); + } +} diff --git a/vendor/elliptic-curve/src/public_key.rs b/vendor/elliptic-curve/src/public_key.rs index 1dc858581..e2d71b3f0 100644 --- a/vendor/elliptic-curve/src/public_key.rs +++ b/vendor/elliptic-curve/src/public_key.rs @@ -1,19 +1,19 @@ //! Elliptic curve public keys. use crate::{ - AffinePoint, Curve, Error, NonZeroScalar, ProjectiveArithmetic, ProjectivePoint, Result, + point::NonIdentity, AffinePoint, CurveArithmetic, Error, NonZeroScalar, ProjectivePoint, Result, }; use core::fmt::Debug; -use group::{Curve as _, Group}; +use group::{Curve, Group}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; #[cfg(feature = "jwk")] use crate::{JwkEcKey, JwkParameters}; -#[cfg(all(feature = "sec1", feature = "pkcs8"))] -use crate::{ - pkcs8::{self, AssociatedOid, DecodePublicKey}, - ALGORITHM_OID, -}; +#[cfg(feature = "pkcs8")] +use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier}; #[cfg(feature = "pem")] use core::str::FromStr; @@ -21,22 +21,35 @@ use core::str::FromStr; #[cfg(feature = "sec1")] use { crate::{ - sec1::{EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint}, - FieldSize, PointCompression, + point::PointCompression, + sec1::{CompressedPoint, EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint}, + FieldBytesSize, }, core::cmp::Ordering, subtle::CtOption, }; -#[cfg(feature = "serde")] -use serdect::serde::{de, ser, Deserialize, Serialize}; - #[cfg(all(feature = "alloc", feature = "pkcs8"))] use pkcs8::EncodePublicKey; #[cfg(any(feature = "jwk", feature = "pem"))] use alloc::string::{String, ToString}; +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +#[cfg(any(feature = "pem", feature = "serde"))] +use pkcs8::DecodePublicKey; + +#[cfg(all(feature = "sec1", feature = "pkcs8"))] +use { + crate::{ + pkcs8::{self, AssociatedOid}, + ALGORITHM_OID, + }, + pkcs8::der, +}; + /// Elliptic curve public keys. /// /// This is a wrapper type for [`AffinePoint`] which ensures an inner @@ -73,18 +86,17 @@ use alloc::string::{String, ToString}; /// Subject Public Key Info (SPKI) as the encoding format. /// /// For a more text-friendly encoding of public keys, use [`JwkEcKey`] instead. -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] #[derive(Clone, Debug, Eq, PartialEq)] pub struct PublicKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { point: AffinePoint<C>, } impl<C> PublicKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { /// Convert an [`AffinePoint`] into a [`PublicKey`] pub fn from_affine(point: AffinePoint<C>) -> Result<Self> { @@ -113,14 +125,29 @@ where #[cfg(feature = "sec1")] pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> where - C: Curve, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, { let point = EncodedPoint::<C>::from_bytes(bytes).map_err(|_| Error)?; Option::from(Self::from_encoded_point(&point)).ok_or(Error) } + /// Convert this [`PublicKey`] into the + /// `Elliptic-Curve-Point-to-Octet-String` encoding described in + /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section 2.3.3 + /// (page 10). + /// + /// <http://www.secg.org/sec1-v2.pdf> + #[cfg(feature = "alloc")] + pub fn to_sec1_bytes(&self) -> Box<[u8]> + where + C: PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, + { + EncodedPoint::<C>::from(self).to_bytes() + } + /// Borrow the inner [`AffinePoint`] from this [`PublicKey`]. /// /// In ECC, public keys are elliptic curve points. @@ -133,50 +160,51 @@ where self.point.into() } + /// Convert this [`PublicKey`] to a [`NonIdentity`] of the inner [`AffinePoint`] + pub fn to_nonidentity(&self) -> NonIdentity<AffinePoint<C>> { + NonIdentity::new_unchecked(self.point) + } + /// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`PublicKey`]. #[cfg(feature = "jwk")] - #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] pub fn from_jwk(jwk: &JwkEcKey) -> Result<Self> where - C: Curve + JwkParameters, + C: JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { jwk.to_public_key::<C>() } /// Parse a string containing a JSON Web Key (JWK) into a [`PublicKey`]. #[cfg(feature = "jwk")] - #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] pub fn from_jwk_str(jwk: &str) -> Result<Self> where - C: Curve + JwkParameters, + C: JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { jwk.parse::<JwkEcKey>().and_then(|jwk| Self::from_jwk(&jwk)) } /// Serialize this public key as [`JwkEcKey`] JSON Web Key (JWK). #[cfg(feature = "jwk")] - #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] pub fn to_jwk(&self) -> JwkEcKey where - C: Curve + JwkParameters, + C: JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { self.into() } /// Serialize this public key as JSON Web Key (JWK) string. #[cfg(feature = "jwk")] - #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] pub fn to_jwk_string(&self) -> String where - C: Curve + JwkParameters, + C: JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { self.to_jwk().to_string() } @@ -184,22 +212,21 @@ where impl<C> AsRef<AffinePoint<C>> for PublicKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { fn as_ref(&self) -> &AffinePoint<C> { self.as_affine() } } -impl<C> Copy for PublicKey<C> where C: Curve + ProjectiveArithmetic {} +impl<C> Copy for PublicKey<C> where C: CurveArithmetic {} #[cfg(feature = "sec1")] -#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] impl<C> FromEncodedPoint<C> for PublicKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { /// Initialize [`PublicKey`] from an [`EncodedPoint`] fn from_encoded_point(encoded_point: &EncodedPoint<C>) -> CtOption<Self> { @@ -211,12 +238,11 @@ where } #[cfg(feature = "sec1")] -#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] impl<C> ToEncodedPoint<C> for PublicKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { /// Serialize this [`PublicKey`] as a SEC1 [`EncodedPoint`], optionally applying /// point compression @@ -226,12 +252,35 @@ where } #[cfg(feature = "sec1")] -#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] +impl<C> From<PublicKey<C>> for CompressedPoint<C> +where + C: CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn from(public_key: PublicKey<C>) -> CompressedPoint<C> { + CompressedPoint::<C>::from(&public_key) + } +} + +#[cfg(feature = "sec1")] +impl<C> From<&PublicKey<C>> for CompressedPoint<C> +where + C: CurveArithmetic + PointCompression, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, +{ + fn from(public_key: &PublicKey<C>) -> CompressedPoint<C> { + CompressedPoint::<C>::clone_from_slice(public_key.to_encoded_point(true).as_bytes()) + } +} + +#[cfg(feature = "sec1")] impl<C> From<PublicKey<C>> for EncodedPoint<C> where - C: Curve + ProjectiveArithmetic + PointCompression, + C: CurveArithmetic + PointCompression, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn from(public_key: PublicKey<C>) -> EncodedPoint<C> { EncodedPoint::<C>::from(&public_key) @@ -239,25 +288,63 @@ where } #[cfg(feature = "sec1")] -#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] impl<C> From<&PublicKey<C>> for EncodedPoint<C> where - C: Curve + ProjectiveArithmetic + PointCompression, + C: CurveArithmetic + PointCompression, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn from(public_key: &PublicKey<C>) -> EncodedPoint<C> { public_key.to_encoded_point(C::COMPRESS_POINTS) } } +impl<C, P> From<NonIdentity<P>> for PublicKey<C> +where + C: CurveArithmetic, + P: Copy + Into<AffinePoint<C>>, +{ + fn from(value: NonIdentity<P>) -> Self { + Self::from(&value) + } +} + +impl<C, P> From<&NonIdentity<P>> for PublicKey<C> +where + C: CurveArithmetic, + P: Copy + Into<AffinePoint<C>>, +{ + fn from(value: &NonIdentity<P>) -> Self { + Self { + point: value.to_point().into(), + } + } +} + +impl<C> From<PublicKey<C>> for NonIdentity<AffinePoint<C>> +where + C: CurveArithmetic, +{ + fn from(value: PublicKey<C>) -> Self { + Self::from(&value) + } +} + +impl<C> From<&PublicKey<C>> for NonIdentity<AffinePoint<C>> +where + C: CurveArithmetic, +{ + fn from(value: &PublicKey<C>) -> Self { + PublicKey::to_nonidentity(value) + } +} + #[cfg(feature = "sec1")] -#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] impl<C> PartialOrd for PublicKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) @@ -265,12 +352,11 @@ where } #[cfg(feature = "sec1")] -#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] impl<C> Ord for PublicKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn cmp(&self, other: &Self) -> Ordering { // TODO(tarcieri): more efficient implementation? @@ -280,64 +366,136 @@ where } } -#[cfg(all(feature = "pkcs8", feature = "sec1"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "pkcs8", feature = "sec1"))))] -impl<C> TryFrom<pkcs8::SubjectPublicKeyInfo<'_>> for PublicKey<C> +#[cfg(feature = "sec1")] +impl<C> TryFrom<CompressedPoint<C>> for PublicKey<C> +where + C: CurveArithmetic, + FieldBytesSize<C>: ModulusSize, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, +{ + type Error = Error; + + fn try_from(point: CompressedPoint<C>) -> Result<Self> { + Self::from_sec1_bytes(&point) + } +} + +#[cfg(feature = "sec1")] +impl<C> TryFrom<&CompressedPoint<C>> for PublicKey<C> +where + C: CurveArithmetic, + FieldBytesSize<C>: ModulusSize, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, +{ + type Error = Error; + + fn try_from(point: &CompressedPoint<C>) -> Result<Self> { + Self::from_sec1_bytes(point) + } +} + +#[cfg(feature = "sec1")] +impl<C> TryFrom<EncodedPoint<C>> for PublicKey<C> where - C: Curve + AssociatedOid + ProjectiveArithmetic, + C: CurveArithmetic, + FieldBytesSize<C>: ModulusSize, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, +{ + type Error = Error; + + fn try_from(point: EncodedPoint<C>) -> Result<Self> { + Self::from_sec1_bytes(point.as_bytes()) + } +} + +#[cfg(feature = "sec1")] +impl<C> TryFrom<&EncodedPoint<C>> for PublicKey<C> +where + C: CurveArithmetic, + FieldBytesSize<C>: ModulusSize, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, +{ + type Error = Error; + + fn try_from(point: &EncodedPoint<C>) -> Result<Self> { + Self::from_sec1_bytes(point.as_bytes()) + } +} + +#[cfg(feature = "pkcs8")] +impl<C> AssociatedAlgorithmIdentifier for PublicKey<C> +where + C: AssociatedOid + CurveArithmetic, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> = AlgorithmIdentifier { + oid: ALGORITHM_OID, + parameters: Some(C::OID), + }; +} + +#[cfg(feature = "pkcs8")] +impl<C> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for PublicKey<C> +where + C: AssociatedOid + CurveArithmetic, + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, + FieldBytesSize<C>: ModulusSize, { type Error = pkcs8::spki::Error; - fn try_from(spki: pkcs8::SubjectPublicKeyInfo<'_>) -> pkcs8::spki::Result<Self> { - spki.algorithm.assert_oids(ALGORITHM_OID, C::OID)?; - Self::from_sec1_bytes(spki.subject_public_key) - .map_err(|_| der::Tag::BitString.value_error().into()) + fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> { + Self::try_from(&spki) } } -#[cfg(all(feature = "pkcs8", feature = "sec1"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "pkcs8", feature = "sec1"))))] -impl<C> DecodePublicKey for PublicKey<C> +#[cfg(feature = "pkcs8")] +impl<C> TryFrom<&pkcs8::SubjectPublicKeyInfoRef<'_>> for PublicKey<C> where - C: Curve + AssociatedOid + ProjectiveArithmetic, + C: AssociatedOid + CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { + type Error = pkcs8::spki::Error; + + fn try_from(spki: &pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> { + spki.algorithm.assert_oids(ALGORITHM_OID, C::OID)?; + + let public_key_bytes = spki + .subject_public_key + .as_bytes() + .ok_or_else(|| der::Tag::BitString.value_error())?; + + Self::from_sec1_bytes(public_key_bytes) + .map_err(|_| der::Tag::BitString.value_error().into()) + } } #[cfg(all(feature = "alloc", feature = "pkcs8"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs8"))))] impl<C> EncodePublicKey for PublicKey<C> where - C: Curve + AssociatedOid + ProjectiveArithmetic, + C: AssociatedOid + CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn to_public_key_der(&self) -> pkcs8::spki::Result<der::Document> { - let algorithm = pkcs8::AlgorithmIdentifier { - oid: ALGORITHM_OID, - parameters: Some((&C::OID).into()), - }; - let public_key_bytes = self.to_encoded_point(false); + let subject_public_key = der::asn1::BitStringRef::new(0, public_key_bytes.as_bytes())?; pkcs8::SubjectPublicKeyInfo { - algorithm, - subject_public_key: public_key_bytes.as_ref(), + algorithm: Self::ALGORITHM_IDENTIFIER, + subject_public_key, } .try_into() } } #[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] impl<C> FromStr for PublicKey<C> where - C: Curve + AssociatedOid + ProjectiveArithmetic, + C: AssociatedOid + CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { type Err = Error; @@ -347,12 +505,11 @@ where } #[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] impl<C> ToString for PublicKey<C> where - C: Curve + AssociatedOid + ProjectiveArithmetic, + C: AssociatedOid + CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn to_string(&self) -> String { self.to_public_key_pem(Default::default()) @@ -361,12 +518,11 @@ where } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<C> Serialize for PublicKey<C> where - C: Curve + AssociatedOid + ProjectiveArithmetic, + C: AssociatedOid + CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> where @@ -378,12 +534,11 @@ where } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de, C> Deserialize<'de> for PublicKey<C> where - C: Curve + AssociatedOid + ProjectiveArithmetic, + C: AssociatedOid + CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> where diff --git a/vendor/elliptic-curve/src/scalar.rs b/vendor/elliptic-curve/src/scalar.rs index 72d796847..eb992493a 100644 --- a/vendor/elliptic-curve/src/scalar.rs +++ b/vendor/elliptic-curve/src/scalar.rs @@ -1,25 +1,46 @@ //! Scalar types. -use subtle::Choice; - -pub(crate) mod core; +#[cfg(feature = "arithmetic")] +mod blinded; +#[cfg(feature = "arithmetic")] +mod nonzero; +mod primitive; +pub use self::primitive::ScalarPrimitive; #[cfg(feature = "arithmetic")] -pub(crate) mod nonzero; +pub use self::{blinded::BlindedScalar, nonzero::NonZeroScalar}; + +use crypto_bigint::Integer; +use subtle::Choice; #[cfg(feature = "arithmetic")] -use crate::ScalarArithmetic; +use crate::CurveArithmetic; /// Scalar field element for a particular elliptic curve. #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub type Scalar<C> = <C as ScalarArithmetic>::Scalar; +pub type Scalar<C> = <C as CurveArithmetic>::Scalar; /// Bit representation of a scalar field element of a given curve. #[cfg(feature = "bits")] -#[cfg_attr(docsrs, doc(cfg(feature = "bits")))] pub type ScalarBits<C> = ff::FieldBits<<Scalar<C> as ff::PrimeFieldBits>::ReprBits>; +/// Instantiate a scalar from an unsigned integer without checking for overflow. +pub trait FromUintUnchecked { + /// Unsigned integer type (i.e. `Curve::Uint`) + type Uint: Integer; + + /// Instantiate scalar from an unsigned integer without checking + /// whether the value overflows the field modulus. + /// + /// ⚠️ WARNING! + /// + /// Incorrectly used this can lead to mathematically invalid results, + /// which can lead to potential security vulnerabilities. + /// + /// Use with care! + fn from_uint_unchecked(uint: Self::Uint) -> Self; +} + /// Is this scalar greater than n / 2? /// /// # Returns diff --git a/vendor/elliptic-curve/src/scalar/blinded.rs b/vendor/elliptic-curve/src/scalar/blinded.rs new file mode 100644 index 000000000..29cfea98c --- /dev/null +++ b/vendor/elliptic-curve/src/scalar/blinded.rs @@ -0,0 +1,74 @@ +//! Random blinding support for [`Scalar`] + +use super::Scalar; +use crate::{ops::Invert, CurveArithmetic}; +use group::ff::Field; +use rand_core::CryptoRngCore; +use subtle::CtOption; +use zeroize::Zeroize; + +/// Scalar blinded with a randomly generated masking value. +/// +/// This provides a randomly blinded impl of [`Invert`] which is useful for +/// e.g. ECDSA ephemeral (`k`) scalars. +/// +/// It implements masked variable-time inversions using Stein's algorithm, which +/// may be helpful for performance on embedded platforms. +#[derive(Clone)] +pub struct BlindedScalar<C> +where + C: CurveArithmetic, +{ + /// Actual scalar value. + scalar: Scalar<C>, + + /// Mask value. + mask: Scalar<C>, +} + +impl<C> BlindedScalar<C> +where + C: CurveArithmetic, +{ + /// Create a new [`BlindedScalar`] from a scalar and a [`CryptoRngCore`]. + pub fn new(scalar: Scalar<C>, rng: &mut impl CryptoRngCore) -> Self { + Self { + scalar, + mask: Scalar::<C>::random(rng), + } + } +} + +impl<C> AsRef<Scalar<C>> for BlindedScalar<C> +where + C: CurveArithmetic, +{ + fn as_ref(&self) -> &Scalar<C> { + &self.scalar + } +} + +impl<C> Invert for BlindedScalar<C> +where + C: CurveArithmetic, +{ + type Output = CtOption<Scalar<C>>; + + fn invert(&self) -> CtOption<Scalar<C>> { + // prevent side channel analysis of scalar inversion by pre-and-post-multiplying + // with the random masking scalar + (self.scalar * self.mask) + .invert_vartime() + .map(|s| s * self.mask) + } +} + +impl<C> Drop for BlindedScalar<C> +where + C: CurveArithmetic, +{ + fn drop(&mut self) { + self.scalar.zeroize(); + self.mask.zeroize(); + } +} diff --git a/vendor/elliptic-curve/src/scalar/nonzero.rs b/vendor/elliptic-curve/src/scalar/nonzero.rs index 7450537a9..c0e45740f 100644 --- a/vendor/elliptic-curve/src/scalar/nonzero.rs +++ b/vendor/elliptic-curve/src/scalar/nonzero.rs @@ -1,11 +1,9 @@ //! Non-zero scalar type. use crate::{ - bigint::Encoding as _, ops::{Invert, Reduce, ReduceNonZero}, - rand_core::{CryptoRng, RngCore}, - Curve, Error, FieldBytes, IsHigh, PrimeCurve, Result, Scalar, ScalarArithmetic, ScalarCore, - SecretKey, + scalar::IsHigh, + CurveArithmetic, Error, FieldBytes, PrimeCurve, Scalar, ScalarPrimitive, SecretKey, }; use base16ct::HexDisplay; use core::{ @@ -15,10 +13,14 @@ use core::{ }; use crypto_bigint::{ArrayEncoding, Integer}; use ff::{Field, PrimeField}; -use generic_array::GenericArray; +use generic_array::{typenum::Unsigned, GenericArray}; +use rand_core::CryptoRngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use zeroize::Zeroize; +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + /// Non-zero scalar type. /// /// This type ensures that its value is not zero, ala `core::num::NonZero*`. @@ -27,21 +29,20 @@ use zeroize::Zeroize; /// /// In the context of ECC, it's useful for ensuring that scalar multiplication /// cannot result in the point at infinity. -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] #[derive(Clone)] pub struct NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { scalar: Scalar<C>, } impl<C> NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { /// Generate a random `NonZeroScalar`. - pub fn random(mut rng: impl CryptoRng + RngCore) -> Self { + pub fn random(mut rng: &mut impl CryptoRngCore) -> Self { // Use rejection sampling to eliminate zero values. // While this method isn't constant-time, the attacker shouldn't learn // anything about unrelated outputs so long as `rng` is a secure `CryptoRng`. @@ -62,15 +63,15 @@ where Scalar::<C>::from_repr(repr).and_then(Self::new) } - /// Create a [`NonZeroScalar`] from a `C::UInt`. - pub fn from_uint(uint: C::UInt) -> CtOption<Self> { - ScalarCore::new(uint).and_then(|scalar| Self::new(scalar.into())) + /// Create a [`NonZeroScalar`] from a `C::Uint`. + pub fn from_uint(uint: C::Uint) -> CtOption<Self> { + ScalarPrimitive::new(uint).and_then(|scalar| Self::new(scalar.into())) } } impl<C> AsRef<Scalar<C>> for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn as_ref(&self) -> &Scalar<C> { &self.scalar @@ -79,7 +80,7 @@ where impl<C> ConditionallySelectable for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self { @@ -90,18 +91,18 @@ where impl<C> ConstantTimeEq for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn ct_eq(&self, other: &Self) -> Choice { self.scalar.ct_eq(&other.scalar) } } -impl<C> Copy for NonZeroScalar<C> where C: Curve + ScalarArithmetic {} +impl<C> Copy for NonZeroScalar<C> where C: CurveArithmetic {} impl<C> Deref for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { type Target = Scalar<C>; @@ -112,7 +113,7 @@ where impl<C> From<NonZeroScalar<C>> for FieldBytes<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn from(scalar: NonZeroScalar<C>) -> FieldBytes<C> { Self::from(&scalar) @@ -121,34 +122,35 @@ where impl<C> From<&NonZeroScalar<C>> for FieldBytes<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn from(scalar: &NonZeroScalar<C>) -> FieldBytes<C> { scalar.to_repr() } } -impl<C> From<NonZeroScalar<C>> for ScalarCore<C> +impl<C> From<NonZeroScalar<C>> for ScalarPrimitive<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { - fn from(scalar: NonZeroScalar<C>) -> ScalarCore<C> { - ScalarCore::from_be_bytes(scalar.to_repr()).unwrap() + #[inline] + fn from(scalar: NonZeroScalar<C>) -> ScalarPrimitive<C> { + Self::from(&scalar) } } -impl<C> From<&NonZeroScalar<C>> for ScalarCore<C> +impl<C> From<&NonZeroScalar<C>> for ScalarPrimitive<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { - fn from(scalar: &NonZeroScalar<C>) -> ScalarCore<C> { - ScalarCore::from_be_bytes(scalar.to_repr()).unwrap() + fn from(scalar: &NonZeroScalar<C>) -> ScalarPrimitive<C> { + ScalarPrimitive::from_bytes(&scalar.to_repr()).unwrap() } } impl<C> From<SecretKey<C>> for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn from(sk: SecretKey<C>) -> NonZeroScalar<C> { Self::from(&sk) @@ -157,10 +159,10 @@ where impl<C> From<&SecretKey<C>> for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn from(sk: &SecretKey<C>) -> NonZeroScalar<C> { - let scalar = sk.as_scalar_core().to_scalar(); + let scalar = sk.as_scalar_primitive().to_scalar(); debug_assert!(!bool::from(scalar.is_zero())); Self { scalar } } @@ -168,21 +170,29 @@ where impl<C> Invert for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, + Scalar<C>: Invert<Output = CtOption<Scalar<C>>>, { type Output = Self; fn invert(&self) -> Self { Self { // This will always succeed since `scalar` will never be 0 - scalar: ff::Field::invert(&self.scalar).unwrap(), + scalar: Invert::invert(&self.scalar).unwrap(), + } + } + + fn invert_vartime(&self) -> Self::Output { + Self { + // This will always succeed since `scalar` will never be 0 + scalar: Invert::invert_vartime(&self.scalar).unwrap(), } } } impl<C> IsHigh for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn is_high(&self) -> Choice { self.scalar.is_high() @@ -191,7 +201,7 @@ where impl<C> Neg for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { type Output = NonZeroScalar<C>; @@ -204,7 +214,7 @@ where impl<C> Mul<NonZeroScalar<C>> for NonZeroScalar<C> where - C: PrimeCurve + ScalarArithmetic, + C: PrimeCurve + CurveArithmetic, { type Output = Self; @@ -216,7 +226,7 @@ where impl<C> Mul<&NonZeroScalar<C>> for NonZeroScalar<C> where - C: PrimeCurve + ScalarArithmetic, + C: PrimeCurve + CurveArithmetic, { type Output = Self; @@ -229,39 +239,53 @@ where } } -/// Note: implementation is the same as `ReduceNonZero` +/// Note: this is a non-zero reduction, as it's impl'd for [`NonZeroScalar`]. impl<C, I> Reduce<I> for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, I: Integer + ArrayEncoding, - Scalar<C>: ReduceNonZero<I>, + Scalar<C>: Reduce<I> + ReduceNonZero<I>, { - fn from_uint_reduced(n: I) -> Self { - Self::from_uint_reduced_nonzero(n) + type Bytes = <Scalar<C> as Reduce<I>>::Bytes; + + fn reduce(n: I) -> Self { + let scalar = Scalar::<C>::reduce_nonzero(n); + debug_assert!(!bool::from(scalar.is_zero())); + Self { scalar } + } + + fn reduce_bytes(bytes: &Self::Bytes) -> Self { + let scalar = Scalar::<C>::reduce_nonzero_bytes(bytes); + debug_assert!(!bool::from(scalar.is_zero())); + Self { scalar } } } +/// Note: forwards to the [`Reduce`] impl. impl<C, I> ReduceNonZero<I> for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + Self: Reduce<I>, + C: CurveArithmetic, I: Integer + ArrayEncoding, - Scalar<C>: ReduceNonZero<I>, + Scalar<C>: Reduce<I, Bytes = Self::Bytes> + ReduceNonZero<I>, { - fn from_uint_reduced_nonzero(n: I) -> Self { - let scalar = Scalar::<C>::from_uint_reduced_nonzero(n); - debug_assert!(!bool::from(scalar.is_zero())); - Self::new(scalar).unwrap() + fn reduce_nonzero(n: I) -> Self { + Self::reduce(n) + } + + fn reduce_nonzero_bytes(bytes: &Self::Bytes) -> Self { + Self::reduce_bytes(bytes) } } impl<C> TryFrom<&[u8]> for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { type Error = Error; - fn try_from(bytes: &[u8]) -> Result<Self> { - if bytes.len() == C::UInt::BYTE_SIZE { + fn try_from(bytes: &[u8]) -> Result<Self, Error> { + if bytes.len() == C::FieldBytesSize::USIZE { Option::from(NonZeroScalar::from_repr(GenericArray::clone_from_slice( bytes, ))) @@ -274,7 +298,7 @@ where impl<C> Zeroize for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn zeroize(&mut self) { // Use zeroize's volatile writes to ensure value is cleared. @@ -282,22 +306,22 @@ where // Write a 1 instead of a 0 to ensure this type's non-zero invariant // is upheld. - self.scalar = Scalar::<C>::one(); + self.scalar = Scalar::<C>::ONE; } } impl<C> fmt::Display for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:X}", self) + write!(f, "{self:X}") } } impl<C> fmt::LowerHex for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:x}", HexDisplay(&self.to_repr())) @@ -306,7 +330,7 @@ where impl<C> fmt::UpperHex for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:}", HexDisplay(&self.to_repr())) @@ -315,11 +339,11 @@ where impl<C> str::FromStr for NonZeroScalar<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { type Err = Error; - fn from_str(hex: &str) -> Result<Self> { + fn from_str(hex: &str) -> Result<Self, Error> { let mut bytes = FieldBytes::<C>::default(); if base16ct::mixed::decode(hex, &mut bytes)?.len() == bytes.len() { @@ -330,6 +354,34 @@ where } } +#[cfg(feature = "serde")] +impl<C> Serialize for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + ScalarPrimitive::from(self).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + let scalar = ScalarPrimitive::deserialize(deserializer)?; + Option::from(Self::new(scalar.into())) + .ok_or_else(|| de::Error::custom("expected non-zero scalar")) + } +} + #[cfg(all(test, feature = "dev"))] mod tests { use crate::dev::{NonZeroScalar, Scalar}; @@ -348,6 +400,6 @@ mod tests { fn zeroize() { let mut scalar = NonZeroScalar::new(Scalar::from(42u64)).unwrap(); scalar.zeroize(); - assert_eq!(*scalar, Scalar::one()); + assert_eq!(*scalar, Scalar::ONE); } } diff --git a/vendor/elliptic-curve/src/scalar/core.rs b/vendor/elliptic-curve/src/scalar/primitive.rs index 6a088ca55..a4f64cb58 100644 --- a/vendor/elliptic-curve/src/scalar/core.rs +++ b/vendor/elliptic-curve/src/scalar/primitive.rs @@ -1,34 +1,33 @@ -//! Generic scalar type with core functionality. +//! Generic scalar type with primitive functionality. use crate::{ bigint::{prelude::*, Limb, NonZero}, - rand_core::{CryptoRng, RngCore}, - subtle::{ - Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, - CtOption, - }, - Curve, Error, FieldBytes, IsHigh, Result, + scalar::FromUintUnchecked, + scalar::IsHigh, + Curve, Error, FieldBytes, FieldBytesEncoding, Result, }; use base16ct::HexDisplay; use core::{ cmp::Ordering, fmt, - ops::{Add, AddAssign, Neg, Sub, SubAssign}, + ops::{Add, AddAssign, Neg, ShrAssign, Sub, SubAssign}, str, }; -use generic_array::GenericArray; +use generic_array::{typenum::Unsigned, GenericArray}; +use rand_core::CryptoRngCore; +use subtle::{ + Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, + CtOption, +}; use zeroize::DefaultIsZeroes; #[cfg(feature = "arithmetic")] -use { - super::{Scalar, ScalarArithmetic}, - group::ff::PrimeField, -}; +use super::{CurveArithmetic, Scalar}; #[cfg(feature = "serde")] use serdect::serde::{de, ser, Deserialize, Serialize}; -/// Generic scalar type with core functionality. +/// Generic scalar type with primitive functionality. /// /// This type provides a baseline level of scalar arithmetic functionality /// which is always available for all curves, regardless of if they implement @@ -41,73 +40,58 @@ use serdect::serde::{de, ser, Deserialize, Serialize}; /// /// The serialization is a fixed-width big endian encoding. When used with /// textual formats, the binary data is encoded as hexadecimal. -// TODO(tarcieri): make this a fully generic `Scalar` type and use it for `ScalarArithmetic` +// TODO(tarcieri): use `crypto-bigint`'s `Residue` type, expose more functionality? #[derive(Copy, Clone, Debug, Default)] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -pub struct ScalarCore<C: Curve> { +pub struct ScalarPrimitive<C: Curve> { /// Inner unsigned integer type. - inner: C::UInt, + inner: C::Uint, } -impl<C> ScalarCore<C> +impl<C> ScalarPrimitive<C> where C: Curve, { /// Zero scalar. pub const ZERO: Self = Self { - inner: C::UInt::ZERO, + inner: C::Uint::ZERO, }; /// Multiplicative identity. pub const ONE: Self = Self { - inner: C::UInt::ONE, + inner: C::Uint::ONE, }; /// Scalar modulus. - pub const MODULUS: C::UInt = C::ORDER; + pub const MODULUS: C::Uint = C::ORDER; - /// Generate a random [`ScalarCore`]. - pub fn random(rng: impl CryptoRng + RngCore) -> Self { + /// Generate a random [`ScalarPrimitive`]. + pub fn random(rng: &mut impl CryptoRngCore) -> Self { Self { - inner: C::UInt::random_mod(rng, &NonZero::new(Self::MODULUS).unwrap()), + inner: C::Uint::random_mod(rng, &NonZero::new(Self::MODULUS).unwrap()), } } - /// Create a new scalar from [`Curve::UInt`]. - pub fn new(uint: C::UInt) -> CtOption<Self> { + /// Create a new scalar from [`Curve::Uint`]. + pub fn new(uint: C::Uint) -> CtOption<Self> { CtOption::new(Self { inner: uint }, uint.ct_lt(&Self::MODULUS)) } - /// Decode [`ScalarCore`] from big endian bytes. - pub fn from_be_bytes(bytes: FieldBytes<C>) -> CtOption<Self> { - Self::new(C::UInt::from_be_byte_array(bytes)) + /// Decode [`ScalarPrimitive`] from a serialized field element + pub fn from_bytes(bytes: &FieldBytes<C>) -> CtOption<Self> { + Self::new(C::Uint::decode_field_bytes(bytes)) } - /// Decode [`ScalarCore`] from a big endian byte slice. - pub fn from_be_slice(slice: &[u8]) -> Result<Self> { - if slice.len() == C::UInt::BYTE_SIZE { - Option::from(Self::from_be_bytes(GenericArray::clone_from_slice(slice))).ok_or(Error) + /// Decode [`ScalarPrimitive`] from a big endian byte slice. + pub fn from_slice(slice: &[u8]) -> Result<Self> { + if slice.len() == C::FieldBytesSize::USIZE { + Option::from(Self::from_bytes(GenericArray::from_slice(slice))).ok_or(Error) } else { Err(Error) } } - /// Decode [`ScalarCore`] from little endian bytes. - pub fn from_le_bytes(bytes: FieldBytes<C>) -> CtOption<Self> { - Self::new(C::UInt::from_le_byte_array(bytes)) - } - - /// Decode [`ScalarCore`] from a little endian byte slice. - pub fn from_le_slice(slice: &[u8]) -> Result<Self> { - if slice.len() == C::UInt::BYTE_SIZE { - Option::from(Self::from_le_bytes(GenericArray::clone_from_slice(slice))).ok_or(Error) - } else { - Err(Error) - } - } - - /// Borrow the inner `C::UInt`. - pub fn as_uint(&self) -> &C::UInt { + /// Borrow the inner `C::Uint`. + pub fn as_uint(&self) -> &C::Uint { &self.inner } @@ -116,46 +100,56 @@ where self.inner.as_ref() } - /// Is this [`ScalarCore`] value equal to zero? + /// Is this [`ScalarPrimitive`] value equal to zero? pub fn is_zero(&self) -> Choice { self.inner.is_zero() } - /// Is this [`ScalarCore`] value even? + /// Is this [`ScalarPrimitive`] value even? pub fn is_even(&self) -> Choice { self.inner.is_even() } - /// Is this [`ScalarCore`] value odd? + /// Is this [`ScalarPrimitive`] value odd? pub fn is_odd(&self) -> Choice { self.inner.is_odd() } - /// Encode [`ScalarCore`] as big endian bytes. - pub fn to_be_bytes(self) -> FieldBytes<C> { - self.inner.to_be_byte_array() + /// Encode [`ScalarPrimitive`] as a serialized field element. + pub fn to_bytes(&self) -> FieldBytes<C> { + self.inner.encode_field_bytes() + } + + /// Convert to a `C::Uint`. + pub fn to_uint(&self) -> C::Uint { + self.inner } +} + +impl<C> FromUintUnchecked for ScalarPrimitive<C> +where + C: Curve, +{ + type Uint = C::Uint; - /// Encode [`ScalarCore`] as little endian bytes. - pub fn to_le_bytes(self) -> FieldBytes<C> { - self.inner.to_le_byte_array() + fn from_uint_unchecked(uint: C::Uint) -> Self { + Self { inner: uint } } } #[cfg(feature = "arithmetic")] -impl<C> ScalarCore<C> +impl<C> ScalarPrimitive<C> where - C: Curve + ScalarArithmetic, + C: CurveArithmetic, { - /// Convert [`ScalarCore`] into a given curve's scalar type - // TODO(tarcieri): replace curve-specific scalars with `ScalarCore` + /// Convert [`ScalarPrimitive`] into a given curve's scalar type. pub(super) fn to_scalar(self) -> Scalar<C> { - Scalar::<C>::from_repr(self.to_be_bytes()).unwrap() + Scalar::<C>::from_uint_unchecked(self.inner) } } // TODO(tarcieri): better encapsulate this? -impl<C> AsRef<[Limb]> for ScalarCore<C> +impl<C> AsRef<[Limb]> for ScalarPrimitive<C> where C: Curve, { @@ -164,18 +158,18 @@ where } } -impl<C> ConditionallySelectable for ScalarCore<C> +impl<C> ConditionallySelectable for ScalarPrimitive<C> where C: Curve, { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self { - inner: C::UInt::conditional_select(&a.inner, &b.inner, choice), + inner: C::Uint::conditional_select(&a.inner, &b.inner, choice), } } } -impl<C> ConstantTimeEq for ScalarCore<C> +impl<C> ConstantTimeEq for ScalarPrimitive<C> where C: Curve, { @@ -184,7 +178,7 @@ where } } -impl<C> ConstantTimeLess for ScalarCore<C> +impl<C> ConstantTimeLess for ScalarPrimitive<C> where C: Curve, { @@ -193,7 +187,7 @@ where } } -impl<C> ConstantTimeGreater for ScalarCore<C> +impl<C> ConstantTimeGreater for ScalarPrimitive<C> where C: Curve, { @@ -202,11 +196,11 @@ where } } -impl<C: Curve> DefaultIsZeroes for ScalarCore<C> {} +impl<C: Curve> DefaultIsZeroes for ScalarPrimitive<C> {} -impl<C: Curve> Eq for ScalarCore<C> {} +impl<C: Curve> Eq for ScalarPrimitive<C> {} -impl<C> PartialEq for ScalarCore<C> +impl<C> PartialEq for ScalarPrimitive<C> where C: Curve, { @@ -215,7 +209,7 @@ where } } -impl<C> PartialOrd for ScalarCore<C> +impl<C> PartialOrd for ScalarPrimitive<C> where C: Curve, { @@ -224,7 +218,7 @@ where } } -impl<C> Ord for ScalarCore<C> +impl<C> Ord for ScalarPrimitive<C> where C: Curve, { @@ -233,18 +227,18 @@ where } } -impl<C> From<u64> for ScalarCore<C> +impl<C> From<u64> for ScalarPrimitive<C> where C: Curve, { fn from(n: u64) -> Self { Self { - inner: C::UInt::from(n), + inner: C::Uint::from(n), } } } -impl<C> Add<ScalarCore<C>> for ScalarCore<C> +impl<C> Add<ScalarPrimitive<C>> for ScalarPrimitive<C> where C: Curve, { @@ -255,7 +249,7 @@ where } } -impl<C> Add<&ScalarCore<C>> for ScalarCore<C> +impl<C> Add<&ScalarPrimitive<C>> for ScalarPrimitive<C> where C: Curve, { @@ -268,7 +262,7 @@ where } } -impl<C> AddAssign<ScalarCore<C>> for ScalarCore<C> +impl<C> AddAssign<ScalarPrimitive<C>> for ScalarPrimitive<C> where C: Curve, { @@ -277,7 +271,7 @@ where } } -impl<C> AddAssign<&ScalarCore<C>> for ScalarCore<C> +impl<C> AddAssign<&ScalarPrimitive<C>> for ScalarPrimitive<C> where C: Curve, { @@ -286,7 +280,7 @@ where } } -impl<C> Sub<ScalarCore<C>> for ScalarCore<C> +impl<C> Sub<ScalarPrimitive<C>> for ScalarPrimitive<C> where C: Curve, { @@ -297,7 +291,7 @@ where } } -impl<C> Sub<&ScalarCore<C>> for ScalarCore<C> +impl<C> Sub<&ScalarPrimitive<C>> for ScalarPrimitive<C> where C: Curve, { @@ -310,7 +304,7 @@ where } } -impl<C> SubAssign<ScalarCore<C>> for ScalarCore<C> +impl<C> SubAssign<ScalarPrimitive<C>> for ScalarPrimitive<C> where C: Curve, { @@ -319,7 +313,7 @@ where } } -impl<C> SubAssign<&ScalarCore<C>> for ScalarCore<C> +impl<C> SubAssign<&ScalarPrimitive<C>> for ScalarPrimitive<C> where C: Curve, { @@ -328,7 +322,7 @@ where } } -impl<C> Neg for ScalarCore<C> +impl<C> Neg for ScalarPrimitive<C> where C: Curve, { @@ -341,18 +335,27 @@ where } } -impl<C> Neg for &ScalarCore<C> +impl<C> Neg for &ScalarPrimitive<C> where C: Curve, { - type Output = ScalarCore<C>; + type Output = ScalarPrimitive<C>; - fn neg(self) -> ScalarCore<C> { + fn neg(self) -> ScalarPrimitive<C> { -*self } } -impl<C> IsHigh for ScalarCore<C> +impl<C> ShrAssign<usize> for ScalarPrimitive<C> +where + C: Curve, +{ + fn shr_assign(&mut self, rhs: usize) { + self.inner >>= rhs; + } +} + +impl<C> IsHigh for ScalarPrimitive<C> where C: Curve, { @@ -362,34 +365,34 @@ where } } -impl<C> fmt::Display for ScalarCore<C> +impl<C> fmt::Display for ScalarPrimitive<C> where C: Curve, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:X}", self) + write!(f, "{self:X}") } } -impl<C> fmt::LowerHex for ScalarCore<C> +impl<C> fmt::LowerHex for ScalarPrimitive<C> where C: Curve, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:x}", HexDisplay(&self.to_be_bytes())) + write!(f, "{:x}", HexDisplay(&self.to_bytes())) } } -impl<C> fmt::UpperHex for ScalarCore<C> +impl<C> fmt::UpperHex for ScalarPrimitive<C> where C: Curve, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:X}", HexDisplay(&self.to_be_bytes())) + write!(f, "{:X}", HexDisplay(&self.to_bytes())) } } -impl<C> str::FromStr for ScalarCore<C> +impl<C> str::FromStr for ScalarPrimitive<C> where C: Curve, { @@ -398,13 +401,12 @@ where fn from_str(hex: &str) -> Result<Self> { let mut bytes = FieldBytes::<C>::default(); base16ct::lower::decode(hex, &mut bytes)?; - Option::from(Self::from_be_bytes(bytes)).ok_or(Error) + Self::from_slice(&bytes) } } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] -impl<C> Serialize for ScalarCore<C> +impl<C> Serialize for ScalarPrimitive<C> where C: Curve, { @@ -412,13 +414,12 @@ where where S: ser::Serializer, { - serdect::array::serialize_hex_upper_or_bin(&self.to_be_bytes(), serializer) + serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer) } } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] -impl<'de, C> Deserialize<'de> for ScalarCore<C> +impl<'de, C> Deserialize<'de> for ScalarPrimitive<C> where C: Curve, { @@ -428,7 +429,6 @@ where { let mut bytes = FieldBytes::<C>::default(); serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; - Option::from(Self::from_be_bytes(bytes)) - .ok_or_else(|| de::Error::custom("scalar out of range")) + Self::from_slice(&bytes).map_err(|_| de::Error::custom("scalar out of range")) } } diff --git a/vendor/elliptic-curve/src/sec1.rs b/vendor/elliptic-curve/src/sec1.rs index 3e1635941..7673386b8 100644 --- a/vendor/elliptic-curve/src/sec1.rs +++ b/vendor/elliptic-curve/src/sec1.rs @@ -4,27 +4,27 @@ pub use sec1::point::{Coordinates, ModulusSize, Tag}; -use crate::{Curve, FieldSize, Result, SecretKey}; +use crate::{Curve, FieldBytesSize, Result, SecretKey}; use generic_array::GenericArray; use subtle::CtOption; #[cfg(feature = "arithmetic")] -use crate::{AffinePoint, Error, ProjectiveArithmetic}; +use crate::{AffinePoint, CurveArithmetic, Error}; /// Encoded elliptic curve point with point compression. pub type CompressedPoint<C> = GenericArray<u8, CompressedPointSize<C>>; /// Size of a compressed elliptic curve point. -pub type CompressedPointSize<C> = <FieldSize<C> as ModulusSize>::CompressedPointSize; +pub type CompressedPointSize<C> = <FieldBytesSize<C> as ModulusSize>::CompressedPointSize; /// Encoded elliptic curve point sized appropriately for a given curve. -pub type EncodedPoint<C> = sec1::point::EncodedPoint<FieldSize<C>>; +pub type EncodedPoint<C> = sec1::point::EncodedPoint<FieldBytesSize<C>>; /// Encoded elliptic curve point *without* point compression. pub type UncompressedPoint<C> = GenericArray<u8, UncompressedPointSize<C>>; /// Size of an uncompressed elliptic curve point. -pub type UncompressedPointSize<C> = <FieldSize<C> as ModulusSize>::UncompressedPointSize; +pub type UncompressedPointSize<C> = <FieldBytesSize<C> as ModulusSize>::UncompressedPointSize; /// Trait for deserializing a value from a SEC1 encoded curve point. /// @@ -33,7 +33,7 @@ pub trait FromEncodedPoint<C> where Self: Sized, C: Curve, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { /// Deserialize the type this trait is impl'd on from an [`EncodedPoint`]. fn from_encoded_point(point: &EncodedPoint<C>) -> CtOption<Self>; @@ -45,7 +45,7 @@ where pub trait ToEncodedPoint<C> where C: Curve, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { /// Serialize this value as a SEC1 [`EncodedPoint`], optionally applying /// point compression. @@ -58,7 +58,7 @@ where pub trait ToCompactEncodedPoint<C> where C: Curve, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { /// Serialize this value as a SEC1 [`EncodedPoint`], optionally applying /// point compression. @@ -68,12 +68,12 @@ where /// Validate that the given [`EncodedPoint`] represents the encoded public key /// value of the given secret. /// -/// Curve implementations which also impl [`ProjectiveArithmetic`] will receive +/// Curve implementations which also impl [`CurveArithmetic`] will receive /// a blanket default impl of this trait. pub trait ValidatePublicKey where Self: Curve, - FieldSize<Self>: ModulusSize, + FieldBytesSize<Self>: ModulusSize, { /// Validate that the given [`EncodedPoint`] is a valid public key for the /// provided secret value. @@ -96,9 +96,9 @@ where #[cfg(all(feature = "arithmetic"))] impl<C> ValidatePublicKey for C where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn validate_public_key(secret_key: &SecretKey<C>, public_key: &EncodedPoint<C>) -> Result<()> { let pk = secret_key diff --git a/vendor/elliptic-curve/src/secret_key.rs b/vendor/elliptic-curve/src/secret_key.rs index 0fc3dafb1..97b3d58bd 100644 --- a/vendor/elliptic-curve/src/secret_key.rs +++ b/vendor/elliptic-curve/src/secret_key.rs @@ -8,10 +8,9 @@ #[cfg(all(feature = "pkcs8", feature = "sec1"))] mod pkcs8; -use crate::{Curve, Error, FieldBytes, Result, ScalarCore}; +use crate::{Curve, Error, FieldBytes, Result, ScalarPrimitive}; use core::fmt::{self, Debug}; -use crypto_bigint::Encoding; -use generic_array::GenericArray; +use generic_array::typenum::Unsigned; use subtle::{Choice, ConstantTimeEq}; use zeroize::{Zeroize, ZeroizeOnDrop}; @@ -22,19 +21,21 @@ use { AffinePoint, }, alloc::vec::Vec, - der::Encode, zeroize::Zeroizing, }; #[cfg(feature = "arithmetic")] -use crate::{ - rand_core::{CryptoRng, RngCore}, - NonZeroScalar, ProjectiveArithmetic, PublicKey, -}; +use crate::{rand_core::CryptoRngCore, CurveArithmetic, NonZeroScalar, PublicKey}; #[cfg(feature = "jwk")] use crate::jwk::{JwkEcKey, JwkParameters}; +#[cfg(feature = "sec1")] +use sec1::der; + +#[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))] +use sec1::der::Encode; + #[cfg(all(feature = "arithmetic", any(feature = "jwk", feature = "pem")))] use alloc::string::String; @@ -47,10 +48,10 @@ use pem_rfc7468 as pem; #[cfg(feature = "sec1")] use crate::{ sec1::{EncodedPoint, ModulusSize, ValidatePublicKey}, - FieldSize, + FieldBytesSize, }; -#[cfg(all(docsrs, feature = "pkcs8"))] +#[cfg(all(doc, feature = "pkcs8"))] use {crate::pkcs8::DecodePrivateKey, core::str::FromStr}; /// Type label for PEM-encoded SEC1 private keys. @@ -83,7 +84,7 @@ pub(crate) const SEC1_PEM_TYPE_LABEL: &str = "EC PRIVATE KEY"; #[derive(Clone)] pub struct SecretKey<C: Curve> { /// Scalar value - inner: ScalarCore<C>, + inner: ScalarPrimitive<C>, } impl<C> SecretKey<C> @@ -92,10 +93,9 @@ where { /// Generate a random [`SecretKey`]. #[cfg(feature = "arithmetic")] - #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] - pub fn random(rng: impl CryptoRng + RngCore) -> Self + pub fn random(rng: &mut impl CryptoRngCore) -> Self where - C: ProjectiveArithmetic, + C: CurveArithmetic, { Self { inner: NonZeroScalar::<C>::random(rng).into(), @@ -103,18 +103,18 @@ where } /// Create a new secret key from a scalar value. - pub fn new(scalar: ScalarCore<C>) -> Self { + pub fn new(scalar: ScalarPrimitive<C>) -> Self { Self { inner: scalar } } - /// Borrow the inner secret [`ScalarCore`] value. + /// Borrow the inner secret [`ScalarPrimitive`] value. /// /// # ⚠️ Warning /// /// This value is key material. /// /// Please treat it with the care it deserves! - pub fn as_scalar_core(&self) -> &ScalarCore<C> { + pub fn as_scalar_primitive(&self) -> &ScalarPrimitive<C> { &self.inner } @@ -126,54 +126,75 @@ where /// /// Please treat it with the care it deserves! #[cfg(feature = "arithmetic")] - #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] pub fn to_nonzero_scalar(&self) -> NonZeroScalar<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { self.into() } /// Get the [`PublicKey`] which corresponds to this secret key #[cfg(feature = "arithmetic")] - #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] pub fn public_key(&self) -> PublicKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { PublicKey::from_secret_scalar(&self.to_nonzero_scalar()) } - /// Deserialize raw secret scalar as a big endian integer. - pub fn from_be_bytes(bytes: &[u8]) -> Result<Self> { - if bytes.len() != C::UInt::BYTE_SIZE { + /// Deserialize secret key from an encoded secret scalar. + pub fn from_bytes(bytes: &FieldBytes<C>) -> Result<Self> { + let inner: ScalarPrimitive<C> = + Option::from(ScalarPrimitive::from_bytes(bytes)).ok_or(Error)?; + + if inner.is_zero().into() { return Err(Error); } - let inner: ScalarCore<C> = Option::from(ScalarCore::from_be_bytes( - GenericArray::clone_from_slice(bytes), - )) - .ok_or(Error)?; + Ok(Self { inner }) + } - if inner.is_zero().into() { + /// Deserialize secret key from an encoded secret scalar passed as a + /// byte slice. + /// + /// The slice is expected to be at most `C::FieldBytesSize` bytes in + /// length but may be up to 4-bytes shorter than that, which is handled by + /// zero-padding the value. + pub fn from_slice(slice: &[u8]) -> Result<Self> { + if slice.len() > C::FieldBytesSize::USIZE { return Err(Error); } - Ok(Self { inner }) + /// Maximum number of "missing" bytes to interpret as zeroes. + const MAX_LEADING_ZEROES: usize = 4; + + let offset = C::FieldBytesSize::USIZE.saturating_sub(slice.len()); + + if offset == 0 { + Self::from_bytes(FieldBytes::<C>::from_slice(slice)) + } else if offset <= MAX_LEADING_ZEROES { + let mut bytes = FieldBytes::<C>::default(); + bytes[offset..].copy_from_slice(slice); + + let ret = Self::from_bytes(&bytes); + bytes.zeroize(); + ret + } else { + Err(Error) + } } /// Serialize raw secret scalar as a big endian integer. - pub fn to_be_bytes(&self) -> FieldBytes<C> { - self.inner.to_be_bytes() + pub fn to_bytes(&self) -> FieldBytes<C> { + self.inner.to_bytes() } /// Deserialize secret key encoded in the SEC1 ASN.1 DER `ECPrivateKey` format. #[cfg(all(feature = "sec1"))] - #[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] pub fn from_sec1_der(der_bytes: &[u8]) -> Result<Self> where C: Curve + ValidatePublicKey, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { sec1::EcPrivateKey::try_from(der_bytes)? .try_into() @@ -182,18 +203,13 @@ where /// Serialize secret key in the SEC1 ASN.1 DER `ECPrivateKey` format. #[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))) - )] pub fn to_sec1_der(&self) -> der::Result<Zeroizing<Vec<u8>>> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { - // TODO(tarcieri): wrap `secret_key_bytes` in `Zeroizing` - let mut private_key_bytes = self.to_be_bytes(); + let private_key_bytes = Zeroizing::new(self.to_bytes()); let public_key_bytes = self.public_key().to_encoded_point(false); let ec_private_key = Zeroizing::new( @@ -202,12 +218,9 @@ where parameters: None, public_key: Some(public_key_bytes.as_bytes()), } - .to_vec()?, + .to_der()?, ); - // TODO(tarcieri): wrap `private_key_bytes` in `Zeroizing` - private_key_bytes.zeroize(); - Ok(ec_private_key) } @@ -219,11 +232,10 @@ where /// -----BEGIN EC PRIVATE KEY----- /// ``` #[cfg(feature = "pem")] - #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] pub fn from_sec1_pem(s: &str) -> Result<Self> where C: Curve + ValidatePublicKey, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { let (label, der_bytes) = pem::decode_vec(s.as_bytes()).map_err(|_| Error)?; @@ -231,7 +243,7 @@ where return Err(Error); } - Self::from_sec1_der(&*der_bytes).map_err(|_| Error) + Self::from_sec1_der(&der_bytes).map_err(|_| Error) } /// Serialize private key as self-zeroizing PEM-encoded SEC1 `ECPrivateKey` @@ -239,12 +251,11 @@ where /// /// Pass `Default::default()` to use the OS's native line endings. #[cfg(feature = "pem")] - #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] - pub fn to_pem(&self, line_ending: pem::LineEnding) -> Result<Zeroizing<String>> + pub fn to_sec1_pem(&self, line_ending: pem::LineEnding) -> Result<Zeroizing<String>> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { self.to_sec1_der() .ok() @@ -255,48 +266,42 @@ where /// Parse a [`JwkEcKey`] JSON Web Key (JWK) into a [`SecretKey`]. #[cfg(feature = "jwk")] - #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] pub fn from_jwk(jwk: &JwkEcKey) -> Result<Self> where C: JwkParameters + ValidatePublicKey, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { Self::try_from(jwk) } /// Parse a string containing a JSON Web Key (JWK) into a [`SecretKey`]. #[cfg(feature = "jwk")] - #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] pub fn from_jwk_str(jwk: &str) -> Result<Self> where C: JwkParameters + ValidatePublicKey, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { jwk.parse::<JwkEcKey>().and_then(|jwk| Self::from_jwk(&jwk)) } /// Serialize this secret key as [`JwkEcKey`] JSON Web Key (JWK). #[cfg(all(feature = "arithmetic", feature = "jwk"))] - #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] - #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] pub fn to_jwk(&self) -> JwkEcKey where - C: Curve + JwkParameters + ProjectiveArithmetic, + C: CurveArithmetic + JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { self.into() } /// Serialize this secret key as JSON Web Key (JWK) string. #[cfg(all(feature = "arithmetic", feature = "jwk"))] - #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] - #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))] pub fn to_jwk_string(&self) -> Zeroizing<String> where - C: Curve + JwkParameters + ProjectiveArithmetic, + C: CurveArithmetic + JwkParameters, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { Zeroizing::new(self.to_jwk().to_string()) } @@ -316,8 +321,8 @@ where C: Curve, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // TODO(tarcieri): use `debug_struct` and `finish_non_exhaustive` when stable - write!(f, "SecretKey<{:?}>{{ ... }}", C::default()) + f.debug_struct(core::any::type_name::<Self>()) + .finish_non_exhaustive() } } @@ -344,16 +349,15 @@ where } #[cfg(all(feature = "sec1"))] -#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))] impl<C> TryFrom<sec1::EcPrivateKey<'_>> for SecretKey<C> where C: Curve + ValidatePublicKey, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { type Error = der::Error; fn try_from(sec1_private_key: sec1::EcPrivateKey<'_>) -> der::Result<Self> { - let secret_key = Self::from_be_bytes(sec1_private_key.private_key) + let secret_key = Self::from_slice(sec1_private_key.private_key) .map_err(|_| der::Tag::Sequence.value_error())?; // TODO(tarcieri): validate `sec1_private_key.params`? @@ -371,10 +375,9 @@ where } #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] impl<C> From<NonZeroScalar<C>> for SecretKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { fn from(scalar: NonZeroScalar<C>) -> SecretKey<C> { SecretKey::from(&scalar) @@ -382,10 +385,9 @@ where } #[cfg(feature = "arithmetic")] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] impl<C> From<&NonZeroScalar<C>> for SecretKey<C> where - C: Curve + ProjectiveArithmetic, + C: CurveArithmetic, { fn from(scalar: &NonZeroScalar<C>) -> SecretKey<C> { SecretKey { diff --git a/vendor/elliptic-curve/src/secret_key/pkcs8.rs b/vendor/elliptic-curve/src/secret_key/pkcs8.rs index 3c1a509bf..92c81f18a 100644 --- a/vendor/elliptic-curve/src/secret_key/pkcs8.rs +++ b/vendor/elliptic-curve/src/secret_key/pkcs8.rs @@ -2,22 +2,21 @@ use super::SecretKey; use crate::{ - pkcs8::{self, AssociatedOid, DecodePrivateKey}, + pkcs8::{self, der::Decode, AssociatedOid}, sec1::{ModulusSize, ValidatePublicKey}, - Curve, FieldSize, ALGORITHM_OID, + Curve, FieldBytesSize, ALGORITHM_OID, }; -use der::Decode; +use pkcs8::spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, ObjectIdentifier}; use sec1::EcPrivateKey; // Imports for the `EncodePrivateKey` impl -// TODO(tarcieri): use weak activation of `pkcs8/alloc` for gating `EncodePrivateKey` impl -#[cfg(all(feature = "arithmetic", feature = "pem"))] +#[cfg(all(feature = "alloc", feature = "arithmetic"))] use { crate::{ sec1::{FromEncodedPoint, ToEncodedPoint}, - AffinePoint, ProjectiveArithmetic, + AffinePoint, CurveArithmetic, }, - pkcs8::EncodePrivateKey, + pkcs8::{der, EncodePrivateKey}, }; // Imports for actual PEM support @@ -25,13 +24,25 @@ use { use { crate::{error::Error, Result}, core::str::FromStr, + pkcs8::DecodePrivateKey, }; -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] +impl<C> AssociatedAlgorithmIdentifier for SecretKey<C> +where + C: AssociatedOid + Curve, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> = AlgorithmIdentifier { + oid: ALGORITHM_OID, + parameters: Some(C::OID), + }; +} + impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SecretKey<C> where - C: Curve + AssociatedOid + ValidatePublicKey, - FieldSize<C>: ModulusSize, + C: AssociatedOid + Curve + ValidatePublicKey, + FieldBytesSize<C>: ModulusSize, { type Error = pkcs8::Error; @@ -45,28 +56,16 @@ where } } -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] -impl<C> DecodePrivateKey for SecretKey<C> -where - C: Curve + AssociatedOid + ValidatePublicKey, - FieldSize<C>: ModulusSize, -{ -} - -// TODO(tarcieri): use weak activation of `pkcs8/alloc` for this when possible -// It doesn't strictly depend on `pkcs8/pem` but we can't easily activate `pkcs8/alloc` -// without adding a separate crate feature just for this functionality. -#[cfg(all(feature = "arithmetic", feature = "pem"))] -#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +#[cfg(all(feature = "alloc", feature = "arithmetic"))] impl<C> EncodePrivateKey for SecretKey<C> where - C: Curve + AssociatedOid + ProjectiveArithmetic, + C: AssociatedOid + CurveArithmetic, AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { fn to_pkcs8_der(&self) -> pkcs8::Result<der::SecretDocument> { - let algorithm_identifier = pkcs8::AlgorithmIdentifier { + // TODO(tarcieri): make `PrivateKeyInfo` generic around `Params` + let algorithm_identifier = pkcs8::AlgorithmIdentifierRef { oid: ALGORITHM_OID, parameters: Some((&C::OID).into()), }; @@ -78,11 +77,10 @@ where } #[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] impl<C> FromStr for SecretKey<C> where C: Curve + AssociatedOid + ValidatePublicKey, - FieldSize<C>: ModulusSize, + FieldBytesSize<C>: ModulusSize, { type Err = Error; diff --git a/vendor/elliptic-curve/src/voprf.rs b/vendor/elliptic-curve/src/voprf.rs new file mode 100644 index 000000000..68f2abf18 --- /dev/null +++ b/vendor/elliptic-curve/src/voprf.rs @@ -0,0 +1,20 @@ +//! Verifiable Oblivious Pseudorandom Function (VOPRF) using prime order groups +//! +//! <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/> + +use crate::PrimeCurve; + +/// Elliptic curve parameters used by VOPRF. +pub trait VoprfParameters: PrimeCurve { + /// The `ID` parameter which identifies a particular elliptic curve + /// as defined in [section 4 of `draft-irtf-cfrg-voprf-19`][voprf]. + /// + /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#name-ciphersuites-2 + const ID: &'static str; + + /// The `Hash` parameter which assigns a particular hash function to this + /// ciphersuite as defined in [section 4 of `draft-irtf-cfrg-voprf-19`][voprf]. + /// + /// [voprf]: https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html#name-ciphersuites-2 + type Hash: digest::Digest; +} |