libp2p_identity/
peer_id.rs1#[cfg(feature = "rand")]
22use rand::Rng;
23use sha2::Digest as _;
24use std::{fmt, str::FromStr};
25use thiserror::Error;
26
27type Multihash = multihash::Multihash<64>;
33
34#[cfg(feature = "serde")]
35use serde::{Deserialize, Serialize};
36
37const MAX_INLINE_KEY_LENGTH: usize = 42;
40
41const MULTIHASH_IDENTITY_CODE: u64 = 0;
42const MULTIHASH_SHA256_CODE: u64 = 0x12;
43
44#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
49pub struct PeerId {
50 multihash: Multihash,
51}
52
53impl fmt::Debug for PeerId {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.debug_tuple("PeerId").field(&self.to_base58()).finish()
56 }
57}
58
59impl fmt::Display for PeerId {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 self.to_base58().fmt(f)
62 }
63}
64
65impl PeerId {
66 pub fn from_public_key(key: &crate::keypair::PublicKey) -> PeerId {
68 let key_enc = key.encode_protobuf();
69
70 let multihash = if key_enc.len() <= MAX_INLINE_KEY_LENGTH {
71 Multihash::wrap(MULTIHASH_IDENTITY_CODE, &key_enc)
72 .expect("64 byte multihash provides sufficient space")
73 } else {
74 Multihash::wrap(MULTIHASH_SHA256_CODE, &sha2::Sha256::digest(key_enc))
75 .expect("64 byte multihash provides sufficient space")
76 };
77
78 PeerId { multihash }
79 }
80
81 pub fn from_bytes(data: &[u8]) -> Result<PeerId, ParseError> {
83 PeerId::from_multihash(Multihash::from_bytes(data)?)
84 .map_err(|mh| ParseError::UnsupportedCode(mh.code()))
85 }
86
87 pub fn from_multihash(multihash: Multihash) -> Result<PeerId, Multihash> {
93 match multihash.code() {
94 MULTIHASH_SHA256_CODE => Ok(PeerId { multihash }),
95 MULTIHASH_IDENTITY_CODE if multihash.digest().len() <= MAX_INLINE_KEY_LENGTH => {
96 Ok(PeerId { multihash })
97 }
98 _ => Err(multihash),
99 }
100 }
101
102 #[cfg(feature = "rand")]
106 pub fn random() -> PeerId {
107 let peer_id = rand::thread_rng().gen::<[u8; 32]>();
108 PeerId {
109 multihash: Multihash::wrap(0x0, &peer_id).expect("The digest size is never too large"),
110 }
111 }
112
113 pub fn to_bytes(self) -> Vec<u8> {
115 self.multihash.to_bytes()
116 }
117
118 pub fn to_base58(self) -> String {
120 bs58::encode(self.to_bytes()).into_string()
121 }
122}
123
124impl From<crate::PublicKey> for PeerId {
125 fn from(key: crate::PublicKey) -> PeerId {
126 PeerId::from_public_key(&key)
127 }
128}
129
130impl From<&crate::PublicKey> for PeerId {
131 fn from(key: &crate::PublicKey) -> PeerId {
132 PeerId::from_public_key(key)
133 }
134}
135
136impl TryFrom<Vec<u8>> for PeerId {
137 type Error = Vec<u8>;
138
139 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
140 PeerId::from_bytes(&value).map_err(|_| value)
141 }
142}
143
144impl TryFrom<Multihash> for PeerId {
145 type Error = Multihash;
146
147 fn try_from(value: Multihash) -> Result<Self, Self::Error> {
148 PeerId::from_multihash(value)
149 }
150}
151
152impl AsRef<Multihash> for PeerId {
153 fn as_ref(&self) -> &Multihash {
154 &self.multihash
155 }
156}
157
158impl From<PeerId> for Multihash {
159 fn from(peer_id: PeerId) -> Self {
160 peer_id.multihash
161 }
162}
163
164impl From<PeerId> for Vec<u8> {
165 fn from(peer_id: PeerId) -> Self {
166 peer_id.to_bytes()
167 }
168}
169
170#[cfg(feature = "serde")]
171impl Serialize for PeerId {
172 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
173 where
174 S: serde::Serializer,
175 {
176 if serializer.is_human_readable() {
177 serializer.serialize_str(&self.to_base58())
178 } else {
179 serializer.serialize_bytes(&self.to_bytes()[..])
180 }
181 }
182}
183
184#[cfg(feature = "serde")]
185impl<'de> Deserialize<'de> for PeerId {
186 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
187 where
188 D: serde::Deserializer<'de>,
189 {
190 use serde::de::*;
191
192 struct PeerIdVisitor;
193
194 impl Visitor<'_> for PeerIdVisitor {
195 type Value = PeerId;
196
197 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
198 write!(f, "valid peer id")
199 }
200
201 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
202 where
203 E: Error,
204 {
205 PeerId::from_bytes(v).map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self))
206 }
207
208 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
209 where
210 E: Error,
211 {
212 PeerId::from_str(v).map_err(|_| Error::invalid_value(Unexpected::Str(v), &self))
213 }
214 }
215
216 if deserializer.is_human_readable() {
217 deserializer.deserialize_str(PeerIdVisitor)
218 } else {
219 deserializer.deserialize_bytes(PeerIdVisitor)
220 }
221 }
222}
223
224#[derive(Debug, Error)]
226pub enum ParseError {
227 #[error("base-58 decode error: {0}")]
228 B58(#[from] bs58::decode::Error),
229 #[error("unsupported multihash code '{0}'")]
230 UnsupportedCode(u64),
231 #[error("invalid multihash")]
232 InvalidMultihash(#[from] multihash::Error),
233}
234
235impl FromStr for PeerId {
236 type Err = ParseError;
237
238 #[inline]
239 fn from_str(s: &str) -> Result<Self, Self::Err> {
240 let bytes = bs58::decode(s).into_vec()?;
241 let peer_id = PeerId::from_bytes(&bytes)?;
242
243 Ok(peer_id)
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 #[cfg(all(feature = "ed25519", feature = "rand"))]
253 fn peer_id_into_bytes_then_from_bytes() {
254 let peer_id = crate::Keypair::generate_ed25519().public().to_peer_id();
255 let second = PeerId::from_bytes(&peer_id.to_bytes()).unwrap();
256 assert_eq!(peer_id, second);
257 }
258
259 #[test]
260 #[cfg(all(feature = "ed25519", feature = "rand"))]
261 fn peer_id_to_base58_then_back() {
262 let peer_id = crate::Keypair::generate_ed25519().public().to_peer_id();
263 let second: PeerId = peer_id.to_base58().parse().unwrap();
264 assert_eq!(peer_id, second);
265 }
266
267 #[test]
268 #[cfg(feature = "rand")]
269 fn random_peer_id_is_valid() {
270 for _ in 0..5000 {
271 let peer_id = PeerId::random();
272 assert_eq!(peer_id, PeerId::from_bytes(&peer_id.to_bytes()).unwrap());
273 }
274 }
275}