near_client/crypto/
mod.rs1#[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;
44pub 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
63pub trait Key<const KEY_LENGTH: usize>: Sized {
66 const KEY_TYPE: &'static str;
69
70 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 fn string(&self) -> String {
92 format!(
93 "{}:{}",
94 Self::KEY_TYPE,
95 bs58::encode(self.to_bytes()).into_string()
96 )
97 }
98
99 fn try_from_bytes(buf: &[u8]) -> Result<Self>;
101
102 fn to_bytes(&self) -> [u8; KEY_LENGTH];
105}
106
107#[derive(thiserror::Error, Debug)]
109pub enum Error {
110 #[error("Couldn't convert key from bytes \"{data}\" into \"{key_name}\", because of: {cause}")]
112 ConvertFromBytes {
113 key_name: &'static str,
115 data: String,
117 cause: String,
119 },
120 #[error(
122 "Couldn't convert key from string \"{data}\" into \"{key_name}\", because of: {cause}"
123 )]
124 ConvertFromString {
125 key_name: &'static str,
127 data: String,
129 cause: String,
131 },
132 #[error("The key format \"{0}\" seems different from ed25519 or x25519 format")]
134 UnknownKeyType(String),
135 #[error(
137 "The expected key type \"{expected_key_type}\" is different from actual \"{key_type}\""
138 )]
139 WrongKeyType {
140 key_type: String,
142 expected_key_type: &'static str,
144 },
145 #[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
174fn 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}