use enr::{CombinedKey, CombinedPublicKey};
use libp2p_core::{multiaddr::Protocol, Multiaddr};
use libp2p_identity::{ed25519, secp256k1, KeyType, Keypair, PeerId, PublicKey};
use std::convert::TryInto;
use std::net::IpAddr;
pub type Enr = enr::Enr<CombinedKey>;
pub const QUIC_ENR_KEY: &str = "quic";
pub const QUIC6_ENR_KEY: &str = "quic6";
#[allow(dead_code)]
pub trait EnrExt {
fn peer_id(&self) -> PeerId;
fn multiaddr(&self) -> Vec<Multiaddr>;
fn multiaddr_p2p(&self) -> Vec<Multiaddr>;
fn multiaddr_p2p_tcp(&self) -> Vec<Multiaddr>;
fn multiaddr_p2p_udp(&self) -> Vec<Multiaddr>;
fn multiaddr_tcp(&self) -> Vec<Multiaddr>;
fn multiaddr_quic(&self) -> Vec<Multiaddr>;
fn quic4(&self) -> Option<u16>;
fn quic6(&self) -> Option<u16>;
fn enode_id(&self) -> String;
}
pub trait CombinedKeyPublicExt {
fn as_peer_id(&self) -> PeerId;
}
#[allow(dead_code)]
pub trait CombinedKeyExt {
fn from_libp2p(key: Keypair) -> Result<CombinedKey, &'static str>;
fn from_secp256k1(key: &secp256k1::Keypair) -> CombinedKey;
}
impl EnrExt for Enr {
fn peer_id(&self) -> PeerId {
self.public_key().as_peer_id()
}
fn quic4(&self) -> Option<u16> {
self.get_decodable(QUIC_ENR_KEY).and_then(Result::ok)
}
fn quic6(&self) -> Option<u16> {
self.get_decodable(QUIC6_ENR_KEY).and_then(Result::ok)
}
fn multiaddr(&self) -> Vec<Multiaddr> {
let mut multiaddrs: Vec<Multiaddr> = Vec::new();
if let Some(ip) = self.ip4() {
if let Some(udp) = self.udp4() {
let mut multiaddr: Multiaddr = ip.into();
multiaddr.push(Protocol::Udp(udp));
multiaddrs.push(multiaddr);
}
if let Some(quic) = self.quic4() {
let mut multiaddr: Multiaddr = ip.into();
multiaddr.push(Protocol::Udp(quic));
multiaddr.push(Protocol::QuicV1);
multiaddrs.push(multiaddr);
}
if let Some(tcp) = self.tcp4() {
let mut multiaddr: Multiaddr = ip.into();
multiaddr.push(Protocol::Tcp(tcp));
multiaddrs.push(multiaddr);
}
}
if let Some(ip6) = self.ip6() {
if let Some(udp6) = self.udp6() {
let mut multiaddr: Multiaddr = ip6.into();
multiaddr.push(Protocol::Udp(udp6));
multiaddrs.push(multiaddr);
}
if let Some(quic6) = self.quic6() {
let mut multiaddr: Multiaddr = ip6.into();
multiaddr.push(Protocol::Udp(quic6));
multiaddr.push(Protocol::QuicV1);
multiaddrs.push(multiaddr);
}
if let Some(tcp6) = self.tcp6() {
let mut multiaddr: Multiaddr = ip6.into();
multiaddr.push(Protocol::Tcp(tcp6));
multiaddrs.push(multiaddr);
}
}
multiaddrs
}
fn multiaddr_p2p(&self) -> Vec<Multiaddr> {
let peer_id = self.peer_id();
let mut multiaddrs: Vec<Multiaddr> = Vec::new();
if let Some(ip) = self.ip4() {
if let Some(udp) = self.udp4() {
let mut multiaddr: Multiaddr = ip.into();
multiaddr.push(Protocol::Udp(udp));
multiaddr.push(Protocol::P2p(peer_id));
multiaddrs.push(multiaddr);
}
if let Some(tcp) = self.tcp4() {
let mut multiaddr: Multiaddr = ip.into();
multiaddr.push(Protocol::Tcp(tcp));
multiaddr.push(Protocol::P2p(peer_id));
multiaddrs.push(multiaddr);
}
}
if let Some(ip6) = self.ip6() {
if let Some(udp6) = self.udp6() {
let mut multiaddr: Multiaddr = ip6.into();
multiaddr.push(Protocol::Udp(udp6));
multiaddr.push(Protocol::P2p(peer_id));
multiaddrs.push(multiaddr);
}
if let Some(tcp6) = self.tcp6() {
let mut multiaddr: Multiaddr = ip6.into();
multiaddr.push(Protocol::Tcp(tcp6));
multiaddr.push(Protocol::P2p(peer_id));
multiaddrs.push(multiaddr);
}
}
multiaddrs
}
fn multiaddr_p2p_tcp(&self) -> Vec<Multiaddr> {
let peer_id = self.peer_id();
let mut multiaddrs: Vec<Multiaddr> = Vec::new();
if let Some(ip) = self.ip4() {
if let Some(tcp) = self.tcp4() {
let mut multiaddr: Multiaddr = ip.into();
multiaddr.push(Protocol::Tcp(tcp));
multiaddr.push(Protocol::P2p(peer_id));
multiaddrs.push(multiaddr);
}
}
if let Some(ip6) = self.ip6() {
if let Some(tcp6) = self.tcp6() {
let mut multiaddr: Multiaddr = ip6.into();
multiaddr.push(Protocol::Tcp(tcp6));
multiaddr.push(Protocol::P2p(peer_id));
multiaddrs.push(multiaddr);
}
}
multiaddrs
}
fn multiaddr_p2p_udp(&self) -> Vec<Multiaddr> {
let peer_id = self.peer_id();
let mut multiaddrs: Vec<Multiaddr> = Vec::new();
if let Some(ip) = self.ip4() {
if let Some(udp) = self.udp4() {
let mut multiaddr: Multiaddr = ip.into();
multiaddr.push(Protocol::Udp(udp));
multiaddr.push(Protocol::P2p(peer_id));
multiaddrs.push(multiaddr);
}
}
if let Some(ip6) = self.ip6() {
if let Some(udp6) = self.udp6() {
let mut multiaddr: Multiaddr = ip6.into();
multiaddr.push(Protocol::Udp(udp6));
multiaddr.push(Protocol::P2p(peer_id));
multiaddrs.push(multiaddr);
}
}
multiaddrs
}
fn multiaddr_quic(&self) -> Vec<Multiaddr> {
let mut multiaddrs: Vec<Multiaddr> = Vec::new();
if let Some(quic_port) = self.quic4() {
if let Some(ip) = self.ip4() {
let mut multiaddr: Multiaddr = ip.into();
multiaddr.push(Protocol::Udp(quic_port));
multiaddr.push(Protocol::QuicV1);
multiaddrs.push(multiaddr);
}
}
if let Some(quic6_port) = self.quic6() {
if let Some(ip6) = self.ip6() {
let mut multiaddr: Multiaddr = ip6.into();
multiaddr.push(Protocol::Udp(quic6_port));
multiaddr.push(Protocol::QuicV1);
multiaddrs.push(multiaddr);
}
}
multiaddrs
}
fn multiaddr_tcp(&self) -> Vec<Multiaddr> {
let mut multiaddrs: Vec<Multiaddr> = Vec::new();
if let Some(ip) = self.ip4() {
if let Some(tcp) = self.tcp4() {
let mut multiaddr: Multiaddr = ip.into();
multiaddr.push(Protocol::Tcp(tcp));
multiaddrs.push(multiaddr);
}
}
if let Some(ip6) = self.ip6() {
if let Some(tcp6) = self.tcp6() {
let mut multiaddr: Multiaddr = ip6.into();
multiaddr.push(Protocol::Tcp(tcp6));
multiaddrs.push(multiaddr);
}
}
multiaddrs
}
fn enode_id(&self) -> String {
let node_id = self.node_id();
let enode = format!("enode://{}", hex::encode(node_id.raw()));
if let Some((ip, tcp_port, udp_port)) = {
if let Some(ip) = self.ip4() {
let tcp_port = self.tcp4();
let udp_port = self.udp4();
Some((IpAddr::from(ip), tcp_port, udp_port))
} else if let Some(ip) = self.ip6() {
let tcp_port = self.tcp4();
let udp_port = self.udp4();
Some((IpAddr::from(ip), tcp_port, udp_port))
} else {
None
}
} {
match (tcp_port, udp_port) {
(Some(tcp_port), Some(udp_port)) => {
if tcp_port != udp_port {
format!("{}@{}:{}?discport={}", enode, ip, tcp_port, udp_port)
} else {
format!("{}@{}:{}", enode, ip, tcp_port)
}
}
(Some(tcp_port), None) => format!("{}@{}:{}", enode, ip, tcp_port),
(None, Some(udp_port)) => format!("{}@{}?discport={}", enode, ip, udp_port),
(None, None) => format!("{}@{}", enode, ip),
}
} else {
enode
}
}
}
impl CombinedKeyPublicExt for CombinedPublicKey {
fn as_peer_id(&self) -> PeerId {
match self {
Self::Secp256k1(pk) => {
let pk_bytes = pk.to_sec1_bytes();
let libp2p_pk: PublicKey = secp256k1::PublicKey::try_from_bytes(&pk_bytes)
.expect("valid public key")
.into();
PeerId::from_public_key(&libp2p_pk)
}
Self::Ed25519(pk) => {
let pk_bytes = pk.to_bytes();
let libp2p_pk: PublicKey = ed25519::PublicKey::try_from_bytes(&pk_bytes)
.expect("valid public key")
.into();
PeerId::from_public_key(&libp2p_pk)
}
}
}
}
impl CombinedKeyExt for CombinedKey {
fn from_libp2p(key: Keypair) -> Result<CombinedKey, &'static str> {
match key.key_type() {
KeyType::Secp256k1 => {
let key = key.try_into_secp256k1().expect("right key type");
let secret = enr::k256::ecdsa::SigningKey::from_slice(&key.secret().to_bytes())
.expect("libp2p key must be valid");
Ok(CombinedKey::Secp256k1(secret))
}
KeyType::Ed25519 => {
let key = key.try_into_ed25519().expect("right key type");
let ed_keypair = enr::ed25519_dalek::SigningKey::from_bytes(
&(key.to_bytes()[..32])
.try_into()
.expect("libp2p key must be valid"),
);
Ok(CombinedKey::from(ed_keypair))
}
_ => Err("Unsupported keypair kind"),
}
}
fn from_secp256k1(key: &secp256k1::Keypair) -> Self {
let secret = enr::k256::ecdsa::SigningKey::from_slice(&key.secret().to_bytes())
.expect("libp2p key must be valid");
CombinedKey::Secp256k1(secret)
}
}
#[cfg(test)]
pub fn peer_id_to_node_id(peer_id: &PeerId) -> Result<enr::NodeId, String> {
use tiny_keccak::{Hasher, Keccak};
let pk_bytes = &peer_id.to_bytes()[2..];
let public_key = PublicKey::try_decode_protobuf(pk_bytes).map_err(|e| {
format!(
" Cannot parse libp2p public key public key from peer id: {}",
e
)
})?;
match public_key.key_type() {
KeyType::Secp256k1 => {
let pk = public_key
.clone()
.try_into_secp256k1()
.expect("right key type");
let uncompressed_key_bytes = &pk.to_bytes_uncompressed()[1..];
let mut output = [0_u8; 32];
let mut hasher = Keccak::v256();
hasher.update(uncompressed_key_bytes);
hasher.finalize(&mut output);
Ok(enr::NodeId::parse(&output).expect("Must be correct length"))
}
KeyType::Ed25519 => {
let pk = public_key
.clone()
.try_into_ed25519()
.expect("right key type");
let uncompressed_key_bytes = pk.to_bytes();
let mut output = [0_u8; 32];
let mut hasher = Keccak::v256();
hasher.update(&uncompressed_key_bytes);
hasher.finalize(&mut output);
Ok(enr::NodeId::parse(&output).expect("Must be correct length"))
}
_ => Err(format!("Unsupported public key from peer {}", peer_id)),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_secp256k1_peer_id_conversion() {
let sk_hex = "df94a73d528434ce2309abb19c16aedb535322797dbd59c157b1e04095900f48";
let sk_bytes = hex::decode(sk_hex).unwrap();
let secret_key = enr::k256::ecdsa::SigningKey::from_slice(&sk_bytes).unwrap();
let libp2p_sk = secp256k1::SecretKey::try_from_bytes(sk_bytes).unwrap();
let secp256k1_kp: secp256k1::Keypair = libp2p_sk.into();
let libp2p_kp: Keypair = secp256k1_kp.into();
let peer_id = libp2p_kp.public().to_peer_id();
let enr = enr::Builder::default().build(&secret_key).unwrap();
let node_id = peer_id_to_node_id(&peer_id).unwrap();
assert_eq!(enr.node_id(), node_id);
}
#[test]
fn test_ed25519_peer_conversion() {
let sk_hex = "4dea8a5072119927e9d243a7d953f2f4bc95b70f110978e2f9bc7a9000e4b261";
let sk_bytes = hex::decode(sk_hex).unwrap();
let secret_key =
enr::ed25519_dalek::SigningKey::from_bytes(&sk_bytes.clone().try_into().unwrap());
let libp2p_sk = ed25519::SecretKey::try_from_bytes(sk_bytes).unwrap();
let secp256k1_kp: ed25519::Keypair = libp2p_sk.into();
let libp2p_kp: Keypair = secp256k1_kp.into();
let peer_id = libp2p_kp.public().to_peer_id();
let enr = enr::Builder::default().build(&secret_key).unwrap();
let node_id = peer_id_to_node_id(&peer_id).unwrap();
assert_eq!(enr.node_id(), node_id);
}
}