From f8ae7ca8b770f9def261dcbc500c67e5b641f5d6 Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Tue, 7 Oct 2025 10:24:45 +0200 Subject: [PATCH] secp: update secp256k1 to 0.31 --- Cargo.lock | 37 +++++++++++++++++++++++---- Cargo.toml | 2 +- monad-eth-types/Cargo.toml | 1 - monad-eth-types/src/lib.rs | 7 ----- monad-secp/Cargo.toml | 1 + monad-secp/src/lib.rs | 8 ++++++ monad-secp/src/recoverable_address.rs | 6 ++--- monad-secp/src/secp.rs | 34 ++++++++++++------------ 8 files changed, 63 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec12483711..9cca987103 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1912,6 +1912,22 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -3615,6 +3631,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + [[package]] name = "hickory-proto" version = "0.24.4" @@ -5248,7 +5273,6 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "monad-crypto", - "monad-secp", "monad-types", "serde", ] @@ -5773,6 +5797,7 @@ dependencies = [ "insta", "k256", "monad-crypto", + "monad-eth-types", "monad-testutil", "proptest", "rand 0.8.5", @@ -8040,18 +8065,20 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.26.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4124a35fe33ae14259c490fd70fa199a32b9ce9502f2ee6bc4f81ec06fa65894" +checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" dependencies = [ + "bitcoin_hashes", + "rand 0.9.2", "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.8.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4473013577ec77b4ee3668179ef1186df3146e2cf2d927bd200974c6fe60fd99" +checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" dependencies = [ "cc", ] diff --git a/Cargo.toml b/Cargo.toml index d8a592dcae..bcfbf32031 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -185,7 +185,7 @@ reqwest = { version = "0.11", features = ["json"] } rstest = "0.25.0" schemars = "0.8.21" scrypt = { version = "0.11", default-features = false } -secp256k1 = "0.26" +secp256k1 = "0.31" serde = "1.0" serde_cbor = "0.11.2" serde_json = "1.0" diff --git a/monad-eth-types/Cargo.toml b/monad-eth-types/Cargo.toml index 3cea3b7fdf..55233a1f9c 100644 --- a/monad-eth-types/Cargo.toml +++ b/monad-eth-types/Cargo.toml @@ -10,7 +10,6 @@ bench = false [dependencies] monad-crypto = { workspace = true } -monad-secp = { workspace = true } monad-types = { workspace = true } alloy-consensus = { workspace = true, features = ["serde"] } diff --git a/monad-eth-types/src/lib.rs b/monad-eth-types/src/lib.rs index 7d07d58b81..662b1e7225 100644 --- a/monad-eth-types/src/lib.rs +++ b/monad-eth-types/src/lib.rs @@ -23,7 +23,6 @@ use alloy_rlp::{ Decodable, Encodable, RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper, }; use monad_crypto::NopPubKey; -use monad_secp::PubKey as SecpPubkey; use monad_types::{Balance, ExecutionProtocol, FinalizedHeader, Nonce, SeqNum}; pub mod serde; @@ -40,12 +39,6 @@ impl ExtractEthAddress for NopPubKey { } } -impl ExtractEthAddress for SecpPubkey { - fn get_eth_address(&self) -> Address { - Address::from_raw_public_key(&Self::bytes(self)[1..]) - } -} - #[derive(Debug, Copy, Clone)] pub struct EthAccount { pub nonce: Nonce, diff --git a/monad-secp/Cargo.toml b/monad-secp/Cargo.toml index bfca6cdcce..7ad0bb377a 100644 --- a/monad-secp/Cargo.toml +++ b/monad-secp/Cargo.toml @@ -10,6 +10,7 @@ bench = false [dependencies] monad-crypto = { workspace = true } +monad-eth-types = { workspace = true } alloy-consensus = { workspace = true } alloy-primitives = { workspace = true, features = ["k256"] } diff --git a/monad-secp/src/lib.rs b/monad-secp/src/lib.rs index 05683a18f8..e783d9222a 100644 --- a/monad-secp/src/lib.rs +++ b/monad-secp/src/lib.rs @@ -16,6 +16,7 @@ mod recoverable_address; mod secp; +use alloy_primitives::Address; use alloy_rlp::{Decodable, Encodable}; use monad_crypto::{ certificate_signature::{ @@ -24,10 +25,17 @@ use monad_crypto::{ }, signing_domain::SigningDomain, }; +pub use monad_eth_types::ExtractEthAddress; pub use recoverable_address::RecoverableAddress; pub use secp::{Error, KeyPair, PubKey, SecpSignature}; use serde::{Deserialize, Serialize}; +impl ExtractEthAddress for PubKey { + fn get_eth_address(&self) -> Address { + Address::from_raw_public_key(&self.bytes()[1..]) + } +} + impl std::fmt::Display for PubKey { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let bytes = self.bytes_compressed(); diff --git a/monad-secp/src/recoverable_address.rs b/monad-secp/src/recoverable_address.rs index 47246878ac..d295a305c4 100644 --- a/monad-secp/src/recoverable_address.rs +++ b/monad-secp/src/recoverable_address.rs @@ -29,7 +29,7 @@ pub trait RecoverableAddress { impl RecoverableAddress for TxEnvelope { fn secp256k1_recover(&self) -> Result { let signature_hash = self.signature_hash(); - let secp_message = Message::from_slice(signature_hash.as_ref())?; + let secp_message = Message::from_digest(*signature_hash.as_ref()); let secp = Secp256k1::new(); @@ -38,10 +38,10 @@ impl RecoverableAddress for TxEnvelope { let recoverable_sig = RecoverableSignature::from_compact( &signature[0..64], - RecoveryId::from_i32(recid as i32)?, + RecoveryId::try_from(recid as i32)?, )?; - let recovered_pubkey = secp.recover_ecdsa(&secp_message, &recoverable_sig)?; + let recovered_pubkey = secp.recover_ecdsa(secp_message, &recoverable_sig)?; let recovered_pubkey_bytes = recovered_pubkey.serialize_uncompressed(); let recovered_hash = keccak256(&recovered_pubkey_bytes[1..]); Ok(Address::from_slice(&recovered_hash[12..])) diff --git a/monad-secp/src/secp.rs b/monad-secp/src/secp.rs index ae8e431ff6..5de8785e93 100644 --- a/monad-secp/src/secp.rs +++ b/monad-secp/src/secp.rs @@ -22,7 +22,7 @@ use monad_crypto::{ hasher::{Hasher, HasherType}, signing_domain::SigningDomain, }; -use secp256k1::{ffi::CPtr, Secp256k1}; +use secp256k1::Secp256k1; use sha2::Sha256; use zeroize::{Zeroize, ZeroizeOnDrop}; @@ -30,7 +30,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; #[derive(Copy, Clone, PartialOrd, Ord)] pub struct PubKey(secp256k1::PublicKey); /// secp256k1 keypair -pub struct KeyPair(secp256k1::KeyPair); +pub struct KeyPair(secp256k1::Keypair); #[derive(ZeroizeOnDrop)] pub struct PrivKeyView(Vec); @@ -94,16 +94,20 @@ fn msg_hash(msg: &[u8]) -> secp256k1::Message { hasher.update(msg); let hash = hasher.hash(); - secp256k1::Message::from_slice(&hash.0).expect("32 bytes") + secp256k1::Message::from_digest(hash.0) } impl KeyPair { /// Create a keypair from a secret key slice. The secret is zero-ized after /// use. The secret must be 32 byytes. pub fn from_bytes(secret: &mut [u8]) -> Result { - let keypair = secp256k1::KeyPair::from_seckey_slice(secp256k1::SECP256K1, secret) - .map(Self) - .map_err(Error); + let secret_array: [u8; 32] = secret + .try_into() + .map_err(|_| Error(secp256k1::Error::InvalidSecretKey))?; + let keypair = + secp256k1::Keypair::from_seckey_byte_array(secp256k1::SECP256K1, secret_array) + .map(Self) + .map_err(Error); secret.zeroize(); keypair } @@ -123,7 +127,7 @@ impl KeyPair { pub fn sign(&self, msg: &[u8]) -> SecpSignature { SecpSignature(Secp256k1::sign_ecdsa_recoverable( secp256k1::SECP256K1, - &msg_hash::(msg), + msg_hash::(msg), &self.0.secret_key(), )) } @@ -164,7 +168,7 @@ impl PubKey { ) -> Result<(), Error> { Secp256k1::verify_ecdsa( secp256k1::SECP256K1, - &msg_hash::(msg), + msg_hash::(msg), &signature.0.to_standard(), &self.0, ) @@ -175,7 +179,7 @@ impl PubKey { impl SecpSignature { /// Recover the pubkey from signature given the message pub fn recover_pubkey(&self, msg: &[u8]) -> Result { - Secp256k1::recover_ecdsa(secp256k1::SECP256K1, &msg_hash::(msg), &self.0) + Secp256k1::recover_ecdsa(secp256k1::SECP256K1, msg_hash::(msg), &self.0) .map(PubKey) .map_err(Error) } @@ -185,9 +189,10 @@ impl SecpSignature { pub fn serialize(&self) -> [u8; secp256k1::constants::COMPACT_SIGNATURE_SIZE + 1] { // recid is 0..3, fit in a single byte (see secp256k1 https://docs.rs/secp256k1/0.27.0/src/secp256k1/ecdsa/recovery.rs.html#39) let (recid, sig) = self.0.serialize_compact(); - assert!((0..=3).contains(&recid.to_i32())); + let recid_byte = recid as u8; + assert!((0..=3).contains(&recid_byte)); let mut sig_vec = sig.to_vec(); - sig_vec.push(recid.to_i32() as u8); + sig_vec.push(recid_byte); sig_vec.try_into().unwrap() } @@ -197,7 +202,7 @@ impl SecpSignature { return Err(Error(secp256k1::Error::InvalidSignature)); } let sig_data = &data[..secp256k1::constants::COMPACT_SIGNATURE_SIZE]; - let recid = secp256k1::ecdsa::RecoveryId::from_i32( + let recid = secp256k1::ecdsa::RecoveryId::try_from( data[secp256k1::constants::COMPACT_SIGNATURE_SIZE] as i32, ) .map_err(Error)?; @@ -226,10 +231,7 @@ impl Decodable for SecpSignature { impl Drop for KeyPair { fn drop(&mut self) { - let ptr = self.0.as_mut_c_ptr(); - unsafe { - (*ptr).non_secure_erase(); - } + self.0.non_secure_erase(); } }