Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add secp256k1 feature in reth-network-peers #8712

Merged
merged 5 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ reth-net-common = { path = "crates/net/common" }
reth-net-nat = { path = "crates/net/nat" }
reth-network = { path = "crates/net/network" }
reth-network-api = { path = "crates/net/network-api" }
reth-network-peers = { path = "crates/net/peers" }
reth-network-peers = { path = "crates/net/peers", default-features = false }
reth-network-p2p = { path = "crates/net/p2p" }
reth-nippy-jar = { path = "crates/storage/nippy-jar" }
reth-node-api = { path = "crates/node/api" }
Expand Down
2 changes: 1 addition & 1 deletion crates/net/discv4/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ workspace = true
reth-primitives.workspace = true
reth-net-common.workspace = true
reth-net-nat.workspace = true
reth-network-peers.workspace = true
reth-network-peers = { workspace = true, features = ["secp256k1"] }

# ethereum
alloy-rlp = { workspace = true, features = ["derive"] }
Expand Down
2 changes: 1 addition & 1 deletion crates/net/discv5/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ workspace = true
# reth
reth-primitives.workspace = true
reth-metrics.workspace = true
reth-network-peers.workspace = true
reth-network-peers = { workspace = true, features = ["secp256k1"] }

# ethereum
alloy-rlp.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/net/dns/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ workspace = true
# reth
reth-primitives.workspace = true
reth-net-common.workspace = true
reth-network-peers.workspace = true
reth-network-peers = { workspace = true, features = ["secp256k1"] }

# ethereum
secp256k1 = { workspace = true, features = ["global-context", "rand-std", "recovery", "serde"] }
Expand Down
2 changes: 1 addition & 1 deletion crates/net/ecies/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ workspace = true
[dependencies]
reth-primitives.workspace = true
reth-net-common.workspace = true
reth-network-peers.workspace = true
reth-network-peers = { workspace = true, features = ["secp256k1"] }

alloy-rlp = { workspace = true, features = ["derive"] }
futures.workspace = true
Expand Down
6 changes: 5 additions & 1 deletion crates/net/peers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ alloy-rlp = { workspace = true, features = ["derive"] }
enr.workspace = true

# crypto
secp256k1.workspace = true

secp256k1 = { workspace = true, optional = true }
# misc
serde_with.workspace = true
thiserror.workspace = true
Expand All @@ -32,3 +32,7 @@ alloy-primitives = { workspace = true, features = ["rand"] }
rand.workspace = true
secp256k1 = { workspace = true, features = ["rand"] }
serde_json.workspace = true

[features]
default = []
secp256k1 = ["dep:secp256k1"]
17 changes: 16 additions & 1 deletion crates/net/peers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

use alloy_primitives::B512;
use std::{net::IpAddr, str::FromStr};
use std::str::FromStr;

#[cfg(feature = "secp256k1")]
use std::net::IpAddr;

// Re-export PeerId for ease of use.
pub use enr::Enr;
Expand All @@ -69,17 +72,20 @@ pub use trusted_peer::TrustedPeer;
/// `SECP256K1_TAG_PUBKEY_UNCOMPRESSED` = `0x04`
///
/// See: <https://github.com/bitcoin-core/secp256k1/blob/master/include/secp256k1.h#L211>
#[cfg(feature = "secp256k1")]
const SECP256K1_TAG_PUBKEY_UNCOMPRESSED: u8 = 4;

/// Converts a [`secp256k1::PublicKey`] to a [`PeerId`] by stripping the
/// `SECP256K1_TAG_PUBKEY_UNCOMPRESSED` tag and storing the rest of the slice in the [`PeerId`].
#[cfg(feature = "secp256k1")]
#[inline]
pub fn pk2id(pk: &secp256k1::PublicKey) -> PeerId {
PeerId::from_slice(&pk.serialize_uncompressed()[1..])
}

/// Converts a [`PeerId`] to a [`secp256k1::PublicKey`] by prepending the [`PeerId`] bytes with the
/// `SECP256K1_TAG_PUBKEY_UNCOMPRESSED` tag.
#[cfg(feature = "secp256k1")]
#[inline]
pub fn id2pk(id: PeerId) -> Result<secp256k1::PublicKey, secp256k1::Error> {
// NOTE: B512 is used as a PeerId because 512 bits is enough to represent an uncompressed
Expand All @@ -97,6 +103,7 @@ pub fn id2pk(id: PeerId) -> Result<secp256k1::PublicKey, secp256k1::Error> {
pub enum AnyNode {
/// An "enode:" peer with full ip
NodeRecord(NodeRecord),
#[cfg(feature = "secp256k1")]
/// An "enr:"
Enr(Enr<secp256k1::SecretKey>),
/// An incomplete "enode" with only a peer id
Expand All @@ -108,6 +115,7 @@ impl AnyNode {
pub fn peer_id(&self) -> PeerId {
match self {
Self::NodeRecord(record) => record.id,
#[cfg(feature = "secp256k1")]
Self::Enr(enr) => pk2id(&enr.public_key()),
Self::PeerId(peer_id) => *peer_id,
}
Expand All @@ -117,6 +125,7 @@ impl AnyNode {
pub fn node_record(&self) -> Option<NodeRecord> {
match self {
Self::NodeRecord(record) => Some(*record),
#[cfg(feature = "secp256k1")]
Self::Enr(enr) => {
let node_record = NodeRecord {
address: enr.ip4().map(IpAddr::from).or_else(|| enr.ip6().map(IpAddr::from))?,
Expand All @@ -138,6 +147,7 @@ impl From<NodeRecord> for AnyNode {
}
}

#[cfg(feature = "secp256k1")]
impl From<Enr<secp256k1::SecretKey>> for AnyNode {
fn from(value: Enr<secp256k1::SecretKey>) -> Self {
Self::Enr(value)
Expand All @@ -158,6 +168,7 @@ impl FromStr for AnyNode {
}
return Err(format!("invalid public key: {rem}"))
}
#[cfg(feature = "secp256k1")]
if s.starts_with("enr:") {
return Enr::from_str(s).map(AnyNode::Enr)
}
Expand All @@ -169,6 +180,7 @@ impl std::fmt::Display for AnyNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NodeRecord(record) => write!(f, "{record}"),
#[cfg(feature = "secp256k1")]
Self::Enr(enr) => write!(f, "{enr}"),
Self::PeerId(peer_id) => {
write!(f, "enode://{}", alloy_primitives::hex::encode(peer_id.as_slice()))
Expand Down Expand Up @@ -235,6 +247,7 @@ impl<T> WithPeerId<Option<T>> {
mod tests {
use super::*;

#[cfg(feature = "secp256k1")]
#[test]
fn test_node_record_parse() {
let url = "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@10.3.58.6:30303?discport=30301";
Expand All @@ -261,6 +274,7 @@ mod tests {
}

// <https://eips.ethereum.org/EIPS/eip-778>
#[cfg(feature = "secp256k1")]
#[test]
fn test_enr_parse() {
let url = "enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8";
Expand All @@ -275,6 +289,7 @@ mod tests {
}

#[test]
#[cfg(feature = "secp256k1")]
fn pk2id2pk() {
let prikey = secp256k1::SecretKey::new(&mut rand::thread_rng());
let pubkey = secp256k1::PublicKey::from_secret_key(secp256k1::SECP256K1, &prikey);
Expand Down
10 changes: 8 additions & 2 deletions crates/net/peers/src/node_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ use std::{
str::FromStr,
};

use crate::{pk2id, PeerId};
use crate::PeerId;
use alloy_rlp::{RlpDecodable, RlpEncodable};
use enr::Enr;
use serde_with::{DeserializeFromStr, SerializeDisplay};

#[cfg(feature = "secp256k1")]
use crate::pk2id;
#[cfg(feature = "secp256k1")]
use enr::Enr;

/// Represents a ENR in discovery.
///
/// Note: this is only an excerpt of the [`NodeRecord`] data structure.
Expand Down Expand Up @@ -40,6 +44,7 @@ pub struct NodeRecord {
}

impl NodeRecord {
#[cfg(feature = "secp256k1")]
/// Derive the [`NodeRecord`] from the secret key and addr
pub fn from_secret_key(addr: SocketAddr, sk: &secp256k1::SecretKey) -> Self {
let pk = secp256k1::PublicKey::from_secret_key(secp256k1::SECP256K1, sk);
Expand Down Expand Up @@ -169,6 +174,7 @@ impl FromStr for NodeRecord {
}
}

#[cfg(feature = "secp256k1")]
impl TryFrom<&Enr<secp256k1::SecretKey>> for NodeRecord {
type Error = NodeRecordParseError;

Expand Down
1 change: 1 addition & 0 deletions crates/net/peers/src/trusted_peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct TrustedPeer {
}

impl TrustedPeer {
#[cfg(feature = "secp256k1")]
/// Derive the [`NodeRecord`] from the secret key and addr
pub fn from_secret_key(host: Host, port: u16, sk: &secp256k1::SecretKey) -> Self {
let pk = secp256k1::PublicKey::from_secret_key(secp256k1::SECP256K1, sk);
Expand Down
Loading