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