Skip to content

Commit

Permalink
ecdsa: remove SignPrimitive/VerifyPrimitive traits (#1020)
Browse files Browse the repository at this point in the history
These were removed upstream in RustCrypto/signatures#793.

The ECDSA implementation is fully generic now. These traits were
originally for per-curve implementations, but those are no-longer
needed.

The upstream implementation now has native support for low-S
normalization by way of `EcdsaCurve::NORMALIZE_S`.
  • Loading branch information
tarcieri authored Jan 18, 2024
1 parent 32e6310 commit 1e4f274
Show file tree
Hide file tree
Showing 8 changed files with 27 additions and 194 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 23 additions & 32 deletions k256/benches/ecdsa.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,26 @@
//! secp256k1 scalar arithmetic benchmarks
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use ecdsa_core::{
elliptic_curve::group::prime::PrimeCurveAffine,
hazmat::{SignPrimitive, VerifyPrimitive},
use k256::{
ecdsa::{
signature::hazmat::{PrehashSigner, PrehashVerifier},
Signature, SigningKey,
},
elliptic_curve::group::ff::PrimeField,
FieldBytes, NonZeroScalar, Scalar,
};
use k256::{elliptic_curve::group::ff::PrimeField, AffinePoint, FieldBytes, Scalar};

fn test_scalar_d() -> Scalar {
Scalar::from_repr(
[
0xbb, 0x48, 0x8a, 0xef, 0x41, 0x6a, 0x41, 0xd7, 0x68, 0x0d, 0x1c, 0xf0, 0x1d, 0x70,
0xf5, 0x9b, 0x60, 0xd7, 0xf5, 0xf7, 0x7e, 0x30, 0xe7, 0x8b, 0x8b, 0xf9, 0xd2, 0xd8,
0x82, 0xf1, 0x56, 0xa6,
]
.into(),
)
.unwrap()
}

fn test_scalar_k() -> Scalar {
Scalar::from_repr(
[
0x67, 0xe2, 0xf6, 0x80, 0x71, 0xed, 0x82, 0x81, 0xe8, 0xae, 0xd6, 0xbc, 0xf1, 0xc5,
0x20, 0x7c, 0x5e, 0x63, 0x37, 0x22, 0xd9, 0x20, 0xaf, 0xd6, 0xae, 0x22, 0xd0, 0x6e,
0xeb, 0x80, 0x35, 0xe3,
]
.into(),
fn test_scalar_d() -> NonZeroScalar {
NonZeroScalar::new(
Scalar::from_repr(
[
0xbb, 0x48, 0x8a, 0xef, 0x41, 0x6a, 0x41, 0xd7, 0x68, 0x0d, 0x1c, 0xf0, 0x1d, 0x70,
0xf5, 0x9b, 0x60, 0xd7, 0xf5, 0xf7, 0x7e, 0x30, 0xe7, 0x8b, 0x8b, 0xf9, 0xd2, 0xd8,
0x82, 0xf1, 0x56, 0xa6,
]
.into(),
)
.unwrap(),
)
.unwrap()
}
Expand All @@ -43,25 +37,22 @@ fn test_scalar_z() -> FieldBytes {
fn bench_ecdsa(c: &mut Criterion) {
let mut group = c.benchmark_group("ecdsa");

let d = test_scalar_d();
let k = test_scalar_k();
let d = SigningKey::from(test_scalar_d());
let z = test_scalar_z();

group.bench_function("try_sign_prehashed", |b| {
b.iter(|| {
black_box(d)
.try_sign_prehashed(black_box(k), &black_box(z))
.unwrap()
let _: Signature = black_box(&d).sign_prehash(&black_box(z)).unwrap();
})
});

let q = (AffinePoint::generator() * d).to_affine();
let s = d.try_sign_prehashed(k, &z).unwrap().0;
let q = d.verifying_key();
let s: Signature = d.sign_prehash(&z).unwrap();

group.bench_function("verify_prehashed", |b| {
b.iter(|| {
black_box(q)
.verify_prehashed(&black_box(z), &black_box(s))
.verify_prehash(&black_box(z), &black_box(s))
.unwrap()
})
});
Expand Down
86 changes: 0 additions & 86 deletions k256/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,56 +58,6 @@
//!
//! One common application of signature recovery with secp256k1 is Ethereum.
//!
//! ### Upgrading recoverable signature code from earlier versions of `k256`
//!
//! The v0.12 release of `k256` contains a brand new recoverable signature API
//! from previous releases. Functionality has been upstreamed from `k256` to a
//! generic implementation in the [`ecdsa`](`ecdsa_core`) crate.
//!
//! If you previously used `k256::ecdsa::recoverable::Signature`, the old
//! functionality now uses a "detached" [`Signature`] and [`RecoveryId`].
//! Here is where the various functionality went:
//!
//! - Signing now requires the use of the [`hazmat::SignPrimitive`] trait
//! (see examples immediately below).
//! - Signature recovery is now implemented as methods of the [`VerifyingKey`]
//! type (i.e. `::recover_from_*`).
//! - Trial recovery is now defined on the [`RecoveryId`] type
//! (i.e. `::trial_recovery_from_*`).
//!
//! ### Computing a signature with a [`RecoveryId`].
//!
//! This example shows how to compute a signature and its associated
//! [`RecoveryId`] in a manner which is byte-for-byte compatible with
//! Ethereum libraries, leveraging the [`SigningKey::sign_digest_recoverable`]
//! API:
//!
#![cfg_attr(feature = "std", doc = "```")]
#![cfg_attr(not(feature = "std"), doc = "```ignore")]
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use hex_literal::hex;
//! use k256::ecdsa::{hazmat::SignPrimitive, RecoveryId, Signature, SigningKey};
//! use sha2::Sha256;
//! use sha3::{Keccak256, Digest};
//!
//! let signing_key = SigningKey::from_bytes(&hex!(
//! "4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318"
//! ).into())?;
//!
//! let msg = hex!("e9808504e3b29200831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca0080018080");
//! let digest = Keccak256::new_with_prefix(msg);
//! let (signature, recid) = signing_key.sign_digest_recoverable(digest)?;
//!
//! assert_eq!(
//! signature.to_bytes().as_slice(),
//! &hex!("c9cf86333bcb065d140032ecaab5d9281bde80f21b9687b3e94161de42d51895727a108a0b8d101465414033c3f705a9c7b826e596766046ee1183dbc8aeaa68")
//! );
//!
//! assert_eq!(recid, RecoveryId::try_from(0u8).unwrap());
//! # Ok(())
//! # }
//! ```
//!
//! ### Recovering a [`VerifyingKey`] from a signature
//!
#![cfg_attr(feature = "std", doc = "```")]
Expand Down Expand Up @@ -152,13 +102,6 @@ pub use ecdsa_core::hazmat;

use crate::Secp256k1;

#[cfg(feature = "ecdsa")]
use {
crate::{AffinePoint, FieldBytes, Scalar},
ecdsa_core::hazmat::{SignPrimitive, VerifyPrimitive},
elliptic_curve::{ops::Invert, scalar::IsHigh, subtle::CtOption},
};

/// ECDSA/secp256k1 signature (fixed-size)
pub type Signature = ecdsa_core::Signature<Secp256k1>;

Expand All @@ -182,35 +125,6 @@ impl hazmat::DigestPrimitive for Secp256k1 {
type Digest = sha2::Sha256;
}

#[cfg(feature = "ecdsa")]
impl SignPrimitive<Secp256k1> for Scalar {
#[allow(non_snake_case, clippy::many_single_char_names)]
fn try_sign_prehashed<K>(
&self,
k: K,
z: &FieldBytes,
) -> Result<(Signature, Option<RecoveryId>), Error>
where
K: AsRef<Self> + Invert<Output = CtOption<Self>>,
{
let (sig, recid) = hazmat::sign_prehashed::<Secp256k1, K>(self, k, z)?;
let is_y_odd = recid.is_y_odd() ^ bool::from(sig.s().is_high());
let recid = RecoveryId::new(is_y_odd, recid.is_x_reduced());
Ok((sig.normalize_s(), Some(recid)))
}
}

#[cfg(feature = "ecdsa")]
impl VerifyPrimitive<Secp256k1> for AffinePoint {
fn verify_prehashed(&self, z: &FieldBytes, sig: &Signature) -> Result<(), Error> {
if sig.s().is_high().into() {
return Err(Error::new());
}

hazmat::verify_prehashed(&self.into(), z, sig)
}
}

#[cfg(all(test, feature = "ecdsa", feature = "arithmetic"))]
mod tests {
mod normalize {
Expand Down
6 changes: 0 additions & 6 deletions p192/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ pub use ecdsa_core::signature::{self, Error};
use super::NistP192;
use ecdsa_core::EcdsaCurve;

#[cfg(feature = "ecdsa")]
use {crate::AffinePoint, ecdsa_core::hazmat::VerifyPrimitive};

/// ECDSA/P-192 signature (fixed-size)
pub type Signature = ecdsa_core::Signature<NistP192>;

Expand All @@ -53,9 +50,6 @@ impl EcdsaCurve for NistP192 {
#[cfg(feature = "ecdsa")]
pub type VerifyingKey = ecdsa_core::VerifyingKey<NistP192>;

#[cfg(feature = "ecdsa")]
impl VerifyPrimitive<NistP192> for AffinePoint {}

#[cfg(all(test, feature = "ecdsa"))]
mod tests {
mod verify {
Expand Down
12 changes: 0 additions & 12 deletions p224/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ pub use ecdsa_core::signature::{self, Error};
use super::NistP224;
use ecdsa_core::EcdsaCurve;

#[cfg(feature = "ecdsa")]
use {
crate::{AffinePoint, Scalar},
ecdsa_core::hazmat::{SignPrimitive, VerifyPrimitive},
};

/// ECDSA/P-224 signature (fixed-size)
pub type Signature = ecdsa_core::Signature<NistP224>;

Expand All @@ -71,12 +65,6 @@ impl ecdsa_core::hazmat::DigestPrimitive for NistP224 {
type Digest = sha2::Sha224;
}

#[cfg(feature = "ecdsa")]
impl SignPrimitive<NistP224> for Scalar {}

#[cfg(feature = "ecdsa")]
impl VerifyPrimitive<NistP224> for AffinePoint {}

#[cfg(all(test, feature = "ecdsa"))]
mod tests {
use crate::ecdsa::{signature::Signer, Signature, SigningKey};
Expand Down
34 changes: 2 additions & 32 deletions p256/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,6 @@ pub use ecdsa_core::signature::{self, Error};
use super::NistP256;
use ecdsa_core::EcdsaCurve;

#[cfg(feature = "ecdsa")]
use {
crate::{AffinePoint, Scalar},
ecdsa_core::hazmat::{SignPrimitive, VerifyPrimitive},
};

/// ECDSA/P-256 signature (fixed-size)
pub type Signature = ecdsa_core::Signature<NistP256>;

Expand All @@ -72,13 +66,6 @@ pub type VerifyingKey = ecdsa_core::VerifyingKey<NistP256>;
impl ecdsa_core::hazmat::DigestPrimitive for NistP256 {
type Digest = sha2::Sha256;
}

#[cfg(feature = "ecdsa")]
impl SignPrimitive<NistP256> for Scalar {}

#[cfg(feature = "ecdsa")]
impl VerifyPrimitive<NistP256> for AffinePoint {}

#[cfg(all(test, feature = "ecdsa"))]
mod tests {
use crate::{
Expand All @@ -87,13 +74,9 @@ mod tests {
signature::Signer,
Signature, SigningKey, VerifyingKey,
},
test_vectors::ecdsa::ECDSA_TEST_VECTORS,
AffinePoint, BlindedScalar, EncodedPoint, Scalar,
};
use ecdsa_core::hazmat::SignPrimitive;
use elliptic_curve::{
array::Array, group::ff::PrimeField, rand_core::OsRng, sec1::FromEncodedPoint,
AffinePoint, EncodedPoint,
};
use elliptic_curve::{array::Array, sec1::FromEncodedPoint};
use hex_literal::hex;
use sha2::Digest;

Expand Down Expand Up @@ -172,19 +155,6 @@ mod tests {
assert!(result.is_ok());
}

#[test]
fn scalar_blinding() {
let vector = &ECDSA_TEST_VECTORS[0];
let d = Scalar::from_repr(Array::clone_from_slice(vector.d)).unwrap();
let k = Scalar::from_repr(Array::clone_from_slice(vector.k)).unwrap();
let k_blinded = BlindedScalar::new(k, &mut OsRng);
let z = Array::clone_from_slice(vector.m);
let sig = d.try_sign_prehashed(k_blinded, &z).unwrap().0;

assert_eq!(vector.r, sig.r().to_bytes().as_slice());
assert_eq!(vector.s, sig.s().to_bytes().as_slice());
}

mod sign {
use crate::{test_vectors::ecdsa::ECDSA_TEST_VECTORS, NistP256};
ecdsa_core::new_signing_test!(NistP256, ECDSA_TEST_VECTORS);
Expand Down
12 changes: 0 additions & 12 deletions p384/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ pub use ecdsa_core::signature::{self, Error};
use super::NistP384;
use ecdsa_core::EcdsaCurve;

#[cfg(feature = "ecdsa")]
use {
crate::{AffinePoint, Scalar},
ecdsa_core::hazmat::{SignPrimitive, VerifyPrimitive},
};

/// ECDSA/P-384 signature (fixed-size)
pub type Signature = ecdsa_core::Signature<NistP384>;

Expand All @@ -71,12 +65,6 @@ impl ecdsa_core::hazmat::DigestPrimitive for NistP384 {
type Digest = sha2::Sha384;
}

#[cfg(feature = "ecdsa")]
impl SignPrimitive<NistP384> for Scalar {}

#[cfg(feature = "ecdsa")]
impl VerifyPrimitive<NistP384> for AffinePoint {}

#[cfg(all(test, feature = "ecdsa"))]
mod tests {
use crate::{
Expand Down
12 changes: 0 additions & 12 deletions p521/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ pub use ecdsa_core::signature::{self, Error};
use super::NistP521;
use ecdsa_core::EcdsaCurve;

#[cfg(feature = "ecdsa")]
use {
crate::{AffinePoint, Scalar},
ecdsa_core::hazmat::{SignPrimitive, VerifyPrimitive},
};

/// ECDSA/P-521 signature (fixed-size)
pub type Signature = ecdsa_core::Signature<NistP521>;

Expand All @@ -71,12 +65,6 @@ impl ecdsa_core::hazmat::DigestPrimitive for NistP521 {
type Digest = sha2::Sha512;
}

#[cfg(feature = "ecdsa")]
impl SignPrimitive<NistP521> for Scalar {}

#[cfg(feature = "ecdsa")]
impl VerifyPrimitive<NistP521> for AffinePoint {}

#[cfg(all(test, feature = "ecdsa"))]
mod tests {
use crate::ecdsa::{signature::Signer, Signature, SigningKey};
Expand Down

0 comments on commit 1e4f274

Please sign in to comment.