diff --git a/Cargo.lock b/Cargo.lock
index cc0d04f62..6c1146640 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2616,6 +2616,7 @@ dependencies = [
"digest 0.10.7",
"elliptic-curve",
"rfc6979",
+ "serdect",
"signature",
"spki",
]
@@ -2690,6 +2691,7 @@ dependencies = [
"pkcs8",
"rand_core 0.6.4",
"sec1",
+ "serdect",
"subtle",
"zeroize",
]
@@ -4622,6 +4624,7 @@ dependencies = [
"ecdsa",
"elliptic-curve",
"once_cell",
+ "serdect",
"sha2 0.10.8",
"signature",
]
@@ -8741,7 +8744,6 @@ dependencies = [
"c-kzg",
"criterion",
"derive_more",
- "k256",
"modular-bitfield",
"once_cell",
"op-alloy-consensus",
@@ -8783,6 +8785,7 @@ dependencies = [
"byteorder",
"bytes",
"derive_more",
+ "k256",
"modular-bitfield",
"op-alloy-consensus",
"proptest",
@@ -8790,6 +8793,7 @@ dependencies = [
"rand 0.8.5",
"reth-codecs",
"revm-primitives",
+ "secp256k1",
"serde",
"serde_json",
"serde_with",
@@ -10179,6 +10183,7 @@ dependencies = [
"der",
"generic-array",
"pkcs8",
+ "serdect",
"subtle",
"zeroize",
]
@@ -10385,6 +10390,16 @@ dependencies = [
"syn 2.0.90",
]
+[[package]]
+name = "serdect"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177"
+dependencies = [
+ "base16ct",
+ "serde",
+]
+
[[package]]
name = "serial_test"
version = "3.2.0"
diff --git a/crates/primitives-traits/Cargo.toml b/crates/primitives-traits/Cargo.toml
index 459fdbde1..2470f9308 100644
--- a/crates/primitives-traits/Cargo.toml
+++ b/crates/primitives-traits/Cargo.toml
@@ -26,6 +26,12 @@ revm-primitives.workspace = true
# op
op-alloy-consensus = { workspace = true, optional = true }
+# crypto
+secp256k1 = { workspace = true, features = [
+ "recovery",
+], optional = true }
+k256.workspace = true
+
# misc
byteorder = { workspace = true, optional = true }
bytes.workspace = true
@@ -67,8 +73,11 @@ std = [
"serde_with?/std",
"alloy-rlp/std",
"bytes/std",
- "derive_more/std"
+ "derive_more/std",
+ "k256/std",
+ "secp256k1?/std"
]
+secp256k1 = ["dep:secp256k1"]
test-utils = [
"arbitrary",
"reth-codecs?/test-utils"
@@ -102,7 +111,9 @@ serde = [
"reth-codecs?/serde",
"revm-primitives/serde",
"revm-primitives/serde",
- "op-alloy-consensus?/serde"
+ "op-alloy-consensus?/serde",
+ "k256/serde",
+ "secp256k1?/serde"
]
reth-codec = [
"dep:reth-codecs",
diff --git a/crates/primitives-traits/src/crypto.rs b/crates/primitives-traits/src/crypto.rs
new file mode 100644
index 000000000..cc9c8aaf3
--- /dev/null
+++ b/crates/primitives-traits/src/crypto.rs
@@ -0,0 +1,213 @@
+//! Crypto utilities.
+
+use crate::transaction::signature::Signature;
+use alloy_primitives::U256;
+
+/// The order of the secp256k1 curve, divided by two. Signatures that should be checked according
+/// to EIP-2 should have an S value less than or equal to this.
+///
+/// `57896044618658097711785492504343953926418782139537452191302581570759080747168`
+pub const SECP256K1N_HALF: U256 = U256::from_be_bytes([
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x5D, 0x57, 0x6E, 0x73, 0x57, 0xA4, 0x50, 0x1D, 0xDF, 0xE9, 0x2F, 0x46, 0x68, 0x1B, 0x20, 0xA0,
+]);
+
+/// Secp256k1 utility functions.
+#[cfg(feature = "secp256k1")]
+pub mod secp256k1 {
+ pub use super::impl_secp256k1::*;
+}
+
+/// Secp256k1 utility functions.
+#[cfg(not(feature = "secp256k1"))]
+pub mod secp256k1 {
+ pub use super::impl_k256::*;
+}
+
+#[cfg(feature = "secp256k1")]
+#[allow(unused)]
+mod impl_secp256k1 {
+ use super::*;
+ pub(crate) use ::secp256k1::Error;
+ use ::secp256k1::{
+ ecdsa::{RecoverableSignature, RecoveryId},
+ Message, PublicKey, SecretKey, SECP256K1,
+ };
+ use alloy_primitives::{keccak256, Address, B256, U256};
+
+ /// Recovers the address of the sender using secp256k1 pubkey recovery.
+ ///
+ /// Converts the public key into an ethereum address by hashing the public key with keccak256.
+ ///
+ /// This does not ensure that the `s` value in the signature is low, and _just_ wraps the
+ /// underlying secp256k1 library.
+ pub fn recover_signer_unchecked(sig: &[u8; 65], msg: &[u8; 32]) -> Result
{
+ let sig =
+ RecoverableSignature::from_compact(&sig[0..64], RecoveryId::from_i32(sig[64] as i32)?)?;
+
+ let public = SECP256K1.recover_ecdsa(&Message::from_digest(*msg), &sig)?;
+ Ok(public_key_to_address(public))
+ }
+
+ /// Signs message with the given secret key.
+ /// Returns the corresponding signature.
+ pub fn sign_message(secret: B256, message: B256) -> Result {
+ let sec = SecretKey::from_slice(secret.as_ref())?;
+ let s = SECP256K1.sign_ecdsa_recoverable(&Message::from_digest(message.0), &sec);
+ let (rec_id, data) = s.serialize_compact();
+
+ let signature = Signature::new(
+ U256::try_from_be_slice(&data[..32]).expect("The slice has at most 32 bytes"),
+ U256::try_from_be_slice(&data[32..64]).expect("The slice has at most 32 bytes"),
+ rec_id.to_i32() != 0,
+ );
+ Ok(signature)
+ }
+
+ /// Converts a public key into an ethereum address by hashing the encoded public key with
+ /// keccak256.
+ pub fn public_key_to_address(public: PublicKey) -> Address {
+ // strip out the first byte because that should be the SECP256K1_TAG_PUBKEY_UNCOMPRESSED
+ // tag returned by libsecp's uncompressed pubkey serialization
+ let hash = keccak256(&public.serialize_uncompressed()[1..]);
+ Address::from_slice(&hash[12..])
+ }
+}
+
+#[cfg_attr(feature = "secp256k1", allow(unused, unreachable_pub))]
+mod impl_k256 {
+ use super::*;
+ use alloy_primitives::{keccak256, Address, B256};
+ pub(crate) use k256::ecdsa::Error;
+ use k256::ecdsa::{RecoveryId, SigningKey, VerifyingKey};
+
+ /// Recovers the address of the sender using secp256k1 pubkey recovery.
+ ///
+ /// Converts the public key into an ethereum address by hashing the public key with keccak256.
+ ///
+ /// This does not ensure that the `s` value in the signature is low, and _just_ wraps the
+ /// underlying secp256k1 library.
+ pub fn recover_signer_unchecked(sig: &[u8; 65], msg: &[u8; 32]) -> Result {
+ let mut signature = k256::ecdsa::Signature::from_slice(&sig[0..64])?;
+ let mut recid = sig[64];
+
+ // normalize signature and flip recovery id if needed.
+ if let Some(sig_normalized) = signature.normalize_s() {
+ signature = sig_normalized;
+ recid ^= 1;
+ }
+ let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid");
+
+ // recover key
+ let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &signature, recid)?;
+ Ok(public_key_to_address(recovered_key))
+ }
+
+ /// Signs message with the given secret key.
+ /// Returns the corresponding signature.
+ pub fn sign_message(secret: B256, message: B256) -> Result {
+ let sec = SigningKey::from_slice(secret.as_ref())?;
+ sec.sign_prehash_recoverable(&message.0).map(Into::into)
+ }
+
+ /// Converts a public key into an ethereum address by hashing the encoded public key with
+ /// keccak256.
+ pub fn public_key_to_address(public: VerifyingKey) -> Address {
+ let hash = keccak256(&public.to_encoded_point(/* compress = */ false).as_bytes()[1..]);
+ Address::from_slice(&hash[12..])
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use alloy_primitives::{keccak256, B256};
+
+ #[cfg(feature = "secp256k1")]
+ #[test]
+ fn sanity_ecrecover_call_secp256k1() {
+ use super::impl_secp256k1::*;
+
+ let (secret, public) = secp256k1::generate_keypair(&mut rand::thread_rng());
+ let signer = public_key_to_address(public);
+
+ let message = b"hello world";
+ let hash = keccak256(message);
+ let signature =
+ sign_message(B256::from_slice(&secret.secret_bytes()[..]), hash).expect("sign message");
+
+ let mut sig: [u8; 65] = [0; 65];
+ sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
+ sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
+ sig[64] = signature.v() as u8;
+
+ assert_eq!(recover_signer_unchecked(&sig, &hash), Ok(signer));
+ }
+
+ #[cfg(not(feature = "secp256k1"))]
+ #[test]
+ fn sanity_ecrecover_call_k256() {
+ use super::impl_k256::*;
+
+ let secret = k256::ecdsa::SigningKey::random(&mut rand::thread_rng());
+ let public = *secret.verifying_key();
+ let signer = public_key_to_address(public);
+
+ let message = b"hello world";
+ let hash = keccak256(message);
+ let signature =
+ sign_message(B256::from_slice(&secret.to_bytes()[..]), hash).expect("sign message");
+
+ let mut sig: [u8; 65] = [0; 65];
+ sig[0..32].copy_from_slice(&signature.r.to_be_bytes::<32>());
+ sig[32..64].copy_from_slice(&signature.s.to_be_bytes::<32>());
+ sig[64] = signature.odd_y_parity as u8;
+
+ assert_eq!(recover_signer_unchecked(&sig, &hash).ok(), Some(signer));
+ }
+
+ #[test]
+ fn sanity_secp256k1_k256_compat() {
+ use super::{impl_k256, impl_secp256k1};
+
+ let (secp256k1_secret, secp256k1_public) =
+ secp256k1::generate_keypair(&mut rand::thread_rng());
+ let k256_secret = k256::ecdsa::SigningKey::from_slice(&secp256k1_secret.secret_bytes())
+ .expect("k256 secret");
+ let k256_public = *k256_secret.verifying_key();
+
+ let secp256k1_signer = impl_secp256k1::public_key_to_address(secp256k1_public);
+ let k256_signer = impl_k256::public_key_to_address(k256_public);
+ assert_eq!(secp256k1_signer, k256_signer);
+
+ let message = b"hello world";
+ let hash = keccak256(message);
+
+ let secp256k1_signature = impl_secp256k1::sign_message(
+ B256::from_slice(&secp256k1_secret.secret_bytes()[..]),
+ hash,
+ )
+ .expect("secp256k1 sign");
+ let k256_signature =
+ impl_k256::sign_message(B256::from_slice(&k256_secret.to_bytes()[..]), hash)
+ .expect("k256 sign");
+ assert_eq!(secp256k1_signature, k256_signature);
+
+ let mut sig: [u8; 65] = [0; 65];
+
+ sig[0..32].copy_from_slice(&secp256k1_signature.r().to_be_bytes::<32>());
+ sig[32..64].copy_from_slice(&secp256k1_signature.s().to_be_bytes::<32>());
+ sig[64] = secp256k1_signature.v() as u8;
+ let secp256k1_recovered =
+ impl_secp256k1::recover_signer_unchecked(&sig, &hash).expect("secp256k1 recover");
+ assert_eq!(secp256k1_recovered, secp256k1_signer);
+
+ sig[0..32].copy_from_slice(&k256_signature.r().to_be_bytes::<32>());
+ sig[32..64].copy_from_slice(&k256_signature.s().to_be_bytes::<32>());
+ sig[64] = k256_signature.v() as u8;
+ let k256_recovered =
+ impl_k256::recover_signer_unchecked(&sig, &hash).expect("k256 recover");
+ assert_eq!(k256_recovered, k256_signer);
+
+ assert_eq!(secp256k1_recovered, k256_recovered);
+ }
+}
diff --git a/crates/primitives-traits/src/lib.rs b/crates/primitives-traits/src/lib.rs
index b620bc535..74d10fc3c 100644
--- a/crates/primitives-traits/src/lib.rs
+++ b/crates/primitives-traits/src/lib.rs
@@ -1,4 +1,21 @@
-//! Common abstracted types in Reth.
+//! Commonly used types and traits in Reth.
+//!
+//! This crate contains various primitive traits used across reth's components.
+//! It provides the [`Block`] trait which is used to represent a block and all its components.
+//! A [`Block`] is composed of a [`Header`] and a [`BlockBody`]. In ethereum (and optimism), a block
+//! body consists of a list of transactions, a list of uncle headers, and a list of withdrawals. For
+//! optimism, uncle headers and withdrawals are always empty lists.
+//!
+//! ## Feature Flags
+//!
+//! - `arbitrary`: Adds `proptest` and `arbitrary` support for primitive types.
+//! - `op`: Implements the traits for various [op-alloy](https://github.com/alloy-rs/op-alloy)
+//! types.
+//! - `reth-codec`: Enables db codec support for reth types including zstd compression for certain
+//! types.
+//! - `serde`: Adds serde support for all types.
+//! - `secp256k1`: Adds secp256k1 support for transaction signing/recovery. (By default the no-std
+//! friendly `k256` is used)
#![doc(
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
@@ -41,6 +58,8 @@ mod encoded;
mod withdrawal;
pub use encoded::WithEncoded;
+pub mod crypto;
+
mod error;
pub use error::{GotExpected, GotExpectedBoxed};
diff --git a/crates/primitives-traits/src/transaction/mod.rs b/crates/primitives-traits/src/transaction/mod.rs
index 874fd494f..a75e371e9 100644
--- a/crates/primitives-traits/src/transaction/mod.rs
+++ b/crates/primitives-traits/src/transaction/mod.rs
@@ -1,6 +1,7 @@
//! Transaction abstraction
pub mod execute;
+pub mod signature;
pub mod signed;
pub mod error;
diff --git a/crates/primitives-traits/src/transaction/signature.rs b/crates/primitives-traits/src/transaction/signature.rs
new file mode 100644
index 000000000..1ff56671b
--- /dev/null
+++ b/crates/primitives-traits/src/transaction/signature.rs
@@ -0,0 +1,4 @@
+//! Signature types and helpers
+
+/// Re-exported signature type
+pub use alloy_primitives::PrimitiveSignature as Signature;
diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml
index 109b20ec2..712abd652 100644
--- a/crates/primitives/Cargo.toml
+++ b/crates/primitives/Cargo.toml
@@ -37,15 +37,15 @@ op-alloy-consensus = { workspace = true, features = [
"serde",
], optional = true }
+# for eip-4844
+c-kzg = { workspace = true, features = ["serde"], optional = true }
+
# crypto
secp256k1 = { workspace = true, features = [
"global-context",
"recovery",
"rand",
], optional = true }
-k256.workspace = true
-# for eip-4844
-c-kzg = { workspace = true, features = ["serde"], optional = true }
# misc
bytes.workspace = true
@@ -73,6 +73,12 @@ alloy-eips = { workspace = true, features = ["arbitrary"] }
alloy-genesis.workspace = true
arbitrary = { workspace = true, features = ["derive"] }
+secp256k1 = { workspace = true, features = [
+ "global-context",
+ "recovery",
+ "rand",
+] }
+
assert_matches.workspace = true
bincode.workspace = true
proptest-arbitrary-interop.workspace = true
@@ -98,10 +104,8 @@ std = [
"alloy-genesis/std",
"alloy-primitives/std",
"alloy-serde?/std",
- "k256/std",
"once_cell/std",
"revm-primitives/std",
- "secp256k1?/std",
"serde/std",
"alloy-trie/std",
"serde_with?/std",
@@ -109,7 +113,8 @@ std = [
"reth-ethereum-forks/std",
"bytes/std",
"derive_more/std",
- "reth-zstd-compressors?/std"
+ "reth-zstd-compressors?/std",
+ "secp256k1?/std"
]
reth-codec = [
"dep:reth-codecs",
@@ -126,7 +131,6 @@ arbitrary = [
"reth-ethereum-forks/arbitrary",
"reth-primitives-traits/arbitrary",
"revm-primitives/arbitrary",
- "secp256k1",
"reth-chainspec/arbitrary",
"alloy-consensus/arbitrary",
"alloy-primitives/arbitrary",
@@ -136,9 +140,12 @@ arbitrary = [
"op-alloy-rpc-types?/arbitrary",
"reth-codecs?/arbitrary",
"alloy-trie/arbitrary",
- "reth-trie-common/arbitrary"
+ "reth-trie-common/arbitrary",
+ "dep:secp256k1"
+]
+secp256k1 = [
+ "reth-primitives-traits/secp256k1",
]
-secp256k1 = ["dep:secp256k1"]
c-kzg = [
"dep:c-kzg",
"alloy-consensus/kzg",
diff --git a/crates/primitives/src/transaction/signature.rs b/crates/primitives/src/transaction/signature.rs
index 6056266ae..f2850aeca 100644
--- a/crates/primitives/src/transaction/signature.rs
+++ b/crates/primitives/src/transaction/signature.rs
@@ -2,15 +2,7 @@ use crate::transaction::util::secp256k1;
use alloy_consensus::transaction::from_eip155_value;
use alloy_primitives::{Address, PrimitiveSignature as Signature, B256, U256};
use alloy_rlp::Decodable;
-
-/// The order of the secp256k1 curve, divided by two. Signatures that should be checked according
-/// to EIP-2 should have an S value less than or equal to this.
-///
-/// `57896044618658097711785492504343953926418782139537452191302581570759080747168`
-const SECP256K1N_HALF: U256 = U256::from_be_bytes([
- 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x5D, 0x57, 0x6E, 0x73, 0x57, 0xA4, 0x50, 0x1D, 0xDF, 0xE9, 0x2F, 0x46, 0x68, 0x1B, 0x20, 0xA0,
-]);
+use reth_primitives_traits::crypto::SECP256K1N_HALF;
pub(crate) fn decode_with_eip155_chain_id(
buf: &mut &[u8],
diff --git a/crates/primitives/src/transaction/util.rs b/crates/primitives/src/transaction/util.rs
index 8eb1a639d..98c8468cf 100644
--- a/crates/primitives/src/transaction/util.rs
+++ b/crates/primitives/src/transaction/util.rs
@@ -1,201 +1,3 @@
//! Utility functions for signature.
-use alloy_primitives::{Address, PrimitiveSignature as Signature};
-
-/// Secp256k1 utility functions.
-#[cfg(feature = "secp256k1")]
-pub mod secp256k1 {
- pub use super::impl_secp256k1::*;
-}
-
-#[cfg(not(feature = "secp256k1"))]
-pub(crate) mod secp256k1 {
- pub use super::impl_k256::*;
-}
-
-#[cfg(feature = "secp256k1")]
-mod impl_secp256k1 {
- use super::*;
- pub(crate) use ::secp256k1::Error;
- use ::secp256k1::{
- ecdsa::{RecoverableSignature, RecoveryId},
- Message, PublicKey, SecretKey, SECP256K1,
- };
- use alloy_primitives::{keccak256, B256, U256};
-
- /// Recovers the address of the sender using secp256k1 pubkey recovery.
- ///
- /// Converts the public key into an ethereum address by hashing the public key with keccak256.
- ///
- /// This does not ensure that the `s` value in the signature is low, and _just_ wraps the
- /// underlying secp256k1 library.
- pub fn recover_signer_unchecked(sig: &[u8; 65], msg: &[u8; 32]) -> Result {
- let sig =
- RecoverableSignature::from_compact(&sig[0..64], RecoveryId::from_i32(sig[64] as i32)?)?;
-
- let public = SECP256K1.recover_ecdsa(&Message::from_digest(*msg), &sig)?;
- Ok(public_key_to_address(public))
- }
-
- /// Signs message with the given secret key.
- /// Returns the corresponding signature.
- pub fn sign_message(secret: B256, message: B256) -> Result {
- let sec = SecretKey::from_slice(secret.as_ref())?;
- let s = SECP256K1.sign_ecdsa_recoverable(&Message::from_digest(message.0), &sec);
- let (rec_id, data) = s.serialize_compact();
-
- let signature = Signature::new(
- U256::try_from_be_slice(&data[..32]).expect("The slice has at most 32 bytes"),
- U256::try_from_be_slice(&data[32..64]).expect("The slice has at most 32 bytes"),
- rec_id.to_i32() != 0,
- );
- Ok(signature)
- }
-
- /// Converts a public key into an ethereum address by hashing the encoded public key with
- /// keccak256.
- pub fn public_key_to_address(public: PublicKey) -> Address {
- // strip out the first byte because that should be the SECP256K1_TAG_PUBKEY_UNCOMPRESSED
- // tag returned by libsecp's uncompressed pubkey serialization
- let hash = keccak256(&public.serialize_uncompressed()[1..]);
- Address::from_slice(&hash[12..])
- }
-}
-
-#[cfg_attr(feature = "secp256k1", allow(unused, unreachable_pub))]
-mod impl_k256 {
- use super::*;
- use alloy_primitives::{keccak256, B256};
- pub(crate) use k256::ecdsa::Error;
- use k256::ecdsa::{RecoveryId, SigningKey, VerifyingKey};
-
- /// Recovers the address of the sender using secp256k1 pubkey recovery.
- ///
- /// Converts the public key into an ethereum address by hashing the public key with keccak256.
- ///
- /// This does not ensure that the `s` value in the signature is low, and _just_ wraps the
- /// underlying secp256k1 library.
- pub fn recover_signer_unchecked(sig: &[u8; 65], msg: &[u8; 32]) -> Result {
- let mut signature = k256::ecdsa::Signature::from_slice(&sig[0..64])?;
- let mut recid = sig[64];
-
- // normalize signature and flip recovery id if needed.
- if let Some(sig_normalized) = signature.normalize_s() {
- signature = sig_normalized;
- recid ^= 1;
- }
- let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid");
-
- // recover key
- let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &signature, recid)?;
- Ok(public_key_to_address(recovered_key))
- }
-
- /// Signs message with the given secret key.
- /// Returns the corresponding signature.
- pub fn sign_message(secret: B256, message: B256) -> Result {
- let sec = SigningKey::from_slice(secret.as_ref())?;
- sec.sign_prehash_recoverable(&message.0).map(Into::into)
- }
-
- /// Converts a public key into an ethereum address by hashing the encoded public key with
- /// keccak256.
- pub fn public_key_to_address(public: VerifyingKey) -> Address {
- let hash = keccak256(&public.to_encoded_point(/* compress = */ false).as_bytes()[1..]);
- Address::from_slice(&hash[12..])
- }
-}
-
-#[cfg(test)]
-mod tests {
- use alloy_primitives::{keccak256, B256};
-
- #[cfg(feature = "secp256k1")]
- #[test]
- fn sanity_ecrecover_call_secp256k1() {
- use super::impl_secp256k1::*;
-
- let (secret, public) = secp256k1::generate_keypair(&mut rand::thread_rng());
- let signer = public_key_to_address(public);
-
- let message = b"hello world";
- let hash = keccak256(message);
- let signature =
- sign_message(B256::from_slice(&secret.secret_bytes()[..]), hash).expect("sign message");
-
- let mut sig: [u8; 65] = [0; 65];
- sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
- sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
- sig[64] = signature.v() as u8;
-
- assert_eq!(recover_signer_unchecked(&sig, &hash), Ok(signer));
- }
-
- #[cfg(not(feature = "secp256k1"))]
- #[test]
- fn sanity_ecrecover_call_k256() {
- use super::impl_k256::*;
-
- let secret = k256::ecdsa::SigningKey::random(&mut rand::thread_rng());
- let public = *secret.verifying_key();
- let signer = public_key_to_address(public);
-
- let message = b"hello world";
- let hash = keccak256(message);
- let signature =
- sign_message(B256::from_slice(&secret.to_bytes()[..]), hash).expect("sign message");
-
- let mut sig: [u8; 65] = [0; 65];
- sig[0..32].copy_from_slice(&signature.r.to_be_bytes::<32>());
- sig[32..64].copy_from_slice(&signature.s.to_be_bytes::<32>());
- sig[64] = signature.odd_y_parity as u8;
-
- assert_eq!(recover_signer_unchecked(&sig, &hash).ok(), Some(signer));
- }
-
- #[test]
- fn sanity_secp256k1_k256_compat() {
- use super::{impl_k256, impl_secp256k1};
-
- let (secp256k1_secret, secp256k1_public) =
- secp256k1::generate_keypair(&mut rand::thread_rng());
- let k256_secret = k256::ecdsa::SigningKey::from_slice(&secp256k1_secret.secret_bytes())
- .expect("k256 secret");
- let k256_public = *k256_secret.verifying_key();
-
- let secp256k1_signer = impl_secp256k1::public_key_to_address(secp256k1_public);
- let k256_signer = impl_k256::public_key_to_address(k256_public);
- assert_eq!(secp256k1_signer, k256_signer);
-
- let message = b"hello world";
- let hash = keccak256(message);
-
- let secp256k1_signature = impl_secp256k1::sign_message(
- B256::from_slice(&secp256k1_secret.secret_bytes()[..]),
- hash,
- )
- .expect("secp256k1 sign");
- let k256_signature =
- impl_k256::sign_message(B256::from_slice(&k256_secret.to_bytes()[..]), hash)
- .expect("k256 sign");
- assert_eq!(secp256k1_signature, k256_signature);
-
- let mut sig: [u8; 65] = [0; 65];
-
- sig[0..32].copy_from_slice(&secp256k1_signature.r().to_be_bytes::<32>());
- sig[32..64].copy_from_slice(&secp256k1_signature.s().to_be_bytes::<32>());
- sig[64] = secp256k1_signature.v() as u8;
- let secp256k1_recovered =
- impl_secp256k1::recover_signer_unchecked(&sig, &hash).expect("secp256k1 recover");
- assert_eq!(secp256k1_recovered, secp256k1_signer);
-
- sig[0..32].copy_from_slice(&k256_signature.r().to_be_bytes::<32>());
- sig[32..64].copy_from_slice(&k256_signature.s().to_be_bytes::<32>());
- sig[64] = k256_signature.v() as u8;
- let k256_recovered =
- impl_k256::recover_signer_unchecked(&sig, &hash).expect("k256 recover");
- assert_eq!(k256_recovered, k256_signer);
-
- assert_eq!(secp256k1_recovered, k256_recovered);
- }
-}
+pub use reth_primitives_traits::crypto::*;