Skip to content

Commit

Permalink
Stop implementing ThirtyTwoByteHash
Browse files Browse the repository at this point in the history
The implementations of `ThirtyTwoByteHash` for types from the `hashes`
crate are problematic during upgrades because both `bitcoin` and
`secp256k1` depend on `hashes` and when the versions of `hashes` get out
of sync usage of the trait breaks.

In order to resolve this issue stop implementing `ThirtyTwoByteHash` for
the `hashes` types, this means also that we cannot use the
`hashes::Hash` trait bound when implementing `from_hashed_data` for
`SecretKey` or `Message` (because of the bound on `From`). We can still
provide the `from_hashed_data` helper function but we now restrict it to
only hashing with `sha256` instead of a generic hasher. Users can still
create the `Message` and `SecretKey` types from other hashes but to do
so they must do it manually, this is documented in the update rustdocs
for each function.
  • Loading branch information
tcharding committed Mar 27, 2024
1 parent b370f67 commit 9d43945
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 45 deletions.
10 changes: 6 additions & 4 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,17 +268,19 @@ impl SecretKey {
/// use secp256k1::hashes::{sha256, Hash};
/// use secp256k1::SecretKey;
///
/// let sk1 = SecretKey::from_hashed_data::<sha256::Hash>("Hello world!".as_bytes());
/// let sk1 = SecretKey::from_hashed_data("Hello world!".as_bytes());
/// // is equivalent to
/// let sk2 = SecretKey::from(sha256::Hash::hash("Hello world!".as_bytes()));
/// let sk2 = SecretKey::from_slice(sha256::Hash::hash("Hello world!".as_bytes()).as_byte_array()).unwrap();
///
/// assert_eq!(sk1, sk2);
/// # }
/// ```
#[cfg(feature = "hashes")]
#[inline]
pub fn from_hashed_data<H: ThirtyTwoByteHash + hashes::Hash>(data: &[u8]) -> Self {
<H as hashes::Hash>::hash(data).into()
pub fn from_hashed_data(data: &[u8]) -> Self {
use hashes::{sha256, Hash};
let hash = sha256::Hash::hash(data);
SecretKey::from_slice(hash.as_byte_array()).expect("sha256 hash is 32 bytes")
}

/// Returns the secret key as a byte value.
Expand Down
49 changes: 8 additions & 41 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
//!
//! let secp = Secp256k1::new();
//! let (secret_key, public_key) = secp.generate_keypair(&mut OsRng);
//! let message = Message::from_hashed_data::<sha256::Hash>("Hello World!".as_bytes());
//! let message = Message::from_hashed_data("Hello World!".as_bytes());
//!
//! let sig = secp.sign_ecdsa(&message, &secret_key);
//! assert!(secp.verify_ecdsa(&message, &sig, &public_key).is_ok());
Expand All @@ -50,7 +50,7 @@
//! use secp256k1::hashes::sha256;
//!
//! let (secret_key, public_key) = generate_keypair(&mut rand::thread_rng());
//! let message = Message::from_hashed_data::<sha256::Hash>("Hello World!".as_bytes());
//! let message = Message::from_hashed_data("Hello World!".as_bytes());
//!
//! let sig = secret_key.sign_ecdsa(message);
//! assert!(sig.verify(&message, &public_key).is_ok());
Expand Down Expand Up @@ -176,8 +176,6 @@ use core::{fmt, mem, str};

#[cfg(all(feature = "global-context", feature = "std"))]
pub use context::global::{self, SECP256K1};
#[cfg(feature = "hashes")]
use hashes::Hash;
#[cfg(feature = "rand")]
pub use rand;
pub use secp256k1_sys as ffi;
Expand All @@ -203,21 +201,6 @@ pub trait ThirtyTwoByteHash {
fn into_32(self) -> [u8; 32];
}

#[cfg(feature = "hashes")]
impl ThirtyTwoByteHash for hashes::sha256::Hash {
fn into_32(self) -> [u8; 32] { self.to_byte_array() }
}

#[cfg(feature = "hashes")]
impl ThirtyTwoByteHash for hashes::sha256d::Hash {
fn into_32(self) -> [u8; 32] { self.to_byte_array() }
}

#[cfg(feature = "hashes")]
impl<T: hashes::sha256t::Tag> ThirtyTwoByteHash for hashes::sha256t::Hash<T> {
fn into_32(self) -> [u8; 32] { self.to_byte_array() }
}

/// A (hashed) message input to an ECDSA signature.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Message([u8; constants::MESSAGE_SIZE]);
Expand Down Expand Up @@ -284,16 +267,18 @@ impl Message {
/// use secp256k1::hashes::{sha256, Hash};
/// use secp256k1::Message;
///
/// let m1 = Message::from_hashed_data::<sha256::Hash>("Hello world!".as_bytes());
/// let m1 = Message::from_hashed_data("Hello world!".as_bytes());
/// // is equivalent to
/// let m2 = Message::from(sha256::Hash::hash("Hello world!".as_bytes()));
/// let m2 = Message::from_digest(sha256::Hash::hash("Hello world!".as_bytes()).to_byte_array());
///
/// assert_eq!(m1, m2);
/// # }
/// ```
#[cfg(feature = "hashes")]
pub fn from_hashed_data<H: ThirtyTwoByteHash + hashes::Hash>(data: &[u8]) -> Self {
<H as hashes::Hash>::hash(data).into()
pub fn from_hashed_data(data: &[u8]) -> Self {
use hashes::{sha256, Hash};
let hash = sha256::Hash::hash(data);
Message::from_digest(hash.to_byte_array())
}
}

Expand Down Expand Up @@ -1043,24 +1028,6 @@ mod tests {
let sig = SECP256K1.sign_ecdsa(&msg, &sk);
assert!(SECP256K1.verify_ecdsa(&msg, &sig, &pk).is_ok());
}

#[cfg(feature = "hashes")]
#[test]
fn test_from_hash() {
use hashes::{sha256, sha256d, Hash};

let test_bytes = "Hello world!".as_bytes();

let hash = sha256::Hash::hash(test_bytes);
let msg = Message::from(hash);
assert_eq!(msg.0, hash.to_byte_array());
assert_eq!(msg, Message::from_hashed_data::<hashes::sha256::Hash>(test_bytes));

let hash = sha256d::Hash::hash(test_bytes);
let msg = Message::from(hash);
assert_eq!(msg.0, hash.to_byte_array());
assert_eq!(msg, Message::from_hashed_data::<hashes::sha256d::Hash>(test_bytes));
}
}

#[cfg(bench)]
Expand Down

0 comments on commit 9d43945

Please sign in to comment.