Skip to content

Commit

Permalink
k256+p256: impl Reduce trait on Scalar types (#436)
Browse files Browse the repository at this point in the history
Adds trait impls to `k256::Scalar` and `p256::Scalar` for the newly
introduced `Reduce` trait, replacing the previous inherent methods:

RustCrypto/traits#768
  • Loading branch information
tarcieri authored Sep 20, 2021
1 parent 10ee318 commit 05986ad
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 31 deletions.
21 changes: 10 additions & 11 deletions k256/src/arithmetic/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use elliptic_curve::{
bigint::{limb, nlimbs, ArrayEncoding, Encoding, Limb, U256},
generic_array::arr,
group::ff::{Field, PrimeField},
ops::Reduce,
rand_core::{CryptoRng, RngCore},
subtle::{
Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
Expand Down Expand Up @@ -210,16 +211,6 @@ impl Scalar {
/// Multiplicative identity.
pub const ONE: Self = Self(U256::ONE);

/// Parses the given byte array as a scalar.
///
/// Subtracts the modulus when the byte array is larger than the modulus.
pub fn from_bytes_reduced(bytes: &FieldBytes) -> Self {
let w = U256::from_be_slice(bytes);
let (r, underflow) = w.sbb(&ORDER, Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (Limb::BIT_SIZE - 1)) as u8);
Self(U256::conditional_select(&w, &r, !underflow))
}

/// Is this scalar greater than or equal to n / 2?
pub fn is_high(&self) -> Choice {
self.0.ct_gt(&FRAC_MODULUS_2)
Expand Down Expand Up @@ -398,7 +389,7 @@ impl FromDigest<Secp256k1> for Scalar {
where
D: Digest<OutputSize = U32>,
{
Self::from_bytes_reduced(&digest.finalize())
Self::from_be_bytes_reduced(digest.finalize())
}
}

Expand Down Expand Up @@ -570,6 +561,14 @@ impl MulAssign<&Scalar> for Scalar {
}
}

impl Reduce<U256> for Scalar {
fn from_uint_reduced(w: U256) -> Self {
let (r, underflow) = w.sbb(&ORDER, Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (Limb::BIT_SIZE - 1)) as u8);
Self(U256::conditional_select(&w, &r, !underflow))
}
}

#[cfg(feature = "bits")]
#[cfg_attr(docsrs, doc(cfg(feature = "bits")))]
impl From<&Scalar> for ScalarBits {
Expand Down
9 changes: 7 additions & 2 deletions k256/src/ecdsa/recoverable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ use crate::{
signature::{digest::Digest, DigestVerifier},
VerifyingKey,
},
elliptic_curve::{consts::U32, ops::Invert, subtle::Choice, DecompressPoint},
elliptic_curve::{
consts::U32,
ops::{Invert, Reduce},
subtle::Choice,
DecompressPoint,
},
lincomb, AffinePoint, FieldBytes, NonZeroScalar, ProjectivePoint, Scalar,
};

Expand Down Expand Up @@ -170,7 +175,7 @@ impl Signature {
) -> Result<VerifyingKey, Error> {
let r = self.r();
let s = self.s();
let z = Scalar::from_bytes_reduced(digest_bytes);
let z = Scalar::from_be_bytes_reduced(*digest_bytes);
let R = AffinePoint::decompress(&r.to_bytes(), self.recovery_id().is_y_odd());

if R.is_some().into() {
Expand Down
4 changes: 2 additions & 2 deletions k256/src/ecdsa/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use ecdsa_core::{
};
use elliptic_curve::{
consts::U32,
ops::Invert,
ops::{Invert, Reduce},
rand_core::{CryptoRng, RngCore},
subtle::{Choice, ConstantTimeEq},
};
Expand Down Expand Up @@ -181,7 +181,7 @@ impl RecoverableSignPrimitive<Secp256k1> for Scalar {

// Lift x-coordinate of 𝐑 (element of base field) into a serialized big
// integer, then reduce it into an element of the scalar field
let r = Scalar::from_bytes_reduced(&R.x.to_bytes());
let r = Scalar::from_be_bytes_reduced(R.x.to_bytes());

// Compute `s` as a signature over `r` and `z`.
let s = k_inverse * (z + (r * self));
Expand Down
8 changes: 6 additions & 2 deletions k256/src/ecdsa/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ use crate::{
};
use core::convert::TryFrom;
use ecdsa_core::{hazmat::VerifyPrimitive, signature};
use elliptic_curve::{consts::U32, ops::Invert, sec1::ToEncodedPoint};
use elliptic_curve::{
consts::U32,
ops::{Invert, Reduce},
sec1::ToEncodedPoint,
};
use signature::{digest::Digest, DigestVerifier};

#[cfg(feature = "sha256")]
Expand Down Expand Up @@ -100,7 +104,7 @@ impl VerifyPrimitive<Secp256k1> for AffinePoint {
.to_affine()
.x;

if Scalar::from_bytes_reduced(&x.to_bytes()).eq(&r) {
if Scalar::from_be_bytes_reduced(x.to_bytes()).eq(&r) {
Ok(())
} else {
Err(Error::new())
Expand Down
21 changes: 10 additions & 11 deletions p256/src/arithmetic/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use elliptic_curve::{
bigint::{ArrayEncoding, Encoding, Limb, U256},
generic_array::arr,
group::ff::{Field, PrimeField},
ops::Reduce,
rand_core::RngCore,
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeLess, CtOption},
zeroize::DefaultIsZeroes,
Expand Down Expand Up @@ -224,16 +225,6 @@ impl Scalar {
/// Multiplicative identity.
pub const ONE: Self = Self(U256::ONE);

/// Parses the given byte array as a scalar.
///
/// Subtracts the modulus when decoded integer is larger than the modulus.
pub fn from_bytes_reduced(bytes: &FieldBytes) -> Self {
let w = U256::from_be_slice(bytes);
let (r, underflow) = w.sbb(&NistP256::ORDER, Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (Limb::BIT_SIZE - 1)) as u8);
Self(U256::conditional_select(&w, &r, !underflow))
}

/// Returns the SEC1 encoding of this scalar.
pub fn to_bytes(&self) -> FieldBytes {
self.0.to_be_byte_array()
Expand Down Expand Up @@ -592,7 +583,7 @@ impl FromDigest<NistP256> for Scalar {
where
D: Digest<OutputSize = U32>,
{
Self::from_bytes_reduced(&digest.finalize())
Self::from_be_bytes_reduced(digest.finalize())
}
}

Expand Down Expand Up @@ -720,6 +711,14 @@ impl<'a> Neg for &'a Scalar {
}
}

impl Reduce<U256> for Scalar {
fn from_uint_reduced(w: U256) -> Self {
let (r, underflow) = w.sbb(&NistP256::ORDER, Limb::ZERO);
let underflow = Choice::from((underflow.0 >> (Limb::BIT_SIZE - 1)) as u8);
Self(U256::conditional_select(&w, &r, !underflow))
}
}

impl ConditionallySelectable for Scalar {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Self(U256::conditional_select(&a.0, &b.0, choice))
Expand Down
9 changes: 6 additions & 3 deletions p256/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ use {
crate::{AffinePoint, ProjectivePoint, Scalar},
core::borrow::Borrow,
ecdsa_core::hazmat::{SignPrimitive, VerifyPrimitive},
elliptic_curve::{group::ff::Field, ops::Invert},
elliptic_curve::{
group::ff::Field,
ops::{Invert, Reduce},
},
};

/// ECDSA/P-256 signature (fixed-size)
Expand Down Expand Up @@ -94,7 +97,7 @@ impl SignPrimitive<NistP256> for Scalar {

// Lift `x` (element of base field) to serialized big endian integer,
// then reduce it to an element of the scalar field
let r = Scalar::from_bytes_reduced(&x.to_bytes());
let r = Scalar::from_be_bytes_reduced(x.to_bytes());

// Compute `s` as a signature over `r` and `z`.
let s = k_inverse * (z + &(r * self));
Expand All @@ -120,7 +123,7 @@ impl VerifyPrimitive<NistP256> for AffinePoint {
.to_affine()
.x;

if Scalar::from_bytes_reduced(&x.to_bytes()) == *r {
if Scalar::from_be_bytes_reduced(x.to_bytes()) == *r {
Ok(())
} else {
Err(Error::new())
Expand Down

0 comments on commit 05986ad

Please sign in to comment.