1#![allow(clippy::wrong_self_convention)]
23
24use crate::crypto::PublicKey;
25
26use multiaddr::{Multiaddr, Protocol};
27use multihash_codetable::{Code, MultihashDigest};
28use rand::Rng;
29use serde::{Deserialize, Serialize};
30use thiserror::Error;
31
32use std::{convert::TryFrom, fmt, str::FromStr};
33
34const MAX_INLINE_KEY_LENGTH: usize = 42;
37pub(crate) const MULTIHASH_IDENTITY_CODE: u64 = 0x00;
38type Multihash = multihash::Multihash<64>;
39
40#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
45pub struct PeerId {
46 multihash: Multihash,
47}
48
49impl fmt::Debug for PeerId {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 f.debug_tuple("PeerId").field(&self.to_base58()).finish()
52 }
53}
54
55impl fmt::Display for PeerId {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 self.to_base58().fmt(f)
58 }
59}
60
61impl PeerId {
62 pub fn from_public_key(key: &PublicKey) -> PeerId {
64 Self::from_public_key_protobuf(&key.to_protobuf_encoding())
65 }
66
67 pub fn from_public_key_protobuf(key_enc: &[u8]) -> PeerId {
69 let multihash = if key_enc.len() <= MAX_INLINE_KEY_LENGTH {
70 Multihash::wrap(MULTIHASH_IDENTITY_CODE, key_enc)
71 .expect("key_enc.len() <= MAX_INLINE_KEY_LENGTH which fits in Multihash<64>")
72 } else {
73 Code::Sha2_256.digest(key_enc)
74 };
75
76 PeerId { multihash }
77 }
78
79 pub fn from_bytes(data: &[u8]) -> Result<PeerId, ParseError> {
81 let multihash = Multihash::from_bytes(data).map_err(|error| {
82 tracing::debug!(?error, "failed to decode peer ID bytes as multihash",);
83 ParseError::MultiHash
84 })?;
85
86 PeerId::from_multihash(multihash).map_err(|multihash| {
87 tracing::debug!(
88 code = multihash.code(),
89 digest_len = multihash.digest().len(),
90 "decoded multihash is not a valid peer ID",
91 );
92 ParseError::MultiHash
93 })
94 }
95
96 pub fn from_multihash(multihash: impl Into<Multihash>) -> Result<PeerId, Multihash> {
105 let multihash = multihash.into();
106
107 match multihash.code() {
108 code if code == u64::from(Code::Sha2_256) => Ok(PeerId { multihash }),
109 MULTIHASH_IDENTITY_CODE if multihash.digest().len() <= MAX_INLINE_KEY_LENGTH =>
110 Ok(PeerId { multihash }),
111 _ => Err(multihash),
112 }
113 }
114
115 pub fn try_from_multiaddr(address: &Multiaddr) -> Option<PeerId> {
120 address.iter().last().and_then(|p| match p {
121 Protocol::P2p(peer_id) => PeerId::from_multihash(peer_id).ok(),
122 _ => None,
123 })
124 }
125
126 pub fn random() -> PeerId {
130 let peer_id = rand::thread_rng().gen::<[u8; 32]>();
131 PeerId {
132 multihash: Multihash::wrap(MULTIHASH_IDENTITY_CODE, &peer_id)
133 .expect("The digest size is never too large"),
134 }
135 }
136
137 pub fn to_bytes(&self) -> Vec<u8> {
139 self.multihash.to_bytes()
140 }
141
142 pub fn to_base58(&self) -> String {
144 bs58::encode(self.to_bytes()).into_string()
145 }
146
147 pub fn is_public_key(&self, public_key: &PublicKey) -> Option<bool> {
152 let enc = public_key.to_protobuf_encoding();
153
154 let expected = match self.multihash.code() {
155 code if code == u64::from(Code::Sha2_256) => Code::Sha2_256.digest(&enc),
156 MULTIHASH_IDENTITY_CODE => Multihash::wrap(MULTIHASH_IDENTITY_CODE, &enc).expect(
157 "identity key enc fits in Multihash<64> since it passed from_public_key_protobuf",
158 ),
159 _ => return None,
160 };
161
162 Some(expected == self.multihash)
163 }
164
165 pub fn to_multiaddr_peer_id(&self) -> Result<multiaddr::PeerId, Multihash> {
171 multiaddr::PeerId::try_from(*self.as_ref())
172 }
173}
174
175impl From<PublicKey> for PeerId {
176 fn from(key: PublicKey) -> PeerId {
177 PeerId::from_public_key(&key)
178 }
179}
180
181impl From<&PublicKey> for PeerId {
182 fn from(key: &PublicKey) -> PeerId {
183 PeerId::from_public_key(key)
184 }
185}
186
187impl TryFrom<Vec<u8>> for PeerId {
188 type Error = Vec<u8>;
189
190 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
191 PeerId::from_bytes(&value).map_err(|_| value)
192 }
193}
194
195impl TryFrom<Multihash> for PeerId {
196 type Error = Multihash;
197
198 fn try_from(value: Multihash) -> Result<Self, Self::Error> {
199 PeerId::from_multihash(value)
200 }
201}
202
203impl AsRef<Multihash> for PeerId {
204 fn as_ref(&self) -> &Multihash {
205 &self.multihash
206 }
207}
208
209impl From<PeerId> for Multihash {
210 fn from(peer_id: PeerId) -> Self {
211 peer_id.multihash
212 }
213}
214
215impl From<PeerId> for Vec<u8> {
216 fn from(peer_id: PeerId) -> Self {
217 peer_id.to_bytes()
218 }
219}
220
221impl From<PeerId> for multiaddr::PeerId {
222 fn from(peer_id: PeerId) -> Self {
230 peer_id
231 .to_multiaddr_peer_id()
232 .expect("litep2p PeerId is always a valid multiaddr PeerId")
233 }
234}
235
236impl Serialize for PeerId {
237 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
238 where
239 S: serde::Serializer,
240 {
241 if serializer.is_human_readable() {
242 serializer.serialize_str(&self.to_base58())
243 } else {
244 serializer.serialize_bytes(&self.to_bytes()[..])
245 }
246 }
247}
248
249impl<'de> Deserialize<'de> for PeerId {
250 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
251 where
252 D: serde::Deserializer<'de>,
253 {
254 use serde::de::*;
255
256 struct PeerIdVisitor;
257
258 impl Visitor<'_> for PeerIdVisitor {
259 type Value = PeerId;
260
261 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
262 write!(f, "valid peer id")
263 }
264
265 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
266 where
267 E: Error,
268 {
269 PeerId::from_bytes(v).map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self))
270 }
271
272 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
273 where
274 E: Error,
275 {
276 PeerId::from_str(v).map_err(|_| Error::invalid_value(Unexpected::Str(v), &self))
277 }
278 }
279
280 if deserializer.is_human_readable() {
281 deserializer.deserialize_str(PeerIdVisitor)
282 } else {
283 deserializer.deserialize_bytes(PeerIdVisitor)
284 }
285 }
286}
287
288#[derive(Debug, Error)]
289pub enum ParseError {
290 #[error("base-58 decode error: {0}")]
291 B58(#[from] bs58::decode::Error),
292 #[error("decoding multihash failed")]
293 MultiHash,
294}
295
296impl FromStr for PeerId {
297 type Err = ParseError;
298
299 #[inline]
300 fn from_str(s: &str) -> Result<Self, Self::Err> {
301 let bytes = bs58::decode(s).into_vec()?;
302 PeerId::from_bytes(&bytes)
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use super::{ParseError, MAX_INLINE_KEY_LENGTH, MULTIHASH_IDENTITY_CODE};
309 use crate::{crypto::ed25519::Keypair, PeerId};
310 use multiaddr::{Multiaddr, Protocol};
311 use multihash::Multihash;
312 use multihash_codetable::Code;
313
314 #[test]
315 fn peer_id_is_public_key() {
316 let key = Keypair::generate().public();
317 let peer_id = key.to_peer_id();
318 assert_eq!(peer_id.is_public_key(&key.into()), Some(true));
319 }
320
321 #[test]
322 fn peer_id_into_bytes_then_from_bytes() {
323 let peer_id = Keypair::generate().public().to_peer_id();
324 let second = PeerId::from_bytes(&peer_id.to_bytes()).unwrap();
325 assert_eq!(peer_id, second);
326 }
327
328 #[test]
329 fn peer_id_to_base58_then_back() {
330 let peer_id = Keypair::generate().public().to_peer_id();
331 let second: PeerId = peer_id.to_base58().parse().unwrap();
332 assert_eq!(peer_id, second);
333 }
334
335 #[test]
336 fn random_peer_id_is_valid() {
337 for _ in 0..5000 {
338 let peer_id = PeerId::random();
339 assert_eq!(peer_id, PeerId::from_bytes(&peer_id.to_bytes()).unwrap());
340 }
341 }
342
343 #[test]
344 fn peer_id_from_multiaddr() {
345 let address = "[::1]:1337".parse::<std::net::SocketAddr>().unwrap();
346 let peer = PeerId::random();
347 let address = Multiaddr::empty()
348 .with(Protocol::from(address.ip()))
349 .with(Protocol::Tcp(address.port()))
350 .with(Protocol::P2p(peer.into()));
351
352 assert_eq!(peer, PeerId::try_from_multiaddr(&address).unwrap());
353 }
354
355 #[test]
356 fn peer_id_from_multiaddr_no_peer_id() {
357 let address = "[::1]:1337".parse::<std::net::SocketAddr>().unwrap();
358 let address = Multiaddr::empty()
359 .with(Protocol::from(address.ip()))
360 .with(Protocol::Tcp(address.port()));
361
362 assert!(PeerId::try_from_multiaddr(&address).is_none());
363 }
364
365 #[test]
366 fn peer_id_from_bytes() {
367 let peer = PeerId::random();
368 let bytes = peer.to_bytes();
369
370 assert_eq!(PeerId::try_from(bytes).unwrap(), peer);
371 }
372
373 #[test]
374 fn peer_id_as_multihash() {
375 let peer = PeerId::random();
376 let multihash = Multihash::from(peer);
377
378 assert_eq!(&multihash, peer.as_ref());
379 assert_eq!(PeerId::try_from(multihash).unwrap(), peer);
380 }
381
382 #[test]
383 fn serialize_deserialize() {
384 let peer = PeerId::random();
385 let serialized = serde_json::to_string(&peer).unwrap();
386 let deserialized = serde_json::from_str(&serialized).unwrap();
387
388 assert_eq!(peer, deserialized);
389 }
390
391 #[test]
392 fn invalid_multihash() {
393 fn test() -> crate::Result<PeerId> {
394 let bytes = [
395 0x16, 0x20, 0x64, 0x4b, 0xcc, 0x7e, 0x56, 0x43, 0x73, 0x04, 0x09, 0x99, 0xaa, 0xc8,
396 0x9e, 0x76, 0x22, 0xf3, 0xca, 0x71, 0xfb, 0xa1, 0xd9, 0x72, 0xfd, 0x94, 0xa3, 0x1c,
397 0x3b, 0xfb, 0xf2, 0x4e, 0x39, 0x38,
398 ];
399
400 PeerId::from_multihash(Multihash::from_bytes(&bytes).unwrap()).map_err(From::from)
401 }
402 let _error = test().unwrap_err();
403 }
404
405 #[test]
408 fn from_public_key_protobuf_small_key_uses_identity_hash() {
409 let key = Keypair::generate();
410 let enc = crate::crypto::PublicKey::from(key.public()).to_protobuf_encoding();
411 assert!(
412 enc.len() <= MAX_INLINE_KEY_LENGTH,
413 "ed25519 protobuf key must fit inline"
414 );
415
416 let peer_id = PeerId::from_public_key_protobuf(&enc);
417 assert_eq!(peer_id.as_ref().code(), MULTIHASH_IDENTITY_CODE);
418 }
419
420 #[test]
421 fn from_public_key_protobuf_identity_hash_stores_raw_bytes_not_rehash() {
422 let key = Keypair::generate();
424 let enc = crate::crypto::PublicKey::from(key.public()).to_protobuf_encoding();
425
426 let peer_id = PeerId::from_public_key_protobuf(&enc);
427 assert_eq!(peer_id.as_ref().digest(), enc.as_slice());
428 }
429
430 #[test]
431 fn from_public_key_protobuf_large_key_uses_sha256() {
432 let enc = vec![0u8; MAX_INLINE_KEY_LENGTH + 1];
434 let peer_id = PeerId::from_public_key_protobuf(&enc);
435 assert_eq!(peer_id.as_ref().code(), u64::from(Code::Sha2_256));
436 }
437
438 #[test]
439 fn from_public_key_protobuf_sha256_digest_is_hash_of_key_not_key_itself() {
440 let enc = vec![0u8; MAX_INLINE_KEY_LENGTH + 1];
442 let peer_id = PeerId::from_public_key_protobuf(&enc);
443 assert_eq!(peer_id.as_ref().digest().len(), 32);
445 assert_ne!(peer_id.as_ref().digest(), enc.as_slice());
446 }
447
448 #[test]
451 fn is_public_key_returns_false_for_different_key() {
452 let key1 = Keypair::generate().public();
453 let key2 = Keypair::generate().public();
454 let peer_id = key1.to_peer_id();
455 assert_eq!(peer_id.is_public_key(&key2.into()), Some(false));
456 }
457
458 #[test]
461 fn from_multihash_rejects_unsupported_code() {
462 let bytes = [
464 0x16, 0x20, 0x64, 0x4b, 0xcc, 0x7e, 0x56, 0x43, 0x73, 0x04, 0x09, 0x99, 0xaa, 0xc8,
465 0x9e, 0x76, 0x22, 0xf3, 0xca, 0x71, 0xfb, 0xa1, 0xd9, 0x72, 0xfd, 0x94, 0xa3, 0x1c,
466 0x3b, 0xfb, 0xf2, 0x4e, 0x39, 0x38,
467 ];
468 let mh = Multihash::from_bytes(&bytes).unwrap();
469 assert!(PeerId::from_multihash(mh).is_err());
470 }
471
472 #[test]
475 fn from_bytes_rejects_invalid_peer_id_multihash() {
476 let bytes = [
477 0x16, 0x20, 0x64, 0x4b, 0xcc, 0x7e, 0x56, 0x43, 0x73, 0x04, 0x09, 0x99, 0xaa, 0xc8,
478 0x9e, 0x76, 0x22, 0xf3, 0xca, 0x71, 0xfb, 0xa1, 0xd9, 0x72, 0xfd, 0x94, 0xa3, 0x1c,
479 0x3b, 0xfb, 0xf2, 0x4e, 0x39, 0x38,
480 ];
481 assert!(matches!(
482 PeerId::from_bytes(&bytes),
483 Err(ParseError::MultiHash)
484 ));
485 }
486
487 #[test]
488 fn from_bytes_rejects_invalid_multihash_bytes() {
489 assert!(matches!(
490 PeerId::from_bytes(&[0xff]),
491 Err(ParseError::MultiHash)
492 ));
493 }
494
495 #[test]
496 fn from_str_rejects_invalid_base58() {
497 assert!(matches!(
498 "not base58: 0".parse::<PeerId>(),
499 Err(ParseError::B58(_))
500 ));
501 }
502
503 #[test]
506 fn identity_peer_id_roundtrip_through_multiaddr() {
507 let peer = PeerId::random();
509 assert_eq!(peer.as_ref().code(), MULTIHASH_IDENTITY_CODE);
510
511 let addr = Multiaddr::empty()
512 .with(Protocol::Ip4("127.0.0.1".parse().unwrap()))
513 .with(Protocol::Tcp(1234))
514 .with(Protocol::P2p(peer.into()));
515
516 assert_eq!(peer, PeerId::try_from_multiaddr(&addr).unwrap());
517 }
518
519 #[test]
520 fn sha256_peer_id_roundtrip_through_multiaddr() {
521 let enc = vec![42u8; MAX_INLINE_KEY_LENGTH + 1];
523 let peer = PeerId::from_public_key_protobuf(&enc);
524 assert_eq!(peer.as_ref().code(), u64::from(Code::Sha2_256));
525
526 let addr = Multiaddr::empty()
527 .with(Protocol::Ip4("127.0.0.1".parse().unwrap()))
528 .with(Protocol::Tcp(1234))
529 .with(Protocol::P2p(peer.into()));
530
531 assert_eq!(peer, PeerId::try_from_multiaddr(&addr).unwrap());
532 }
533}