ratman_identity/
lib.rs

1//! # A Ratman network identity abstraction
2//!
3//! Because Ratman is a userspace router with no concept of link layer
4//! identities, network IDs are chosen to be fixed size byte arrays.
5//! It's left to the implementing application to map these to some
6//! useful source of identity.  This crate also provides a hashing
7//! constructor behind the `digest` feature flag which can be used to
8//! hash a secret to derive the identity value.
9//!
10//! Whatever scheme is chosen, two principles about identity must not
11//! be violated:
12//!
13//! 1. There are no identity collisions
14//! 2. Identities don't change mid-route
15//!
16//! This crate is part of the qaul project.  The docs for this
17//! crate are propably lacking because currently Ratman/ libqaul are
18//! the only users of it.  If you have questions, don't hesitate to
19//! [contact us]!
20//!
21//! [contact us]: https://docs.qaul.org/contributors/social/_intro.html
22
23use cfg_if;
24use serde::{
25    de::{Deserializer, SeqAccess, Visitor},
26    Deserialize, Serialize, Serializer,
27};
28use std::{
29    fmt::{self, Debug, Display, Formatter},
30    string::ToString,
31};
32
33cfg_if::cfg_if! {
34    if #[cfg(features = "aligned")] {
35        use std::mem::size_of,
36        /// Length of the identity buffer to align with platform words
37        pub const ID_LEN: usize = size_of::<usize>();
38    } else {
39        /// Length of the identity buffer to align with an ed25519 pubkey
40        pub const ID_LEN: usize = 32;
41    }
42}
43
44/// A generic object identifier
45#[derive(Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
46pub struct Identity([u8; ID_LEN]);
47
48impl Debug for Identity {
49    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
50        write!(f, "<ID: {}>", hex::encode_upper(self))
51    }
52}
53
54impl Display for Identity {
55    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
56        write!(
57            f,
58            "{}",
59            hex::encode_upper(self)
60                .as_bytes()
61                .chunks(4)
62                .map(std::str::from_utf8)
63                .collect::<Result<Vec<_>, _>>()
64                .unwrap()
65                .join("-")
66        )
67    }
68}
69
70impl Identity {
71    /// Create an identity from the first 16 bytes of a vector
72    ///
73    /// This function will panic, if the provided vector isn't long
74    /// enough, but extra data will simply be discarded.
75    pub fn truncate<'vec, V: Into<&'vec Vec<u8>>>(vec: V) -> Self {
76        let vec = vec.into();
77        assert!(vec.len() >= ID_LEN);
78
79        Self(
80            vec.into_iter()
81                .enumerate()
82                .take(ID_LEN)
83                .fold([0; ID_LEN], |mut buf, (i, u)| {
84                    buf[i] = *u;
85                    buf
86                }),
87        )
88    }
89
90    /// Create an identity from an exactly length-matched byte slice
91    ///
92    /// This function will panic, if the provided slice isn't exactly
93    /// the length of the underlying identity implementation (see
94    /// `ID_LEN`)
95    pub fn from_bytes(buf: &[u8]) -> Self {
96        assert_eq!(buf.len(), ID_LEN);
97        Self(
98            buf.into_iter()
99                .enumerate()
100                .fold([0; ID_LEN], |mut buf, (i, u)| {
101                    buf[i] = *u;
102                    buf
103                }),
104        )
105    }
106
107    pub fn from_string(s: &String) -> Self {
108        let v: Vec<u8> = s
109            .split("-")
110            .map(|s| {
111                hex::decode(s).expect(
112                    "Don't call from_string() on input that was not serialised by to_string()!",
113                )
114            })
115            .collect::<Vec<Vec<u8>>>()
116            .into_iter()
117            .flatten()
118            .collect();
119        Self::from_bytes(&v)
120    }
121
122    pub fn as_bytes(&self) -> &[u8] {
123        &self.0
124    }
125
126    /// Create an identity using a digest function
127    ///
128    /// This allows you to pass arbitrary length data which will
129    /// result in a precise ID length data output.  The hash function
130    /// is the cryptographic [blake2] cipher, so it can be used to
131    /// turn secrets into identity information.
132    ///
133    /// This function requires the `digest` feature.
134    ///
135    /// [blake2]: https://blake2.net/
136    #[cfg(feature = "digest")]
137    pub fn with_digest<'vec, V: Into<&'vec Vec<u8>>>(vec: V) -> Self {
138        use blake2::{
139            digest::{Input, VariableOutput},
140            VarBlake2b,
141        };
142
143        let mut hasher = VarBlake2b::new(ID_LEN).unwrap();
144        hasher.input(vec.into());
145        Self::truncate(&hasher.vec_result())
146    }
147
148    /// Generate a new random Identity
149    #[cfg(feature = "random")]
150    pub fn random() -> Self {
151        use rand::RngCore;
152        let mut rng = rand::thread_rng();
153        let mut buf = [0; ID_LEN];
154        rng.fill_bytes(&mut buf);
155        Self(buf)
156    }
157
158    /// Returns an iterator over the bytes of the identity
159    pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a u8> {
160        self.0.iter()
161    }
162}
163
164/// Implement RAW `From` binary array
165impl From<[u8; ID_LEN]> for Identity {
166    fn from(i: [u8; ID_LEN]) -> Self {
167        Self(i)
168    }
169}
170
171/// Implement RAW `From` binary (reference) array
172impl From<&[u8; ID_LEN]> for Identity {
173    fn from(i: &[u8; ID_LEN]) -> Self {
174        Self(i.clone())
175    }
176}
177
178/// Implement binary array `From` RAW
179impl From<Identity> for [u8; ID_LEN] {
180    fn from(i: Identity) -> Self {
181        i.0
182    }
183}
184
185/// Implement binary array `From` RAW reference
186impl From<&Identity> for [u8; ID_LEN] {
187    fn from(i: &Identity) -> Self {
188        i.0.clone()
189    }
190}
191
192/// Implement RAW identity to binary array reference
193impl AsRef<[u8]> for Identity {
194    fn as_ref(&self) -> &[u8] {
195        &self.0
196    }
197}
198
199/// Iterator for iterating over `Identity`
200pub struct Iter {
201    index: usize,
202    ident: Identity,
203}
204
205impl Iterator for Iter {
206    type Item = u8;
207    fn next(&mut self) -> Option<Self::Item> {
208        let ret = self.ident.0.get(self.index).map(|byte| *byte);
209        self.index += 1;
210        ret
211    }
212}
213
214impl IntoIterator for Identity {
215    type Item = u8;
216    type IntoIter = Iter;
217    fn into_iter(self) -> Self::IntoIter {
218        Iter {
219            index: 0,
220            ident: self,
221        }
222    }
223}
224
225impl Serialize for Identity {
226    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
227    where
228        S: Serializer,
229    {
230        if ser.is_human_readable() {
231            ser.serialize_str(&self.to_string())
232        } else {
233            ser.serialize_bytes(&self.0)
234        }
235    }
236}
237
238impl<'de> Deserialize<'de> for Identity {
239    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
240    where
241        D: Deserializer<'de>,
242    {
243        use serde::de::Error;
244
245        struct IdentityVisitor;
246
247        impl IdentityVisitor {
248            fn from_str<E: Error>(v: &str) -> Result<Identity, E> {
249                let v: Vec<u8> = v
250                    .split("-")
251                    .map(|s| hex::decode(s).map_err(|e| E::custom(e)))
252                    // I don't like this way of propagating errors up but the alternative
253                    // is a for loop which i also don't like
254                    .collect::<Result<Vec<Vec<u8>>, E>>()?
255                    .into_iter()
256                    .flatten()
257                    .collect();
258
259                Self::from_bytes(&v)
260            }
261
262            fn from_bytes<E: Error, V: AsRef<[u8]>>(v: V) -> Result<Identity, E> {
263                let v = v.as_ref();
264                if v.len() != ID_LEN {
265                    return Err(E::custom(format!(
266                        "Expected {} bytes, got {}",
267                        ID_LEN,
268                        v.len()
269                    )));
270                }
271
272                Ok(Identity(v.iter().enumerate().take(ID_LEN).fold(
273                    [0; ID_LEN],
274                    |mut buf, (i, u)| {
275                        buf[i] = *u;
276                        buf
277                    },
278                )))
279            }
280        }
281
282        impl<'de> Visitor<'de> for IdentityVisitor {
283            type Value = Identity;
284
285            fn expecting(&self, f: &mut Formatter) -> fmt::Result {
286                write!(
287                    f,
288                    "Either a {l} byte array or a hex string representing {l} bytes",
289                    l = ID_LEN
290                )
291            }
292
293            fn visit_borrowed_str<E: Error>(self, v: &'de str) -> Result<Self::Value, E> {
294                Self::from_str(v)
295            }
296
297            fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
298                Self::from_str(&v)
299            }
300
301            fn visit_borrowed_bytes<E: Error>(self, v: &'de [u8]) -> Result<Self::Value, E> {
302                Self::from_bytes(v)
303            }
304
305            fn visit_byte_buf<E: Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
306                Self::from_bytes(v)
307            }
308
309            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
310            where
311                A: SeqAccess<'de>,
312            {
313                let mut v = Vec::new();
314                while let Some(b) = seq.next_element::<u8>()? {
315                    v.push(b);
316                }
317
318                Self::from_bytes(v)
319            }
320        }
321
322        if deserializer.is_human_readable() {
323            deserializer.deserialize_str(IdentityVisitor)
324        } else {
325            deserializer.deserialize_bytes(IdentityVisitor)
326        }
327    }
328}
329
330#[cfg(test)]
331mod test {
332    use super::*;
333    use bincode;
334    use serde_json;
335
336    #[test]
337    #[cfg(not(features = "aligned"))]
338    fn json_serde() {
339        let s = b"Yes, we will make total destroy.";
340        let i = Identity::truncate(&s.to_vec());
341        let v = serde_json::to_string(&i).unwrap();
342        assert_eq!(
343            v,
344            "\"5965-732C-2077-6520-7769-6C6C-206D-616B-6520-746F-7461-6C20-6465-7374-726F-792E\""
345        );
346        let i2 = serde_json::from_str(&v).unwrap();
347        assert_eq!(i, i2);
348    }
349
350    #[test]
351    #[cfg(not(features = "aligned"))]
352    fn bincode_serde() {
353        let s = b"Yes, we will make total destroy.";
354        let i = Identity::truncate(&s.to_vec());
355        let v: Vec<u8> = bincode::serialize(&i).unwrap();
356        assert_eq!(
357            v,
358            vec![
359                32, 0, 0, 0, 0, 0, 0, 0, 89, 101, 115, 44, 32, 119, 101, 32, 119, 105, 108, 108,
360                32, 109, 97, 107, 101, 32, 116, 111, 116, 97, 108, 32, 100, 101, 115, 116, 114,
361                111, 121, 46
362            ],
363        );
364        let i2 = bincode::deserialize(&v).unwrap();
365        assert_eq!(i, i2);
366    }
367
368    #[test]
369    #[cfg(features = "aligned")]
370    fn sized() {
371        assert_eq!(crate::ID_LEN, size_of::<usize>());
372    }
373
374    /// This is the default length
375    #[test]
376    #[cfg(not(features = "aligned"))]
377    fn sized() {
378        assert_eq!(crate::ID_LEN, 32);
379    }
380}