diff --git a/Cargo.lock b/Cargo.lock index ce95c1a8535..7efe5fd5aa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -665,16 +665,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", + "digest", ] [[package]] @@ -1138,16 +1129,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "ctr" version = "0.9.2" @@ -1177,7 +1158,7 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", - "digest 0.10.7", + "digest", "fiat-crypto", "rustc_version", "subtle", @@ -1218,7 +1199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18e4fdb82bd54a12e42fb58a800dcae6b9e13982238ce2296dc3570b92148e1f" dependencies = [ "data-encoding", - "syn 2.0.100", + "syn 1.0.109", ] [[package]] @@ -1282,22 +1263,13 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "const-oid", "crypto-common", "subtle", @@ -1358,7 +1330,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", - "digest 0.10.7", + "digest", "elliptic-curve", "rfc6979", "signature", @@ -1385,7 +1357,7 @@ dependencies = [ "ed25519", "rand_core 0.6.4", "serde", - "sha2 0.10.8", + "sha2", "subtle", "zeroize", ] @@ -1404,7 +1376,7 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.10.7", + "digest", "ff", "generic-array", "group", @@ -2021,17 +1993,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac 0.12.1", -] - -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac", - "digest 0.9.0", + "hmac", ] [[package]] @@ -2040,18 +2002,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array", - "hmac 0.8.1", + "digest", ] [[package]] @@ -2641,6 +2592,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + [[package]] name = "keccak" version = "0.1.5" @@ -2909,7 +2874,7 @@ dependencies = [ "rand 0.8.5", "regex", "serde", - "sha2 0.10.8", + "sha2", "tokio", "tracing", "tracing-subscriber", @@ -2940,7 +2905,7 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.2.10" +version = "0.2.11" dependencies = [ "asn1_der", "bs58", @@ -2948,7 +2913,7 @@ dependencies = [ "ed25519-dalek", "hex-literal", "hkdf", - "libsecp256k1", + "k256", "multihash", "p256", "quick-protobuf", @@ -2959,7 +2924,7 @@ dependencies = [ "sec1", "serde", "serde_json", - "sha2 0.10.8", + "sha2", "thiserror 2.0.12", "tracing", "zeroize", @@ -2988,7 +2953,7 @@ dependencies = [ "quickcheck-ext", "rand 0.8.5", "serde", - "sha2 0.10.8", + "sha2", "smallvec", "thiserror 2.0.12", "tokio", @@ -3505,7 +3470,7 @@ dependencies = [ "quick-protobuf-codec", "rand 0.8.5", "serde", - "sha2 0.10.8", + "sha2", "tinytemplate", "tracing", ] @@ -3616,54 +3581,6 @@ dependencies = [ "libc", ] -[[package]] -name = "libsecp256k1" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" -dependencies = [ - "arrayref", - "base64", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", - "rand 0.8.5", - "serde", - "sha2 0.9.9", - "typenum", -] - -[[package]] -name = "libsecp256k1-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" -dependencies = [ - "crunchy", - "digest 0.9.0", - "subtle", -] - -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" -dependencies = [ - "libsecp256k1-core", -] - [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -3745,7 +3662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest 0.10.7", + "digest", ] [[package]] @@ -4353,7 +4270,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.8", + "sha2", ] [[package]] @@ -4365,7 +4282,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.8", + "sha2", ] [[package]] @@ -5075,7 +4992,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac 0.12.1", + "hmac", "subtle", ] @@ -5201,7 +5118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d55b95147fe01265d06b3955db798bdaed52e60e2211c41137701b3aba8e21" dependencies = [ "globset", - "sha2 0.10.8", + "sha2", "walkdir", ] @@ -5518,20 +5435,7 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "digest", ] [[package]] @@ -5542,7 +5446,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] @@ -5551,7 +5455,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.7", + "digest", "keccak", ] @@ -5594,7 +5498,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest 0.10.7", + "digest", "rand_core 0.6.4", ] @@ -5652,7 +5556,7 @@ dependencies = [ "rand_core 0.6.4", "ring", "rustc_version", - "sha2 0.10.8", + "sha2", "subtle", ] @@ -6790,7 +6694,7 @@ dependencies = [ "sdp", "serde", "serde_json", - "sha2 0.10.8", + "sha2", "smol_str", "stun", "thiserror 1.0.69", @@ -6839,7 +6743,7 @@ dependencies = [ "ccm", "der-parser 9.0.0", "hkdf", - "hmac 0.12.1", + "hmac", "log", "p256", "p384", @@ -6853,7 +6757,7 @@ dependencies = [ "sec1", "serde", "sha1", - "sha2 0.10.8", + "sha2", "subtle", "thiserror 1.0.69", "tokio", @@ -6943,7 +6847,7 @@ dependencies = [ "byteorder", "bytes", "ctr", - "hmac 0.12.1", + "hmac", "log", "rtcp", "rtp", @@ -7021,7 +6925,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3507e0fd622..a7d9bdfa5cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,7 @@ libp2p-dns = { version = "0.43.0", path = "transports/dns" } libp2p-floodsub = { version = "0.46.1", path = "protocols/floodsub" } libp2p-gossipsub = { version = "0.49.0", path = "protocols/gossipsub" } libp2p-identify = { version = "0.47.0", path = "protocols/identify" } -libp2p-identity = { version = "0.2.10" } +libp2p-identity = { version = "0.2.11" } libp2p-kad = { version = "0.47.0", path = "protocols/kad" } libp2p-mdns = { version = "0.47.0", path = "protocols/mdns" } libp2p-memory-connection-limits = { version = "0.4.0", path = "misc/memory-connection-limits" } diff --git a/identity/CHANGELOG.md b/identity/CHANGELOG.md index 98f3e5c5636..81ce7ad718b 100644 --- a/identity/CHANGELOG.md +++ b/identity/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.2.11 + +- Switch from `libsecp256` to `k256` for secp256k1 support. + See [PR 5892](https://github.com/libp2p/rust-libp2p/pull/5892) + ## 0.2.10 - Deprecate `void` crate. diff --git a/identity/Cargo.toml b/identity/Cargo.toml index 67f2b3f459d..366de74eac5 100644 --- a/identity/Cargo.toml +++ b/identity/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libp2p-identity" -version = "0.2.10" +version = "0.2.11" edition = "2021" # MUST NOT inherit from workspace because we don't want to publish breaking changes to `libp2p-identity`. description = "Data structures and algorithms for identifying peers in libp2p." rust-version = "1.73.0" # MUST NOT inherit from workspace because we don't want to publish breaking changes to `libp2p-identity`. @@ -16,7 +16,7 @@ asn1_der = { version = "0.7.6", optional = true } bs58 = { version = "0.5.1", optional = true } ed25519-dalek = { version = "2.1", optional = true } hkdf = { version = "0.12.4", optional = true } -libsecp256k1 = { version = "0.7.0", optional = true } +k256 = { version = "0.13.4", optional = true, features = ["ecdsa", "arithmetic"] } tracing = { workspace = true } multihash = { version = "0.19.1", optional = true } p256 = { version = "0.13", default-features = false, features = ["ecdsa", "std", "pem"], optional = true } @@ -32,7 +32,7 @@ zeroize = { version = "1.8", optional = true } ring = { workspace = true, features = ["alloc", "std"], optional = true } [features] -secp256k1 = ["dep:libsecp256k1", "dep:asn1_der", "dep:sha2", "dep:hkdf", "dep:zeroize"] +secp256k1 = ["dep:k256", "dep:asn1_der", "dep:sha2", "dep:hkdf", "dep:zeroize"] ecdsa = ["dep:p256", "dep:zeroize", "dep:sec1", "dep:sha2", "dep:hkdf"] rsa = ["dep:ring", "dep:asn1_der", "dep:rand", "dep:zeroize"] ed25519 = ["dep:ed25519-dalek", "dep:zeroize", "dep:sha2", "dep:hkdf"] diff --git a/identity/src/secp256k1.rs b/identity/src/secp256k1.rs index e884cf1385d..c56b52f035e 100644 --- a/identity/src/secp256k1.rs +++ b/identity/src/secp256k1.rs @@ -23,8 +23,11 @@ use core::{cmp, fmt, hash}; use asn1_der::typed::{DerDecodable, Sequence}; -use libsecp256k1::{Message, Signature}; -use sha2::{Digest as ShaDigestTrait, Sha256}; +use k256::{ + ecdsa::Signature, + sha2::{Digest as ShaDigestTrait, Sha256}, + ProjectivePoint, +}; use zeroize::Zeroize; use super::error::DecodingError; @@ -65,7 +68,7 @@ impl fmt::Debug for Keypair { /// Promote a Secp256k1 secret key into a keypair. impl From for Keypair { fn from(secret: SecretKey) -> Keypair { - let public = PublicKey(libsecp256k1::PublicKey::from_secret_key(&secret.0)); + let public = PublicKey(*secret.0.verifying_key()); Keypair { secret, public } } } @@ -79,7 +82,7 @@ impl From for SecretKey { /// A Secp256k1 secret key. #[derive(Clone)] -pub struct SecretKey(libsecp256k1::SecretKey); +pub struct SecretKey(k256::ecdsa::SigningKey); impl fmt::Debug for SecretKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -91,7 +94,7 @@ impl SecretKey { /// Generate a new random Secp256k1 secret key. #[cfg(feature = "rand")] pub fn generate() -> SecretKey { - SecretKey(libsecp256k1::SecretKey::random(&mut rand::thread_rng())) + SecretKey(k256::ecdsa::SigningKey::random(&mut rand::thread_rng())) } /// Create a secret key from a byte slice, zeroing the slice on success. @@ -101,7 +104,7 @@ impl SecretKey { /// Note that the expected binary format is the same as `libsecp256k1`'s. pub fn try_from_bytes(mut sk: impl AsMut<[u8]>) -> Result { let sk_bytes = sk.as_mut(); - let secret = libsecp256k1::SecretKey::parse_slice(&*sk_bytes) + let secret = k256::ecdsa::SigningKey::from_slice(sk_bytes) .map_err(|e| DecodingError::failed_to_parse("parse secp256k1 secret key", e))?; sk_bytes.zeroize(); Ok(SecretKey(secret)) @@ -131,30 +134,23 @@ impl SecretKey { /// /// [RFC3278]: https://tools.ietf.org/html/rfc3278#section-8.2 pub fn sign(&self, msg: &[u8]) -> Vec { - let generic_array = Sha256::digest(msg); + use k256::ecdsa::signature::Signer; - // FIXME: Once `generic-array` hits 1.0, we should be able to just use `Into` here. - let mut array = [0u8; 32]; - array.copy_from_slice(generic_array.as_slice()); - - let message = Message::parse(&array); - - libsecp256k1::sign(&message, &self.0) - .0 - .serialize_der() - .as_ref() - .into() + Signer::::sign(&self.0, msg) + .to_der() + .to_bytes() + .into_vec() } /// Returns the raw bytes of the secret key. pub fn to_bytes(&self) -> [u8; 32] { - self.0.serialize() + self.0.to_bytes().into() } } /// A Secp256k1 public key. #[derive(Eq, Clone)] -pub struct PublicKey(libsecp256k1::PublicKey); +pub struct PublicKey(k256::ecdsa::VerifyingKey); impl fmt::Debug for PublicKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -193,31 +189,46 @@ impl cmp::Ord for PublicKey { impl PublicKey { /// Verify the Secp256k1 signature on a message using the public key. pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool { - self.verify_hash(Sha256::digest(msg).as_ref(), sig) + let digest = Sha256::new_with_prefix(msg); + self.verify_hash(digest.finalize().as_slice(), sig) } - /// Verify the Secp256k1 DER-encoded signature on a raw 256-bit message using the public key. + /// Verify the Secp256k1 DER-encoded signature on a raw 256-bit message using the public key. + /// Will return false if the hash is not 32 bytes long, or the signature cannot be parsed. pub fn verify_hash(&self, msg: &[u8], sig: &[u8]) -> bool { - Message::parse_slice(msg) - .and_then(|m| Signature::parse_der(sig).map(|s| libsecp256k1::verify(&m, &s, &self.0))) - .unwrap_or(false) + Signature::from_der(sig).is_ok_and(|s| { + k256::ecdsa::hazmat::verify_prehashed( + &ProjectivePoint::from(self.0.as_affine()), + msg.into(), + &s, + ) + .is_ok() + }) } /// Convert the public key to a byte buffer in compressed form, i.e. with one coordinate /// represented by a single bit. pub fn to_bytes(&self) -> [u8; 33] { - self.0.serialize_compressed() + let encoded_point = self.0.to_encoded_point(true); + debug_assert!(encoded_point.as_bytes().len() == 33); + let mut array: [u8; 33] = [0u8; 33]; + array.copy_from_slice(encoded_point.as_bytes()); + array } /// Convert the public key to a byte buffer in uncompressed form. pub fn to_bytes_uncompressed(&self) -> [u8; 65] { - self.0.serialize() + let encoded_point = self.0.to_encoded_point(false); + debug_assert!(encoded_point.as_bytes().len() == 65); + let mut array: [u8; 65] = [0u8; 65]; + array.copy_from_slice(encoded_point.as_bytes()); + array } /// Decode a public key from a byte slice in the format produced /// by `encode`. pub fn try_from_bytes(k: &[u8]) -> Result { - libsecp256k1::PublicKey::parse_slice(k, Some(libsecp256k1::PublicKeyFormat::Compressed)) + k256::ecdsa::VerifyingKey::from_sec1_bytes(k) .map_err(|e| DecodingError::failed_to_parse("secp256k1 public key", e)) .map(PublicKey) } @@ -232,9 +243,9 @@ mod tests { fn secp256k1_secret_from_bytes() { let sk1 = SecretKey::generate(); let mut sk_bytes = [0; 32]; - sk_bytes.copy_from_slice(&sk1.0.serialize()[..]); + sk_bytes.copy_from_slice(&sk1.to_bytes()[..]); let sk2 = SecretKey::try_from_bytes(&mut sk_bytes).unwrap(); - assert_eq!(sk1.0.serialize(), sk2.0.serialize()); + assert_eq!(sk1.to_bytes(), sk2.to_bytes()); assert_eq!(sk_bytes, [0; 32]); } }