1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5use crate::error::Error;
6
7#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub struct Id20(pub [u8; 20]);
10
11#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
13pub struct Id32(pub [u8; 32]);
14
15impl Id20 {
18 pub const ZERO: Self = Self([0u8; 20]);
20
21 pub fn from_hex(s: &str) -> Result<Self, Error> {
27 let bytes = hex::decode(s).map_err(|e| Error::InvalidHex(e.to_string()))?;
28 Self::from_bytes(&bytes)
29 }
30
31 pub fn from_base32(s: &str) -> Result<Self, Error> {
37 let bytes = data_encoding::BASE32_NOPAD
38 .decode(s.as_bytes())
39 .map_err(|e| Error::InvalidHex(format!("base32: {e}")))?;
40 Self::from_bytes(&bytes)
41 }
42
43 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
49 let arr: [u8; 20] = bytes.try_into().map_err(|_| Error::InvalidHashLength {
50 expected: 20,
51 got: bytes.len(),
52 })?;
53 Ok(Self(arr))
54 }
55
56 #[must_use]
58 pub fn to_hex(&self) -> String {
59 hex::encode(self.0)
60 }
61
62 #[must_use]
64 pub fn to_base32(&self) -> String {
65 data_encoding::BASE32_NOPAD.encode(&self.0)
66 }
67
68 #[must_use]
70 pub fn xor_distance(&self, other: &Self) -> Self {
71 let mut result = [0u8; 20];
72 for (i, byte) in result.iter_mut().enumerate() {
73 *byte = self.0[i] ^ other.0[i];
74 }
75 Self(result)
76 }
77
78 #[must_use]
80 pub fn as_bytes(&self) -> &[u8; 20] {
81 &self.0
82 }
83}
84
85impl fmt::Debug for Id20 {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 write!(f, "Id20({})", self.to_hex())
88 }
89}
90
91impl fmt::Display for Id20 {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 write!(f, "{}", self.to_hex())
94 }
95}
96
97impl AsRef<[u8]> for Id20 {
98 fn as_ref(&self) -> &[u8] {
99 &self.0
100 }
101}
102
103impl From<[u8; 20]> for Id20 {
104 fn from(arr: [u8; 20]) -> Self {
105 Self(arr)
106 }
107}
108
109impl Serialize for Id20 {
110 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
111 serializer.serialize_bytes(&self.0)
112 }
113}
114
115impl<'de> Deserialize<'de> for Id20 {
116 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
117 let bytes: Vec<u8> = serde_bytes::deserialize(deserializer)?;
118 Self::from_bytes(&bytes).map_err(serde::de::Error::custom)
119 }
120}
121
122impl Id32 {
125 pub const ZERO: Self = Self([0u8; 32]);
127
128 const MULTIHASH_PREFIX: [u8; 2] = [0x12, 0x20];
130
131 pub fn from_hex(s: &str) -> Result<Self, Error> {
137 let bytes = hex::decode(s).map_err(|e| Error::InvalidHex(e.to_string()))?;
138 Self::from_bytes(&bytes)
139 }
140
141 pub fn from_base32(s: &str) -> Result<Self, Error> {
147 let bytes = data_encoding::BASE32_NOPAD
148 .decode(s.as_bytes())
149 .map_err(|e| Error::InvalidHex(format!("base32: {e}")))?;
150 Self::from_bytes(&bytes)
151 }
152
153 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
159 let arr: [u8; 32] = bytes.try_into().map_err(|_| Error::InvalidHashLength {
160 expected: 32,
161 got: bytes.len(),
162 })?;
163 Ok(Self(arr))
164 }
165
166 #[must_use]
168 pub fn to_hex(&self) -> String {
169 hex::encode(self.0)
170 }
171
172 #[must_use]
174 pub fn to_base32(&self) -> String {
175 data_encoding::BASE32_NOPAD.encode(&self.0)
176 }
177
178 #[must_use]
182 pub fn to_multihash_hex(&self) -> String {
183 let mut buf = Vec::with_capacity(34);
184 buf.extend_from_slice(&Self::MULTIHASH_PREFIX);
185 buf.extend_from_slice(&self.0);
186 hex::encode(buf)
187 }
188
189 pub fn from_multihash_hex(s: &str) -> Result<Self, Error> {
197 let bytes = hex::decode(s).map_err(|e| Error::InvalidHex(e.to_string()))?;
198 if bytes.len() != 34 {
199 return Err(Error::InvalidHashLength {
200 expected: 34,
201 got: bytes.len(),
202 });
203 }
204 if bytes[0] != Self::MULTIHASH_PREFIX[0] || bytes[1] != Self::MULTIHASH_PREFIX[1] {
205 return Err(Error::InvalidHex(format!(
206 "invalid multihash prefix: expected 1220, got {:02x}{:02x}",
207 bytes[0], bytes[1]
208 )));
209 }
210 Self::from_bytes(&bytes[2..])
211 }
212
213 #[must_use]
215 pub fn as_bytes(&self) -> &[u8; 32] {
216 &self.0
217 }
218}
219
220impl fmt::Debug for Id32 {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 write!(f, "Id32({})", self.to_hex())
223 }
224}
225
226impl fmt::Display for Id32 {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 write!(f, "{}", self.to_hex())
229 }
230}
231
232impl AsRef<[u8]> for Id32 {
233 fn as_ref(&self) -> &[u8] {
234 &self.0
235 }
236}
237
238impl From<[u8; 32]> for Id32 {
239 fn from(arr: [u8; 32]) -> Self {
240 Self(arr)
241 }
242}
243
244impl Serialize for Id32 {
245 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
246 serializer.serialize_bytes(&self.0)
247 }
248}
249
250impl<'de> Deserialize<'de> for Id32 {
251 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
252 let bytes: Vec<u8> = serde_bytes::deserialize(deserializer)?;
253 Self::from_bytes(&bytes).map_err(serde::de::Error::custom)
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260
261 #[test]
262 fn id20_hex_round_trip() {
263 let hex_str = "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d";
264 let id = Id20::from_hex(hex_str).unwrap();
265 assert_eq!(id.to_hex(), hex_str);
266 }
267
268 #[test]
269 fn id20_base32_round_trip() {
270 let id = Id20::from_hex("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d").unwrap();
271 let b32 = id.to_base32();
272 let id2 = Id20::from_base32(&b32).unwrap();
273 assert_eq!(id, id2);
274 }
275
276 #[test]
277 fn id20_xor_distance() {
278 let a = Id20::from_hex("0000000000000000000000000000000000000001").unwrap();
279 let b = Id20::from_hex("0000000000000000000000000000000000000003").unwrap();
280 let dist = a.xor_distance(&b);
281 assert_eq!(
282 dist,
283 Id20::from_hex("0000000000000000000000000000000000000002").unwrap()
284 );
285 }
286
287 #[test]
288 fn id20_xor_self_is_zero() {
289 let a = Id20::from_hex("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d").unwrap();
290 assert_eq!(a.xor_distance(&a), Id20::ZERO);
291 }
292
293 #[test]
294 fn id20_invalid_hex() {
295 assert!(Id20::from_hex("not_hex").is_err());
296 assert!(Id20::from_hex("aabbcc").is_err()); }
298
299 #[test]
300 fn id20_display() {
301 let id = Id20::from_hex("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d").unwrap();
302 assert_eq!(format!("{id}"), "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d");
303 }
304
305 #[test]
306 fn id32_hex_round_trip() {
307 let hex_str = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
308 let id = Id32::from_hex(hex_str).unwrap();
309 assert_eq!(id.to_hex(), hex_str);
310 }
311
312 #[test]
313 fn id32_base32_round_trip() {
314 let id = Id32::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
315 .unwrap();
316 let b32 = id.to_base32();
317 let id2 = Id32::from_base32(&b32).unwrap();
318 assert_eq!(id, id2);
319 }
320
321 #[test]
322 fn id32_multihash_round_trip() {
323 let id = Id32::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
324 .unwrap();
325 let mh = id.to_multihash_hex();
326 assert!(mh.starts_with("1220"));
328 assert_eq!(mh.len(), 68); let id2 = Id32::from_multihash_hex(&mh).unwrap();
330 assert_eq!(id, id2);
331 }
332
333 #[test]
334 fn id32_multihash_reject_wrong_function_code() {
335 let bad = "1120e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
337 assert!(Id32::from_multihash_hex(bad).is_err());
338 }
339}