tentacle_secio/
peer_id.rs1use std::fmt;
3
4use rand::{Rng, thread_rng};
5use unsigned_varint::{decode, encode};
6
7use crate::handshake::handshake_struct::PublicKey;
8
9const SHA256_CODE: u64 = 0x12;
10const SHA256_SIZE: u8 = 32;
11
12#[derive(Clone, PartialOrd, PartialEq, Eq, Hash)]
16pub struct PeerId {
17 inner: Vec<u8>,
18}
19
20impl PeerId {
21 #[inline]
23 pub fn from_public_key(public_key: &PublicKey) -> Self {
24 let key_inner = public_key.inner_ref();
25 Self::from_seed(key_inner)
26 }
27
28 pub fn from_bytes(data: Vec<u8>) -> Result<Self, Error> {
30 if data.is_empty() {
31 return Err(Error::Empty);
32 }
33
34 let (code, bytes) = decode::u64(&data).map_err(|_| Error::InvalidData)?;
35
36 if code != SHA256_CODE {
37 return Err(Error::NotSupportHashCode);
38 }
39
40 if bytes.len() != SHA256_SIZE as usize + 1 {
41 return Err(Error::WrongLength);
42 }
43
44 if bytes[0] != SHA256_SIZE {
45 return Err(Error::InvalidData);
46 }
47
48 Ok(PeerId { inner: data })
49 }
50
51 pub fn random() -> Self {
53 let mut seed = [0u8; 20];
54 thread_rng().fill(&mut seed[..]);
55 Self::from_seed(&seed)
56 }
57
58 fn from_seed(seed: &[u8]) -> Self {
60 let mut buf = encode::u64_buffer();
61 let code = encode::u64(SHA256_CODE, &mut buf);
62
63 let header_len = code.len() + 1;
64
65 let mut inner = vec![0; header_len + SHA256_SIZE as usize];
66 inner[..code.len()].copy_from_slice(code);
67 inner[code.len()] = SHA256_SIZE;
68
69 let mut ctx = crate::sha256_compat::Context::new();
70 ctx.update(seed);
71 inner[header_len..].copy_from_slice(ctx.finish().as_ref());
72 PeerId { inner }
73 }
74
75 #[inline]
77 pub fn as_bytes(&self) -> &[u8] {
78 &self.inner
79 }
80
81 #[inline]
83 pub fn into_bytes(self) -> Vec<u8> {
84 self.inner
85 }
86
87 #[inline]
89 pub fn to_base58(&self) -> String {
90 bs58::encode(self.inner.clone()).into_string()
91 }
92
93 #[inline]
95 pub fn digest(&self) -> &[u8] {
96 let (_, bytes) = decode::u16(&self.inner).expect("a invalid digest");
97 &bytes[1..]
98 }
99
100 pub fn is_public_key(&self, public_key: &PublicKey) -> bool {
102 let peer_id = Self::from_public_key(public_key);
103 &peer_id == self
104 }
105}
106
107impl fmt::Debug for PeerId {
108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109 write!(f, "PeerId({})", self.to_base58())
110 }
111}
112
113impl fmt::Display for PeerId {
114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115 write!(f, "{}", self.to_base58())
116 }
117}
118
119impl From<PublicKey> for PeerId {
120 #[inline]
121 fn from(key: PublicKey) -> PeerId {
122 PeerId::from_public_key(&key)
123 }
124}
125
126impl ::std::str::FromStr for PeerId {
127 type Err = Error;
128
129 #[inline]
130 fn from_str(s: &str) -> Result<Self, Self::Err> {
131 let bytes = bs58::decode(s).into_vec().map_err(|_| Error::InvalidData)?;
132 PeerId::from_bytes(bytes)
133 }
134}
135
136#[derive(Debug)]
138pub enum Error {
139 InvalidData,
141 WrongLength,
143 NotSupportHashCode,
145 Empty,
147}
148
149impl fmt::Display for Error {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 match self {
152 Error::Empty => write!(f, "data is empty"),
153 Error::InvalidData => write!(f, "invalid data"),
154 Error::WrongLength => write!(f, "wrong length"),
155 Error::NotSupportHashCode => write!(f, "not support hash code"),
156 }
157 }
158}
159
160impl ::std::error::Error for Error {}
161
162#[cfg(test)]
163mod tests {
164 use crate::{SecioKeyPair, peer_id::PeerId};
165
166 #[test]
167 fn peer_id_is_public_key() {
168 let pub_key = SecioKeyPair::secp256k1_generated().public_key();
169 let peer_id = PeerId::from_public_key(&pub_key);
170 assert!(peer_id.is_public_key(&pub_key));
171 }
172
173 #[test]
174 fn peer_id_into_bytes_then_from_bytes() {
175 let peer_id = SecioKeyPair::secp256k1_generated().peer_id();
176 let second = PeerId::from_bytes(peer_id.as_bytes().to_vec()).unwrap();
177 assert_eq!(peer_id, second);
178 }
179
180 #[test]
181 fn peer_id_to_base58_then_back() {
182 let peer_id = SecioKeyPair::secp256k1_generated().peer_id();
183 let second: PeerId = peer_id.to_base58().parse().unwrap();
184 assert_eq!(peer_id, second);
185 }
186
187 #[test]
188 fn peer_id_randomness() {
189 let peer_id = PeerId::random();
190 let second: PeerId = PeerId::random();
191 assert_ne!(peer_id, second);
192 }
193}