diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:47:55 +0000 |
commit | 2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch) | |
tree | 033cc839730fda84ff08db877037977be94e5e3a /vendor/elliptic-curve/src/scalar | |
parent | Initial commit. (diff) | |
download | cargo-2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4.tar.xz cargo-2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4.zip |
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/elliptic-curve/src/scalar')
-rw-r--r-- | vendor/elliptic-curve/src/scalar/blinded.rs | 74 | ||||
-rw-r--r-- | vendor/elliptic-curve/src/scalar/nonzero.rs | 405 | ||||
-rw-r--r-- | vendor/elliptic-curve/src/scalar/primitive.rs | 434 |
3 files changed, 913 insertions, 0 deletions
diff --git a/vendor/elliptic-curve/src/scalar/blinded.rs b/vendor/elliptic-curve/src/scalar/blinded.rs new file mode 100644 index 0000000..29cfea9 --- /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 new file mode 100644 index 0000000..c0e4574 --- /dev/null +++ b/vendor/elliptic-curve/src/scalar/nonzero.rs @@ -0,0 +1,405 @@ +//! Non-zero scalar type. + +use crate::{ + ops::{Invert, Reduce, ReduceNonZero}, + scalar::IsHigh, + CurveArithmetic, Error, FieldBytes, PrimeCurve, Scalar, ScalarPrimitive, SecretKey, +}; +use base16ct::HexDisplay; +use core::{ + fmt, + ops::{Deref, Mul, Neg}, + str, +}; +use crypto_bigint::{ArrayEncoding, Integer}; +use ff::{Field, PrimeField}; +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*`. +/// To do this, the generic `S` type must impl both `Default` and +/// `ConstantTimeEq`, with the requirement that `S::default()` returns 0. +/// +/// In the context of ECC, it's useful for ensuring that scalar multiplication +/// cannot result in the point at infinity. +#[derive(Clone)] +pub struct NonZeroScalar<C> +where + C: CurveArithmetic, +{ + scalar: Scalar<C>, +} + +impl<C> NonZeroScalar<C> +where + C: CurveArithmetic, +{ + /// Generate a random `NonZeroScalar`. + 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`. + loop { + if let Some(result) = Self::new(Field::random(&mut rng)).into() { + break result; + } + } + } + + /// Create a [`NonZeroScalar`] from a scalar. + pub fn new(scalar: Scalar<C>) -> CtOption<Self> { + CtOption::new(Self { scalar }, !scalar.is_zero()) + } + + /// Decode a [`NonZeroScalar`] from a big endian-serialized field element. + pub fn from_repr(repr: FieldBytes<C>) -> CtOption<Self> { + 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> { + ScalarPrimitive::new(uint).and_then(|scalar| Self::new(scalar.into())) + } +} + +impl<C> AsRef<Scalar<C>> for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn as_ref(&self) -> &Scalar<C> { + &self.scalar + } +} + +impl<C> ConditionallySelectable for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Self { + scalar: Scalar::<C>::conditional_select(&a.scalar, &b.scalar, choice), + } + } +} + +impl<C> ConstantTimeEq for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.scalar.ct_eq(&other.scalar) + } +} + +impl<C> Copy for NonZeroScalar<C> where C: CurveArithmetic {} + +impl<C> Deref for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + type Target = Scalar<C>; + + fn deref(&self) -> &Scalar<C> { + &self.scalar + } +} + +impl<C> From<NonZeroScalar<C>> for FieldBytes<C> +where + C: CurveArithmetic, +{ + fn from(scalar: NonZeroScalar<C>) -> FieldBytes<C> { + Self::from(&scalar) + } +} + +impl<C> From<&NonZeroScalar<C>> for FieldBytes<C> +where + C: CurveArithmetic, +{ + fn from(scalar: &NonZeroScalar<C>) -> FieldBytes<C> { + scalar.to_repr() + } +} + +impl<C> From<NonZeroScalar<C>> for ScalarPrimitive<C> +where + C: CurveArithmetic, +{ + #[inline] + fn from(scalar: NonZeroScalar<C>) -> ScalarPrimitive<C> { + Self::from(&scalar) + } +} + +impl<C> From<&NonZeroScalar<C>> for ScalarPrimitive<C> +where + C: CurveArithmetic, +{ + fn from(scalar: &NonZeroScalar<C>) -> ScalarPrimitive<C> { + ScalarPrimitive::from_bytes(&scalar.to_repr()).unwrap() + } +} + +impl<C> From<SecretKey<C>> for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn from(sk: SecretKey<C>) -> NonZeroScalar<C> { + Self::from(&sk) + } +} + +impl<C> From<&SecretKey<C>> for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn from(sk: &SecretKey<C>) -> NonZeroScalar<C> { + let scalar = sk.as_scalar_primitive().to_scalar(); + debug_assert!(!bool::from(scalar.is_zero())); + Self { scalar } + } +} + +impl<C> Invert for NonZeroScalar<C> +where + 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: 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: CurveArithmetic, +{ + fn is_high(&self) -> Choice { + self.scalar.is_high() + } +} + +impl<C> Neg for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + type Output = NonZeroScalar<C>; + + fn neg(self) -> NonZeroScalar<C> { + let scalar = -self.scalar; + debug_assert!(!bool::from(scalar.is_zero())); + NonZeroScalar { scalar } + } +} + +impl<C> Mul<NonZeroScalar<C>> for NonZeroScalar<C> +where + C: PrimeCurve + CurveArithmetic, +{ + type Output = Self; + + #[inline] + fn mul(self, other: Self) -> Self { + Self::mul(self, &other) + } +} + +impl<C> Mul<&NonZeroScalar<C>> for NonZeroScalar<C> +where + C: PrimeCurve + CurveArithmetic, +{ + type Output = Self; + + fn mul(self, other: &Self) -> Self { + // Multiplication is modulo a prime, so the product of two non-zero + // scalars is also non-zero. + let scalar = self.scalar * other.scalar; + debug_assert!(!bool::from(scalar.is_zero())); + NonZeroScalar { scalar } + } +} + +/// Note: this is a non-zero reduction, as it's impl'd for [`NonZeroScalar`]. +impl<C, I> Reduce<I> for NonZeroScalar<C> +where + C: CurveArithmetic, + I: Integer + ArrayEncoding, + Scalar<C>: Reduce<I> + ReduceNonZero<I>, +{ + 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 + Self: Reduce<I>, + C: CurveArithmetic, + I: Integer + ArrayEncoding, + Scalar<C>: Reduce<I, Bytes = Self::Bytes> + ReduceNonZero<I>, +{ + 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: CurveArithmetic, +{ + type Error = Error; + + fn try_from(bytes: &[u8]) -> Result<Self, Error> { + if bytes.len() == C::FieldBytesSize::USIZE { + Option::from(NonZeroScalar::from_repr(GenericArray::clone_from_slice( + bytes, + ))) + .ok_or(Error) + } else { + Err(Error) + } + } +} + +impl<C> Zeroize for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn zeroize(&mut self) { + // Use zeroize's volatile writes to ensure value is cleared. + self.scalar.zeroize(); + + // Write a 1 instead of a 0 to ensure this type's non-zero invariant + // is upheld. + self.scalar = Scalar::<C>::ONE; + } +} + +impl<C> fmt::Display for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self:X}") + } +} + +impl<C> fmt::LowerHex for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:x}", HexDisplay(&self.to_repr())) + } +} + +impl<C> fmt::UpperHex for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:}", HexDisplay(&self.to_repr())) + } +} + +impl<C> str::FromStr for NonZeroScalar<C> +where + C: CurveArithmetic, +{ + type Err = Error; + + fn from_str(hex: &str) -> Result<Self, Error> { + let mut bytes = FieldBytes::<C>::default(); + + if base16ct::mixed::decode(hex, &mut bytes)?.len() == bytes.len() { + Option::from(Self::from_repr(bytes)).ok_or(Error) + } else { + Err(Error) + } + } +} + +#[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}; + use ff::{Field, PrimeField}; + use hex_literal::hex; + use zeroize::Zeroize; + + #[test] + fn round_trip() { + let bytes = hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721"); + let scalar = NonZeroScalar::from_repr(bytes.into()).unwrap(); + assert_eq!(&bytes, scalar.to_repr().as_slice()); + } + + #[test] + fn zeroize() { + let mut scalar = NonZeroScalar::new(Scalar::from(42u64)).unwrap(); + scalar.zeroize(); + assert_eq!(*scalar, Scalar::ONE); + } +} diff --git a/vendor/elliptic-curve/src/scalar/primitive.rs b/vendor/elliptic-curve/src/scalar/primitive.rs new file mode 100644 index 0000000..a4f64cb --- /dev/null +++ b/vendor/elliptic-curve/src/scalar/primitive.rs @@ -0,0 +1,434 @@ +//! Generic scalar type with primitive functionality. + +use crate::{ + bigint::{prelude::*, Limb, NonZero}, + scalar::FromUintUnchecked, + scalar::IsHigh, + Curve, Error, FieldBytes, FieldBytesEncoding, Result, +}; +use base16ct::HexDisplay; +use core::{ + cmp::Ordering, + fmt, + ops::{Add, AddAssign, Neg, ShrAssign, Sub, SubAssign}, + str, +}; +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::{CurveArithmetic, Scalar}; + +#[cfg(feature = "serde")] +use serdect::serde::{de, ser, Deserialize, Serialize}; + +/// 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 +/// any arithmetic traits. +/// +/// # `serde` support +/// +/// When the optional `serde` feature of this create is enabled, [`Serialize`] +/// and [`Deserialize`] impls are provided for this type. +/// +/// The serialization is a fixed-width big endian encoding. When used with +/// textual formats, the binary data is encoded as hexadecimal. +// TODO(tarcieri): use `crypto-bigint`'s `Residue` type, expose more functionality? +#[derive(Copy, Clone, Debug, Default)] +pub struct ScalarPrimitive<C: Curve> { + /// Inner unsigned integer type. + inner: C::Uint, +} + +impl<C> ScalarPrimitive<C> +where + C: Curve, +{ + /// Zero scalar. + pub const ZERO: Self = Self { + inner: C::Uint::ZERO, + }; + + /// Multiplicative identity. + pub const ONE: Self = Self { + inner: C::Uint::ONE, + }; + + /// Scalar modulus. + pub const MODULUS: C::Uint = C::ORDER; + + /// Generate a random [`ScalarPrimitive`]. + pub fn random(rng: &mut impl CryptoRngCore) -> Self { + Self { + 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> { + CtOption::new(Self { inner: uint }, uint.ct_lt(&Self::MODULUS)) + } + + /// 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 [`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) + } + } + + /// Borrow the inner `C::Uint`. + pub fn as_uint(&self) -> &C::Uint { + &self.inner + } + + /// Borrow the inner limbs as a slice. + pub fn as_limbs(&self) -> &[Limb] { + self.inner.as_ref() + } + + /// Is this [`ScalarPrimitive`] value equal to zero? + pub fn is_zero(&self) -> Choice { + self.inner.is_zero() + } + + /// Is this [`ScalarPrimitive`] value even? + pub fn is_even(&self) -> Choice { + self.inner.is_even() + } + + /// Is this [`ScalarPrimitive`] value odd? + pub fn is_odd(&self) -> Choice { + self.inner.is_odd() + } + + /// 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; + + fn from_uint_unchecked(uint: C::Uint) -> Self { + Self { inner: uint } + } +} + +#[cfg(feature = "arithmetic")] +impl<C> ScalarPrimitive<C> +where + C: CurveArithmetic, +{ + /// Convert [`ScalarPrimitive`] into a given curve's scalar type. + pub(super) fn to_scalar(self) -> Scalar<C> { + Scalar::<C>::from_uint_unchecked(self.inner) + } +} + +// TODO(tarcieri): better encapsulate this? +impl<C> AsRef<[Limb]> for ScalarPrimitive<C> +where + C: Curve, +{ + fn as_ref(&self) -> &[Limb] { + self.as_limbs() + } +} + +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), + } + } +} + +impl<C> ConstantTimeEq for ScalarPrimitive<C> +where + C: Curve, +{ + fn ct_eq(&self, other: &Self) -> Choice { + self.inner.ct_eq(&other.inner) + } +} + +impl<C> ConstantTimeLess for ScalarPrimitive<C> +where + C: Curve, +{ + fn ct_lt(&self, other: &Self) -> Choice { + self.inner.ct_lt(&other.inner) + } +} + +impl<C> ConstantTimeGreater for ScalarPrimitive<C> +where + C: Curve, +{ + fn ct_gt(&self, other: &Self) -> Choice { + self.inner.ct_gt(&other.inner) + } +} + +impl<C: Curve> DefaultIsZeroes for ScalarPrimitive<C> {} + +impl<C: Curve> Eq for ScalarPrimitive<C> {} + +impl<C> PartialEq for ScalarPrimitive<C> +where + C: Curve, +{ + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +impl<C> PartialOrd for ScalarPrimitive<C> +where + C: Curve, +{ + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl<C> Ord for ScalarPrimitive<C> +where + C: Curve, +{ + fn cmp(&self, other: &Self) -> Ordering { + self.inner.cmp(&other.inner) + } +} + +impl<C> From<u64> for ScalarPrimitive<C> +where + C: Curve, +{ + fn from(n: u64) -> Self { + Self { + inner: C::Uint::from(n), + } + } +} + +impl<C> Add<ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + type Output = Self; + + fn add(self, other: Self) -> Self { + self.add(&other) + } +} + +impl<C> Add<&ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + type Output = Self; + + fn add(self, other: &Self) -> Self { + Self { + inner: self.inner.add_mod(&other.inner, &Self::MODULUS), + } + } +} + +impl<C> AddAssign<ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl<C> AddAssign<&ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + fn add_assign(&mut self, other: &Self) { + *self = *self + other; + } +} + +impl<C> Sub<ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + type Output = Self; + + fn sub(self, other: Self) -> Self { + self.sub(&other) + } +} + +impl<C> Sub<&ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + type Output = Self; + + fn sub(self, other: &Self) -> Self { + Self { + inner: self.inner.sub_mod(&other.inner, &Self::MODULUS), + } + } +} + +impl<C> SubAssign<ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl<C> SubAssign<&ScalarPrimitive<C>> for ScalarPrimitive<C> +where + C: Curve, +{ + fn sub_assign(&mut self, other: &Self) { + *self = *self - other; + } +} + +impl<C> Neg for ScalarPrimitive<C> +where + C: Curve, +{ + type Output = Self; + + fn neg(self) -> Self { + Self { + inner: self.inner.neg_mod(&Self::MODULUS), + } + } +} + +impl<C> Neg for &ScalarPrimitive<C> +where + C: Curve, +{ + type Output = ScalarPrimitive<C>; + + fn neg(self) -> ScalarPrimitive<C> { + -*self + } +} + +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, +{ + fn is_high(&self) -> Choice { + let n_2 = C::ORDER >> 1; + self.inner.ct_gt(&n_2) + } +} + +impl<C> fmt::Display for ScalarPrimitive<C> +where + C: Curve, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self:X}") + } +} + +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_bytes())) + } +} + +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_bytes())) + } +} + +impl<C> str::FromStr for ScalarPrimitive<C> +where + C: Curve, +{ + type Err = Error; + + fn from_str(hex: &str) -> Result<Self> { + let mut bytes = FieldBytes::<C>::default(); + base16ct::lower::decode(hex, &mut bytes)?; + Self::from_slice(&bytes) + } +} + +#[cfg(feature = "serde")] +impl<C> Serialize for ScalarPrimitive<C> +where + C: Curve, +{ + fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, C> Deserialize<'de> for ScalarPrimitive<C> +where + C: Curve, +{ + fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + let mut bytes = FieldBytes::<C>::default(); + serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; + Self::from_slice(&bytes).map_err(|_| de::Error::custom("scalar out of range")) + } +} |