//! Development-related functionality. //! //! Helpers and types for writing tests against concrete implementations of //! the traits in this crate. use crate::{ bigint::{Limb, U256}, error::{Error, Result}, ops::{LinearCombination, Reduce}, pkcs8, rand_core::RngCore, sec1::{FromEncodedPoint, ToEncodedPoint}, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, zeroize::DefaultIsZeroes, AffineArithmetic, AffineXCoordinate, Curve, IsHigh, PrimeCurve, ProjectiveArithmetic, ScalarArithmetic, }; use core::{ iter::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; #[cfg(feature = "jwk")] use crate::JwkParameters; /// Pseudo-coordinate for fixed-based scalar mult output pub const PSEUDO_COORDINATE_FIXED_BASE_MUL: [u8; 32] = hex!("deadbeef00000000000000000000000000000000000000000000000000000001"); /// SEC1 encoded point. pub type EncodedPoint = crate::sec1::EncodedPoint; /// Field element bytes. pub type FieldBytes = crate::FieldBytes; /// Non-zero scalar value. pub type NonZeroScalar = crate::NonZeroScalar; /// Public key. pub type PublicKey = crate::PublicKey; /// Secret key. pub type SecretKey = crate::SecretKey; /// Scalar core. // TODO(tarcieri): make this the scalar type pub type ScalarCore = crate::ScalarCore; /// Scalar bits. #[cfg(feature = "bits")] pub type ScalarBits = crate::ScalarBits; /// Mock elliptic curve type useful for writing tests which require a concrete /// curve type. /// /// Note: this type is roughly modeled off of NIST P-256, but does not provide /// an actual cure arithmetic implementation. #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub struct MockCurve; impl Curve for MockCurve { type UInt = U256; const ORDER: U256 = U256::from_be_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); } impl PrimeCurve for MockCurve {} impl AffineArithmetic for MockCurve { type AffinePoint = AffinePoint; } impl ProjectiveArithmetic for MockCurve { type ProjectivePoint = ProjectivePoint; } impl ScalarArithmetic for MockCurve { type Scalar = Scalar; } impl AssociatedOid for MockCurve { /// OID for NIST P-256 const OID: pkcs8::ObjectIdentifier = pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); } #[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); impl Field for Scalar { fn random(mut rng: impl RngCore) -> Self { let mut bytes = FieldBytes::default(); loop { rng.fill_bytes(&mut bytes); if let Some(scalar) = Self::from_repr(bytes).into() { return scalar; } } } fn zero() -> Self { Self(ScalarCore::ZERO) } fn one() -> Self { Self(ScalarCore::ONE) } fn is_zero(&self) -> Choice { self.0.is_zero() } #[must_use] fn square(&self) -> Self { unimplemented!(); } #[must_use] fn double(&self) -> Self { self.add(self) } fn invert(&self) -> CtOption { unimplemented!(); } fn sqrt(&self) -> CtOption { unimplemented!(); } } impl PrimeField for Scalar { type Repr = FieldBytes; const NUM_BITS: u32 = 256; const CAPACITY: u32 = 255; const S: u32 = 4; fn from_repr(bytes: FieldBytes) -> CtOption { ScalarCore::from_be_bytes(bytes).map(Self) } fn to_repr(&self) -> FieldBytes { self.0.to_be_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")] impl PrimeFieldBits for Scalar { #[cfg(target_pointer_width = "32")] type ReprBits = [u32; 8]; #[cfg(target_pointer_width = "64")] type ReprBits = [u64; 4]; fn to_le_bits(&self) -> ScalarBits { self.0.as_uint().to_words().into() } fn char_le_bits() -> ScalarBits { MockCurve::ORDER.to_words().into() } } impl TryFrom for Scalar { type Error = Error; fn try_from(w: U256) -> Result { Option::from(ScalarCore::new(w)).map(Self).ok_or(Error) } } impl From for U256 { fn from(scalar: Scalar) -> U256 { *scalar.0.as_uint() } } impl ConditionallySelectable for Scalar { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Self(ScalarCore::conditional_select(&a.0, &b.0, choice)) } } impl ConstantTimeEq for Scalar { fn ct_eq(&self, other: &Self) -> Choice { self.0.ct_eq(&other.0) } } impl DefaultIsZeroes for Scalar {} impl Add for Scalar { type Output = Scalar; fn add(self, other: Scalar) -> Scalar { self.add(&other) } } impl Add<&Scalar> for Scalar { type Output = Scalar; fn add(self, other: &Scalar) -> Scalar { Self(self.0.add(&other.0)) } } impl AddAssign for Scalar { fn add_assign(&mut self, other: Scalar) { *self = *self + other; } } impl AddAssign<&Scalar> for Scalar { fn add_assign(&mut self, other: &Scalar) { *self = *self + other; } } impl Sub for Scalar { type Output = Scalar; fn sub(self, other: Scalar) -> Scalar { self.sub(&other) } } impl Sub<&Scalar> for Scalar { type Output = Scalar; fn sub(self, other: &Scalar) -> Scalar { Self(self.0.sub(&other.0)) } } impl SubAssign for Scalar { fn sub_assign(&mut self, other: Scalar) { *self = *self - other; } } impl SubAssign<&Scalar> for Scalar { fn sub_assign(&mut self, other: &Scalar) { *self = *self - other; } } impl Mul for Scalar { type Output = Scalar; fn mul(self, _other: Scalar) -> Scalar { unimplemented!(); } } impl Mul<&Scalar> for Scalar { type Output = Scalar; fn mul(self, _other: &Scalar) -> Scalar { unimplemented!(); } } impl MulAssign for Scalar { fn mul_assign(&mut self, _rhs: Scalar) { unimplemented!(); } } impl MulAssign<&Scalar> for Scalar { fn mul_assign(&mut self, _rhs: &Scalar) { unimplemented!(); } } impl Neg for Scalar { type Output = Scalar; fn neg(self) -> Scalar { Self(self.0.neg()) } } impl Reduce for Scalar { fn from_uint_reduced(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 reduced = U256::conditional_select(&w, &r, !underflow); Self(ScalarCore::new(reduced).unwrap()) } } impl From for Scalar { fn from(n: u64) -> Scalar { Self(n.into()) } } impl From for Scalar { fn from(scalar: ScalarCore) -> Scalar { Self(scalar) } } impl From for FieldBytes { fn from(scalar: Scalar) -> Self { Self::from(&scalar) } } impl From<&Scalar> for FieldBytes { fn from(scalar: &Scalar) -> Self { scalar.to_repr() } } impl IsHigh for Scalar { fn is_high(&self) -> Choice { self.0.is_high() } } /// Example affine point type #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum AffinePoint { /// Result of fixed-based scalar multiplication. FixedBaseOutput(Scalar), /// Identity. Identity, /// Base point. Generator, /// Point corresponding to a given [`EncodedPoint`]. Other(EncodedPoint), } impl AffineXCoordinate for AffinePoint { fn x(&self) -> FieldBytes { unimplemented!(); } } impl ConstantTimeEq for AffinePoint { fn ct_eq(&self, _other: &Self) -> Choice { unimplemented!(); } } impl ConditionallySelectable for AffinePoint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { // Not really constant time, but this is dev code if choice.into() { *b } else { *a } } } impl Default for AffinePoint { fn default() -> Self { Self::Identity } } impl DefaultIsZeroes for AffinePoint {} impl FromEncodedPoint for AffinePoint { fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption { let point = if encoded_point.is_identity() { Self::Identity } else { Self::Other(*encoded_point) }; CtOption::new(point, Choice::from(1)) } } impl ToEncodedPoint for AffinePoint { fn to_encoded_point(&self, compress: bool) -> EncodedPoint { match self { Self::FixedBaseOutput(scalar) => EncodedPoint::from_affine_coordinates( &scalar.to_repr(), &PSEUDO_COORDINATE_FIXED_BASE_MUL.into(), false, ), Self::Other(point) => { if compress == point.is_compressed() { *point } else { unimplemented!(); } } _ => unimplemented!(), } } } impl Mul for AffinePoint { type Output = AffinePoint; fn mul(self, _scalar: NonZeroScalar) -> Self { unimplemented!(); } } /// Example projective point type #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ProjectivePoint { /// Result of fixed-based scalar multiplication FixedBaseOutput(Scalar), /// Is this point the identity point? Identity, /// Is this point the generator point? Generator, /// Is this point a different point corresponding to a given [`AffinePoint`] Other(AffinePoint), } impl ConstantTimeEq for ProjectivePoint { fn ct_eq(&self, _other: &Self) -> Choice { unimplemented!(); } } impl ConditionallySelectable for ProjectivePoint { fn conditional_select(_a: &Self, _b: &Self, _choice: Choice) -> Self { unimplemented!(); } } impl Default for ProjectivePoint { fn default() -> Self { Self::Identity } } impl DefaultIsZeroes for ProjectivePoint {} impl From for ProjectivePoint { fn from(point: AffinePoint) -> ProjectivePoint { match point { AffinePoint::FixedBaseOutput(scalar) => ProjectivePoint::FixedBaseOutput(scalar), AffinePoint::Identity => ProjectivePoint::Identity, AffinePoint::Generator => ProjectivePoint::Generator, other => ProjectivePoint::Other(other), } } } impl From for AffinePoint { fn from(point: ProjectivePoint) -> AffinePoint { group::Curve::to_affine(&point) } } impl FromEncodedPoint for ProjectivePoint { fn from_encoded_point(_point: &EncodedPoint) -> CtOption { unimplemented!(); } } impl ToEncodedPoint for ProjectivePoint { fn to_encoded_point(&self, _compress: bool) -> EncodedPoint { unimplemented!(); } } impl group::Group for ProjectivePoint { type Scalar = Scalar; fn random(_rng: impl RngCore) -> Self { unimplemented!(); } fn identity() -> Self { Self::Identity } fn generator() -> Self { Self::Generator } fn is_identity(&self) -> Choice { Choice::from((self == &Self::Identity) as u8) } #[must_use] fn double(&self) -> Self { unimplemented!(); } } impl group::Curve for ProjectivePoint { type AffineRepr = AffinePoint; fn to_affine(&self) -> AffinePoint { match self { Self::FixedBaseOutput(scalar) => AffinePoint::FixedBaseOutput(*scalar), Self::Other(affine) => *affine, _ => unimplemented!(), } } } impl LinearCombination for ProjectivePoint {} impl Add for ProjectivePoint { type Output = ProjectivePoint; fn add(self, _other: ProjectivePoint) -> ProjectivePoint { unimplemented!(); } } impl Add<&ProjectivePoint> for ProjectivePoint { type Output = ProjectivePoint; fn add(self, _other: &ProjectivePoint) -> ProjectivePoint { unimplemented!(); } } impl AddAssign for ProjectivePoint { fn add_assign(&mut self, _rhs: ProjectivePoint) { unimplemented!(); } } impl AddAssign<&ProjectivePoint> for ProjectivePoint { fn add_assign(&mut self, _rhs: &ProjectivePoint) { unimplemented!(); } } impl Sub for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, _other: ProjectivePoint) -> ProjectivePoint { unimplemented!(); } } impl Sub<&ProjectivePoint> for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, _other: &ProjectivePoint) -> ProjectivePoint { unimplemented!(); } } impl SubAssign for ProjectivePoint { fn sub_assign(&mut self, _rhs: ProjectivePoint) { unimplemented!(); } } impl SubAssign<&ProjectivePoint> for ProjectivePoint { fn sub_assign(&mut self, _rhs: &ProjectivePoint) { unimplemented!(); } } impl Add for ProjectivePoint { type Output = ProjectivePoint; fn add(self, _other: AffinePoint) -> ProjectivePoint { unimplemented!(); } } impl Add<&AffinePoint> for ProjectivePoint { type Output = ProjectivePoint; fn add(self, _other: &AffinePoint) -> ProjectivePoint { unimplemented!(); } } impl AddAssign for ProjectivePoint { fn add_assign(&mut self, _rhs: AffinePoint) { unimplemented!(); } } impl AddAssign<&AffinePoint> for ProjectivePoint { fn add_assign(&mut self, _rhs: &AffinePoint) { unimplemented!(); } } impl Sum for ProjectivePoint { fn sum>(_iter: I) -> Self { unimplemented!(); } } impl<'a> Sum<&'a ProjectivePoint> for ProjectivePoint { fn sum>(_iter: I) -> Self { unimplemented!(); } } impl Sub for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, _other: AffinePoint) -> ProjectivePoint { unimplemented!(); } } impl Sub<&AffinePoint> for ProjectivePoint { type Output = ProjectivePoint; fn sub(self, _other: &AffinePoint) -> ProjectivePoint { unimplemented!(); } } impl SubAssign for ProjectivePoint { fn sub_assign(&mut self, _rhs: AffinePoint) { unimplemented!(); } } impl SubAssign<&AffinePoint> for ProjectivePoint { fn sub_assign(&mut self, _rhs: &AffinePoint) { unimplemented!(); } } impl Mul for ProjectivePoint { type Output = ProjectivePoint; fn mul(self, scalar: Scalar) -> ProjectivePoint { match self { Self::Generator => Self::FixedBaseOutput(scalar), _ => unimplemented!(), } } } impl Mul<&Scalar> for ProjectivePoint { type Output = ProjectivePoint; fn mul(self, scalar: &Scalar) -> ProjectivePoint { self * *scalar } } impl MulAssign for ProjectivePoint { fn mul_assign(&mut self, _rhs: Scalar) { unimplemented!(); } } impl MulAssign<&Scalar> for ProjectivePoint { fn mul_assign(&mut self, _rhs: &Scalar) { unimplemented!(); } } impl Neg for ProjectivePoint { type Output = ProjectivePoint; fn neg(self) -> ProjectivePoint { unimplemented!(); } } /// 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 { unimplemented!() } /// Returns the square root of self mod p, or `None` if no square root exists. pub fn sqrt(&self) -> CtOption { 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; use ff::PrimeField; use hex_literal::hex; #[test] fn round_trip() { let bytes = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); let scalar = Scalar::from_repr(bytes.into()).unwrap(); assert_eq!(&bytes, scalar.to_repr().as_slice()); } }