Skip to content

Commit a3384dc

Browse files
authored
Impl ecdsa::CheckSignatureBytes-related changes (#159)
Corresponding `ecdsa` crate PR is RustCrypto/signatures#151 This implements the changes which eagerly validate that ECDSA signature `r` and `s` components are in-range `NonZeroScalar` values. This eliminates the need to do these checks as part of each ECDSA verification implementation.
1 parent a6f3bd6 commit a3384dc

File tree

6 files changed

+22
-34
lines changed

6 files changed

+22
-34
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

k256/src/ecdsa.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ use core::convert::TryInto;
7171
/// ECDSA/secp256k1 signature (fixed-size)
7272
pub type Signature = ecdsa_core::Signature<Secp256k1>;
7373

74+
#[cfg(not(feature = "ecdsa"))]
75+
impl ecdsa_core::CheckSignatureBytes for Secp256k1 {}
76+
7477
#[cfg(all(feature = "ecdsa", feature = "sha256"))]
7578
impl ecdsa_core::hazmat::DigestPrimitive for Secp256k1 {
7679
type Digest = sha2::Sha256;

k256/src/ecdsa/sign.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ impl Scalar {
186186
return Err(Error::new());
187187
}
188188

189-
let mut signature = Signature::from_scalars(&r.into(), &s.into());
189+
let mut signature = Signature::from_scalars(r, s)?;
190190
let is_r_odd = bool::from(R.y.normalize().is_odd());
191191
let is_s_high = signature.normalize_s()?;
192192
let recovery_id = recoverable::Id((is_r_odd ^ is_s_high) as u8);

k256/src/ecdsa/verify.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
//! ECDSA verifier
22
33
use super::{recoverable, Error, Signature};
4-
use crate::{
5-
AffinePoint, CompressedPoint, EncodedPoint, NonZeroScalar, ProjectivePoint, Scalar, Secp256k1,
6-
};
4+
use crate::{AffinePoint, CompressedPoint, EncodedPoint, ProjectivePoint, Scalar, Secp256k1};
75
use core::convert::TryFrom;
86
use ecdsa_core::{hazmat::VerifyPrimitive, signature};
9-
use elliptic_curve::{consts::U32, ops::Invert, sec1::ToEncodedPoint, FromBytes};
7+
use elliptic_curve::{consts::U32, ops::Invert, sec1::ToEncodedPoint};
108
use signature::{digest::Digest, DigestVerifier, PrehashSignature};
119

1210
/// ECDSA/secp256k1 verification key (i.e. public key)
@@ -87,15 +85,8 @@ impl TryFrom<&EncodedPoint> for VerifyKey {
8785

8886
impl VerifyPrimitive<Secp256k1> for AffinePoint {
8987
fn verify_prehashed(&self, z: &Scalar, signature: &Signature) -> Result<(), Error> {
90-
let maybe_r = NonZeroScalar::from_bytes(signature.r());
91-
let maybe_s = NonZeroScalar::from_bytes(signature.s());
92-
93-
// TODO(tarcieri): replace with into conversion when available (see subtle#73)
94-
let (r, s) = if maybe_r.is_some().into() && maybe_s.is_some().into() {
95-
(maybe_r.unwrap(), maybe_s.unwrap())
96-
} else {
97-
return Err(Error::new());
98-
};
88+
let r = signature.r();
89+
let s = signature.s();
9990

10091
// Ensure signature is "low S" normalized ala BIP 0062
10192
if s.is_high().into() {

p256/src/ecdsa.rs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use {
4848
crate::{AffinePoint, ProjectivePoint, Scalar},
4949
core::borrow::Borrow,
5050
ecdsa_core::hazmat::{SignPrimitive, VerifyPrimitive},
51-
elliptic_curve::{ops::Invert, subtle::CtOption, FromBytes},
51+
elliptic_curve::ops::Invert,
5252
};
5353

5454
/// ECDSA/P-256 signature (fixed-size)
@@ -64,6 +64,9 @@ pub type SigningKey = ecdsa_core::SigningKey<NistP256>;
6464
#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
6565
pub type VerifyKey = ecdsa_core::VerifyKey<NistP256>;
6666

67+
#[cfg(not(feature = "ecdsa"))]
68+
impl ecdsa_core::CheckSignatureBytes for NistP256 {}
69+
6770
#[cfg(all(feature = "ecdsa", feature = "sha256"))]
6871
impl ecdsa_core::hazmat::DigestPrimitive for NistP256 {
6972
type Digest = sha2::Sha256;
@@ -99,36 +102,25 @@ impl SignPrimitive<NistP256> for Scalar {
99102
return Err(Error::new());
100103
}
101104

102-
Ok(Signature::from_scalars(&r.into(), &s.into()))
105+
Signature::from_scalars(r, s)
103106
}
104107
}
105108

106109
#[cfg(feature = "ecdsa")]
107110
impl VerifyPrimitive<NistP256> for AffinePoint {
108111
fn verify_prehashed(&self, z: &Scalar, signature: &Signature) -> Result<(), Error> {
109-
let maybe_r =
110-
Scalar::from_bytes(signature.r()).and_then(|r| CtOption::new(r, !r.is_zero()));
111-
112-
let maybe_s =
113-
Scalar::from_bytes(signature.s()).and_then(|s| CtOption::new(s, !s.is_zero()));
114-
115-
// TODO(tarcieri): replace with into conversion when available (see subtle#73)
116-
let (r, s) = if maybe_r.is_some().into() && maybe_s.is_some().into() {
117-
(maybe_r.unwrap(), maybe_s.unwrap())
118-
} else {
119-
return Err(Error::new());
120-
};
121-
112+
let r = signature.r();
113+
let s = signature.s();
122114
let s_inv = s.invert().unwrap();
123115
let u1 = z * &s_inv;
124-
let u2 = r * &s_inv;
116+
let u2 = *r * &s_inv;
125117

126118
let x = ((&ProjectivePoint::generator() * &u1) + &(ProjectivePoint::from(*self) * &u2))
127119
.to_affine()
128120
.unwrap()
129121
.x;
130122

131-
if Scalar::from_bytes_reduced(&x.to_bytes()) == r {
123+
if Scalar::from_bytes_reduced(&x.to_bytes()) == *r {
132124
Ok(())
133125
} else {
134126
Err(Error::new())
@@ -177,8 +169,8 @@ mod tests {
177169
let z = Scalar::from_bytes(vector.m.try_into().unwrap()).unwrap();
178170
let sig = d.try_sign_prehashed(&k_blinded, &z).unwrap();
179171

180-
assert_eq!(vector.r, sig.r().as_slice());
181-
assert_eq!(vector.s, sig.s().as_slice());
172+
assert_eq!(vector.r, sig.r().to_bytes().as_slice());
173+
assert_eq!(vector.s, sig.s().to_bytes().as_slice());
182174
}
183175
}
184176

p384/src/ecdsa.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ pub use crate::NistP384;
55
/// ECDSA/P-384 signature (fixed-size)
66
pub type Signature = ecdsa::Signature<NistP384>;
77

8+
impl ecdsa::CheckSignatureBytes for NistP384 {}
9+
810
#[cfg(feature = "sha384")]
911
#[cfg_attr(docsrs, doc(cfg(feature = "sha384")))]
1012
impl ecdsa::hazmat::DigestPrimitive for NistP384 {

0 commit comments

Comments
 (0)