tendermint/node/
id.rs

1//! Tendermint node IDs
2
3use core::{
4    fmt::{self, Debug, Display},
5    str::FromStr,
6};
7
8use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
9use subtle::ConstantTimeEq;
10use subtle_encoding::hex;
11
12use crate::{error::Error, prelude::*};
13
14/// Length of a Node ID in bytes
15pub const LENGTH: usize = 20;
16
17/// Node IDs
18#[allow(clippy::derived_hash_with_manual_eq)]
19#[derive(Copy, Clone, Eq, Hash, PartialOrd, Ord)]
20pub struct Id([u8; LENGTH]);
21
22impl Id {
23    /// Create a new Node ID from raw bytes
24    pub fn new(bytes: [u8; LENGTH]) -> Id {
25        Id(bytes)
26    }
27
28    /// Borrow the node ID as a byte slice
29    pub fn as_bytes(&self) -> &[u8] {
30        &self.0[..]
31    }
32}
33
34impl AsRef<[u8]> for Id {
35    fn as_ref(&self) -> &[u8] {
36        self.as_bytes()
37    }
38}
39
40impl ConstantTimeEq for Id {
41    fn ct_eq(&self, other: &Id) -> subtle::Choice {
42        self.as_bytes().ct_eq(other.as_bytes())
43    }
44}
45
46impl Display for Id {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        for byte in &self.0 {
49            write!(f, "{byte:02x}")?;
50        }
51        Ok(())
52    }
53}
54
55impl Debug for Id {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        write!(f, "node::Id({self})")
58    }
59}
60
61#[cfg(feature = "rust-crypto")]
62mod key_conversions {
63    use super::{Id, LENGTH};
64    use crate::crypto::default::Sha256;
65    use crate::public_key::{Ed25519, PublicKey};
66    use crate::Error;
67    use digest::Digest;
68
69    impl From<Ed25519> for Id {
70        fn from(pk: Ed25519) -> Id {
71            let digest = Sha256::digest(pk.as_bytes());
72            let mut bytes = [0u8; LENGTH];
73            bytes.copy_from_slice(&digest[..LENGTH]);
74            Id(bytes)
75        }
76    }
77
78    impl TryFrom<PublicKey> for Id {
79        type Error = Error;
80
81        fn try_from(pk: PublicKey) -> Result<Self, Self::Error> {
82            match pk {
83                PublicKey::Ed25519(ed25519) => Ok(Id::from(ed25519)),
84                #[cfg(feature = "secp256k1")]
85                _ => Err(Error::unsupported_key_type()),
86            }
87        }
88    }
89}
90
91/// Decode Node ID from hex
92impl FromStr for Id {
93    type Err = Error;
94
95    fn from_str(s: &str) -> Result<Self, Self::Err> {
96        // Accept either upper or lower case hex
97        let bytes = hex::decode_upper(s)
98            .or_else(|_| hex::decode(s))
99            .map_err(Error::subtle_encoding)?;
100
101        if bytes.len() != LENGTH {
102            return Err(Error::parse("invalid length".to_string()));
103        }
104
105        let mut result_bytes = [0u8; LENGTH];
106        result_bytes.copy_from_slice(&bytes);
107        Ok(Id(result_bytes))
108    }
109}
110
111impl PartialEq for Id {
112    fn eq(&self, other: &Id) -> bool {
113        self.ct_eq(other).into()
114    }
115}
116
117impl<'de> Deserialize<'de> for Id {
118    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
119    where
120        D: Deserializer<'de>,
121    {
122        let s = String::deserialize(deserializer)?;
123        Self::from_str(&s).map_err(|_| {
124            de::Error::custom(format!(
125                "expected {}-character hex string, got {:?}",
126                LENGTH * 2,
127                s
128            ))
129        })
130    }
131}
132
133impl Serialize for Id {
134    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
135        self.to_string().serialize(serializer)
136    }
137}