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