near_client/crypto/
mod.rs

1//! Fast and efficient Rust implementation of ed25519 key generation, signing, and verification
2//! Used a [Dalek](https://github.com/dalek-cryptography/ed25519-dalek) cryptography
3//! By default near is using two kinds of keys. ed25519 and secp256k1.
4//! For simplicity secp256k1 is removed and used ed25519 only.
5
6#[macro_use]
7mod serde_impl {
8    macro_rules! serde_impl {
9        ($key_type: ty) => {
10            impl serde::Serialize for $key_type {
11                fn serialize<S>(
12                    &self,
13                    serializer: S,
14                ) -> std::result::Result<
15                    <S as serde::Serializer>::Ok,
16                    <S as serde::Serializer>::Error,
17                >
18                where
19                    S: serde::Serializer,
20                {
21                    serializer.serialize_str(&Key::string(self))
22                }
23            }
24
25            impl<'de> serde::Deserialize<'de> for $key_type {
26                fn deserialize<D>(
27                    deserializer: D,
28                ) -> std::result::Result<Self, <D as serde::Deserializer<'de>>::Error>
29                where
30                    D: serde::Deserializer<'de>,
31                {
32                    let s = <String as serde::Deserialize>::deserialize(deserializer)?;
33                    <$key_type>::from_string(&s).map_err(|err| {
34                        serde::de::Error::custom(format!("Deserialization failed: `{}`", err))
35                    })
36                }
37            }
38        };
39    }
40}
41
42pub mod dhx;
43pub mod ed25519;
44/// Crypto prelude
45pub mod prelude {
46    pub use super::{
47        dhx::{PublicKey, SecretKey, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH},
48        ed25519::{
49            Ed25519PublicKey, Ed25519SecretKey, Ed25519Signature, Keypair,
50            ED25519_PUBLIC_KEY_LENGTH, ED25519_SECRET_KEY_LENGTH, ED25519_SIGNATURE_LENGTH,
51        },
52        Error, Key,
53    };
54}
55
56use itertools::Itertools;
57
58type Result<T> = std::result::Result<T, Error>;
59
60pub(crate) const ED25519: &str = "ed25519";
61pub(crate) const X25519: &str = "x25519";
62
63/// ## Key
64/// **KEY_LENGTH** - It's a key size for ed25519 or x25519
65pub trait Key<const KEY_LENGTH: usize>: Sized {
66    /// **KEY_TYPE** - Key type, for internal usage to reduce a boilerplate code.
67    /// It's a prefix for a key string serialization. Possible values are ["ed25519", "x25519"]
68    const KEY_TYPE: &'static str;
69
70    /// Parse an encoded string to the corresponding [`Key`]
71    fn from_string(key: &str) -> Result<Self> {
72        let (key_type, bs58_encoded) = split_encoded_str(key)?;
73
74        if key_type != Self::KEY_TYPE {
75            return Err(Error::WrongKeyType {
76                key_type: key_type.to_owned(),
77                expected_key_type: Self::KEY_TYPE,
78            });
79        }
80
81        let bytes = bs58::decode(bs58_encoded)
82            .into_vec()
83            .map_err(|err| Error::from_string::<Self>(bs58_encoded.to_owned(), err.to_string()))?;
84        Self::try_from_bytes(&bytes)
85    }
86
87    /// Return a string representation of a [`Key`]
88    /// The string is split with a delimiter ":"
89    /// The first part is a `X25519` or `ED25519` prefix
90    /// The second part is a bs58 encoded key
91    fn string(&self) -> String {
92        format!(
93            "{}:{}",
94            Self::KEY_TYPE,
95            bs58::encode(self.to_bytes()).into_string()
96        )
97    }
98
99    /// Parse a bytes slice to the corresponding [`Key`]
100    fn try_from_bytes(buf: &[u8]) -> Result<Self>;
101
102    /// Return a byte representation of a [`Key`]
103    /// The size of a slice defined with a `KEY_LENGTH`
104    fn to_bytes(&self) -> [u8; KEY_LENGTH];
105}
106
107/// Errors that happens during crypto operations
108#[derive(thiserror::Error, Debug)]
109pub enum Error {
110    /// Convert Error, happens during conversion from a bytes
111    #[error("Couldn't convert key from bytes \"{data}\" into \"{key_name}\", because of: {cause}")]
112    ConvertFromBytes {
113        /// Key type ed25519 or x25519
114        key_name: &'static str,
115        /// Data that cause an error
116        data: String,
117        /// Actual cause
118        cause: String,
119    },
120    /// Convert Error, happens during conversion from a string
121    #[error(
122        "Couldn't convert key from string \"{data}\" into \"{key_name}\", because of: {cause}"
123    )]
124    ConvertFromString {
125        /// Key type ed25519 or x25519
126        key_name: &'static str,
127        /// Data that cause an error
128        data: String,
129        /// Actual cause
130        cause: String,
131    },
132    /// Used an unknown key prefix
133    #[error("The key format \"{0}\" seems different from ed25519 or x25519 format")]
134    UnknownKeyType(String),
135    /// Key type error
136    #[error(
137        "The expected key type \"{expected_key_type}\" is different from actual \"{key_type}\""
138    )]
139    WrongKeyType {
140        /// Something different than ed25519 or x25519
141        key_type: String,
142        /// Key type ed25519 or x25519
143        expected_key_type: &'static str,
144    },
145    /// Signature verification Error
146    #[error("Signature \"{0}\" verification failed")]
147    Verification(String),
148}
149
150impl Error {
151    pub(crate) fn from_string<T>(data: String, cause: String) -> Self {
152        Self::ConvertFromString {
153            key_name: std::any::type_name::<T>()
154                .rsplit("::")
155                .next()
156                .unwrap_or_default(),
157            data,
158            cause,
159        }
160    }
161
162    pub(crate) fn from_bytes<T>(data: &[u8], cause: String) -> Self {
163        Self::ConvertFromBytes {
164            key_name: std::any::type_name::<T>()
165                .rsplit("::")
166                .next()
167                .unwrap_or_default(),
168            data: bs58::encode(data).into_string(),
169            cause,
170        }
171    }
172}
173
174/// Split encoded [`str`] to key prefix and bs58 encoded string
175fn split_encoded_str(encoded: &str) -> Result<(&str, &str)> {
176    match encoded.split(':').next_tuple() {
177        Some((key_type @ ED25519, bs58_encoded) | (key_type @ X25519, bs58_encoded)) => {
178            Ok((key_type, bs58_encoded))
179        }
180        _ => Err(Error::UnknownKeyType(encoded.to_owned())),
181    }
182}
183
184#[cfg(test)]
185mod tests {
186
187    use super::{split_encoded_str, Error, ED25519, X25519};
188
189    #[test]
190    fn split_encoded() {
191        let bs58_str = bs58::encode(vec![0, 0, 0]).into_string();
192        assert!(matches!(
193                split_encoded_str(&format!("ed25519:{bs58_str}")),
194                Ok((key_type, s)) if key_type == ED25519 && s == bs58_str));
195        assert!(matches!(
196                split_encoded_str(&format!("x25519:{bs58_str}")),
197                Ok((key_type, s)) if key_type == X25519 && s == bs58_str));
198        assert!(matches!(
199            split_encoded_str(&bs58_str),
200            Err(Error::UnknownKeyType(..))
201        ));
202    }
203}