浏览代码

Merge pull request #27 from Relayz-io/silvestr/16-move-cryptographic-code-from-near-client

Copy existed crypto.rs to common-api crate
develop
Predko Silvestr 2 年前
父节点
当前提交
4363d747ce
没有帐户链接到提交者的电子邮件
共有 5 个文件被更改,包括 400 次插入1 次删除
  1. 1
    1
      Cargo.toml
  2. 23
    0
      common-api/Cargo.toml
  3. 321
    0
      common-api/src/crypto/ed25519.rs
  4. 51
    0
      common-api/src/crypto/mod.rs
  5. 4
    0
      common-api/src/lib.rs

+ 1
- 1
Cargo.toml 查看文件

@@ -1,5 +1,5 @@
1 1
 [workspace]
2
-members = ["wasm-client", "near-client"]
2
+members = ["wasm-client", "near-client", "common-api"]
3 3
 
4 4
 [profile.release]
5 5
 codegen-units = 1

+ 23
- 0
common-api/Cargo.toml 查看文件

@@ -0,0 +1,23 @@
1
+[package]
2
+name = "common-api"
3
+version = "0.1.0"
4
+edition = "2021"
5
+authors = ["silvestr@relayz.io"]
6
+description = """
7
+This crate is used between many other crates to provide the same
8
+API for signing data and shared types. Please note that all data
9
+structures should be serializable with "serde" and "borsh"
10
+"""
11
+
12
+[lib]
13
+crate-type = ["cdylib", "rlib"]
14
+
15
+[dependencies]
16
+base64 = "0.13"
17
+bs58 = "0.4"
18
+borsh = "0.9"
19
+ed25519-dalek = "1"
20
+itertools = "0.10"
21
+serde = { version = "1", default-features = false, features = ["derive"] }
22
+serde_json = { version = "1", default-features = false }
23
+thiserror = "1"

+ 321
- 0
common-api/src/crypto/ed25519.rs 查看文件

@@ -0,0 +1,321 @@
1
+//! ### Sign with ed25519 elliptic curve signing algorithm
2
+//! ---
3
+//! Used Dalek cryptography, and implemented [`Borsh`](https://borsh.io/) serialization for them
4
+
5
+use borsh::{BorshDeserialize, BorshSerialize};
6
+use ed25519_dalek::{
7
+    ExpandedSecretKey, PublicKey, SecretKey, Signature, Verifier, PUBLIC_KEY_LENGTH,
8
+    SECRET_KEY_LENGTH, SIGNATURE_LENGTH,
9
+};
10
+use itertools::Itertools;
11
+use serde::{Deserialize, Serialize};
12
+use std::{
13
+    fmt::{Debug, Display},
14
+    hash::{Hash, Hasher},
15
+    io::{Error as IoError, ErrorKind},
16
+    str::FromStr,
17
+};
18
+
19
+use super::Error;
20
+
21
+type Result<T> = std::result::Result<T, Error>;
22
+
23
+pub trait Key<T, const KEY_LENGTH: usize> {
24
+    fn from_string(key: &str) -> Result<T> {
25
+        let bs58_encoded = split_encoded_str(key)?;
26
+        let bytes = bs58::decode(bs58_encoded)
27
+            .into_vec()
28
+            .map_err(|err| Error::from_string::<T>(bs58_encoded.to_owned(), err.to_string()))?;
29
+        Self::from_bytes(&bytes)
30
+    }
31
+
32
+    fn to_string(&self) -> String {
33
+        format!("ed25519:{}", bs58::encode(self.to_bytes()).into_string())
34
+    }
35
+
36
+    fn from_bytes(bytes: &[u8]) -> Result<T>;
37
+    fn to_bytes(&self) -> [u8; KEY_LENGTH];
38
+}
39
+
40
+#[derive(Copy, Clone, Default, Eq, PartialEq)]
41
+pub struct ED25519PublicKey(PublicKey);
42
+
43
+impl ED25519PublicKey {
44
+    pub fn verify(&self, data: &[u8], signature: &ED25519Signature) -> Result<()> {
45
+        self.0
46
+            .verify(data, &signature.0)
47
+            .map_err(|_| Error::Verification(*signature))
48
+    }
49
+
50
+    #[inline]
51
+    pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LENGTH] {
52
+        self.0.as_bytes()
53
+    }
54
+}
55
+
56
+impl Key<ED25519PublicKey, PUBLIC_KEY_LENGTH> for ED25519PublicKey {
57
+    fn from_bytes(bytes: &[u8]) -> Result<ED25519PublicKey> {
58
+        PublicKey::from_bytes(bytes)
59
+            .map(Self)
60
+            .map_err(|err| Error::from_bytes::<ED25519PublicKey>(bytes, err.to_string()))
61
+    }
62
+
63
+    #[inline]
64
+    fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] {
65
+        self.0.to_bytes()
66
+    }
67
+}
68
+
69
+impl BorshDeserialize for ED25519PublicKey {
70
+    fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
71
+        if buf.len() != PUBLIC_KEY_LENGTH {
72
+            return Err(IoError::new(ErrorKind::InvalidData, format!("Couldn't deserialize a ED25519PublicKey, input buffer {} is greater or less than required", buf.len())));
73
+        }
74
+
75
+        // The first byte is a key type, let's skip it because currently is used ed25519 only
76
+        let temp_buf = std::mem::take(buf);
77
+        Ok(Self(PublicKey::from_bytes(&temp_buf[1..]).map_err(
78
+            |err| {
79
+                IoError::new(
80
+                    ErrorKind::InvalidData,
81
+                    format!("Couldn't deserialize a ED25519PublicKey because of: {err}"),
82
+                )
83
+            },
84
+        )?))
85
+    }
86
+}
87
+
88
+impl BorshSerialize for ED25519PublicKey {
89
+    fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
90
+        BorshSerialize::serialize(&0_u8, writer)?;
91
+        writer.write_all(self.0.as_bytes())
92
+    }
93
+}
94
+
95
+impl From<&ED25519SecretKey> for ED25519PublicKey {
96
+    fn from(sk: &ED25519SecretKey) -> Self {
97
+        Self(PublicKey::from(&sk.0))
98
+    }
99
+}
100
+
101
+// This `Hash` implementation is safe since it retains the property
102
+// `k1 == k2 ⇒ hash(k1) == hash(k2)`.
103
+#[allow(clippy::derive_hash_xor_eq)]
104
+impl Hash for ED25519PublicKey {
105
+    fn hash<H: Hasher>(&self, state: &mut H) {
106
+        state.write_u8(0u8);
107
+        state.write(self.0.as_bytes());
108
+    }
109
+}
110
+
111
+impl Debug for ED25519PublicKey {
112
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
113
+        write!(f, "{}", self)
114
+    }
115
+}
116
+
117
+impl Display for ED25519PublicKey {
118
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119
+        write!(f, "{}", Key::to_string(self))
120
+    }
121
+}
122
+
123
+pub struct ED25519SecretKey(SecretKey);
124
+
125
+impl ED25519SecretKey {
126
+    pub fn sign(&self, data: &[u8], public_key: &ED25519PublicKey) -> ED25519Signature {
127
+        let expanded_key = ExpandedSecretKey::from(&self.0);
128
+        ED25519Signature(expanded_key.sign(data, &public_key.0))
129
+    }
130
+
131
+    #[inline]
132
+    pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LENGTH] {
133
+        self.0.as_bytes()
134
+    }
135
+
136
+    pub fn from_encoded_expanded(key: &str) -> Result<Self> {
137
+        let bs58_encoded = split_encoded_str(key)?;
138
+        let expanded_key_bytes = bs58::decode(bs58_encoded).into_vec().map_err(|err| {
139
+            Error::from_string::<ED25519SecretKey>(bs58_encoded.to_owned(), err.to_string())
140
+        })?;
141
+        Self::from_bytes(&expanded_key_bytes[..32])
142
+    }
143
+}
144
+
145
+impl Key<ED25519SecretKey, SECRET_KEY_LENGTH> for ED25519SecretKey {
146
+    fn from_bytes(bytes: &[u8]) -> Result<ED25519SecretKey> {
147
+        SecretKey::from_bytes(bytes)
148
+            .map(Self)
149
+            .map_err(|err| Error::from_bytes::<ED25519SecretKey>(bytes, err.to_string()))
150
+    }
151
+
152
+    #[inline]
153
+    fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
154
+        self.0.to_bytes()
155
+    }
156
+}
157
+
158
+#[derive(Copy, Clone, Eq, PartialEq)]
159
+pub struct ED25519Signature(Signature);
160
+
161
+impl Key<ED25519Signature, SIGNATURE_LENGTH> for ED25519Signature {
162
+    fn from_bytes(bytes: &[u8]) -> Result<ED25519Signature> {
163
+        Signature::from_bytes(bytes)
164
+            .map(Self)
165
+            .map_err(|err| Error::from_bytes::<ED25519Signature>(bytes, err.to_string()))
166
+    }
167
+
168
+    fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] {
169
+        self.0.to_bytes()
170
+    }
171
+}
172
+
173
+impl BorshSerialize for ED25519Signature {
174
+    fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
175
+        BorshSerialize::serialize(&0_u8, writer)?;
176
+        writer.write_all(&self.to_bytes())
177
+    }
178
+}
179
+
180
+impl BorshDeserialize for ED25519Signature {
181
+    fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
182
+        if buf.len() != SIGNATURE_LENGTH + 1 {
183
+            return Err(IoError::new(ErrorKind::InvalidData, format!("Couldn't deserialize a ED25519Signature, input buffer {} is greater or less than required", buf.len())));
184
+        }
185
+
186
+        // The first byte is a key type, let's skip it because currently is used ed25519 only
187
+        let temp_buf = std::mem::take(buf);
188
+        Self::from_bytes(&temp_buf[1..]).map_err(|err| {
189
+            IoError::new(
190
+                ErrorKind::InvalidData,
191
+                format!("Couldn't deserialize a ED25519Signature because of: {err}"),
192
+            )
193
+        })
194
+    }
195
+}
196
+
197
+#[allow(clippy::derive_hash_xor_eq)]
198
+impl Hash for ED25519Signature {
199
+    fn hash<H: Hasher>(&self, state: &mut H) {
200
+        self.to_bytes().hash(state);
201
+    }
202
+}
203
+
204
+impl Debug for ED25519Signature {
205
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
206
+        write!(f, "{}", self)
207
+    }
208
+}
209
+
210
+impl Display for ED25519Signature {
211
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212
+        write!(f, "{}", Key::to_string(self))
213
+    }
214
+}
215
+
216
+#[derive(Serialize, Deserialize)]
217
+pub struct Keypair {
218
+    pub public_key: ED25519PublicKey,
219
+    pub secret_key: ED25519SecretKey,
220
+}
221
+
222
+impl Keypair {
223
+    pub fn new(secret_key: ED25519SecretKey) -> Self {
224
+        let public_key = ED25519PublicKey::from(&secret_key);
225
+        Self {
226
+            public_key,
227
+            secret_key,
228
+        }
229
+    }
230
+
231
+    pub fn from_encoded(encoded: &str) -> Result<Self> {
232
+        let secret_key = ED25519SecretKey::from_encoded_expanded(encoded)?;
233
+        let public_key = ED25519PublicKey::from(&secret_key);
234
+        Ok(Self {
235
+            public_key,
236
+            secret_key,
237
+        })
238
+    }
239
+
240
+    pub fn sign(&self, data: &[u8]) -> ED25519Signature {
241
+        self.secret_key.sign(data, &self.public_key)
242
+    }
243
+
244
+    pub fn verify(&self, data: &[u8], signature: &ED25519Signature) -> Result<()> {
245
+        self.public_key.verify(data, signature)
246
+    }
247
+}
248
+
249
+macro_rules! util_impl {
250
+    ($key_type: ty) => {
251
+        impl From<$key_type> for String {
252
+            fn from(key: $key_type) -> Self {
253
+                Key::to_string(&key)
254
+            }
255
+        }
256
+
257
+        impl FromStr for $key_type {
258
+            type Err = Error;
259
+
260
+            fn from_str(s: &str) -> Result<Self> {
261
+                Self::from_string(s)
262
+            }
263
+        }
264
+    };
265
+}
266
+
267
+macro_rules! serde_impl {
268
+    ($key_type: ty) => {
269
+        impl serde::Serialize for $key_type {
270
+            fn serialize<S>(
271
+                &self,
272
+                serializer: S,
273
+            ) -> std::result::Result<<S as serde::Serializer>::Ok, <S as serde::Serializer>::Error>
274
+            where
275
+                S: serde::Serializer,
276
+            {
277
+                serializer.serialize_str(&Key::to_string(self))
278
+            }
279
+        }
280
+
281
+        impl<'de> serde::Deserialize<'de> for $key_type {
282
+            fn deserialize<D>(
283
+                deserializer: D,
284
+            ) -> std::result::Result<Self, <D as serde::Deserializer<'de>>::Error>
285
+            where
286
+                D: serde::Deserializer<'de>,
287
+            {
288
+                let s = <String as serde::Deserialize>::deserialize(deserializer)?;
289
+                s.parse().map_err(|err| {
290
+                    serde::de::Error::custom(format!("Deserialization failed: `{}`", err))
291
+                })
292
+            }
293
+        }
294
+    };
295
+}
296
+
297
+fn split_encoded_str(encoded: &str) -> Result<&str> {
298
+    match encoded.split(':').next_tuple() {
299
+        Some((key_type, bs58_encoded)) => {
300
+            if key_type != "ed25519" {
301
+                return Err(Error::UnknownKeyType(key_type.to_owned()));
302
+            }
303
+            Ok(bs58_encoded)
304
+        }
305
+        _ => Err(Error::UnknownKeyType(encoded.to_owned())),
306
+    }
307
+}
308
+
309
+serde_impl!(ED25519PublicKey);
310
+util_impl!(ED25519PublicKey);
311
+serde_impl!(ED25519SecretKey);
312
+util_impl!(ED25519SecretKey);
313
+serde_impl!(ED25519Signature);
314
+util_impl!(ED25519Signature);
315
+
316
+#[cfg(test)]
317
+mod tests {
318
+
319
+    #[test]
320
+    fn test() {}
321
+}

+ 51
- 0
common-api/src/crypto/mod.rs 查看文件

@@ -0,0 +1,51 @@
1
+pub mod ed25519;
2
+
3
+use ed25519::ED25519Signature;
4
+
5
+#[derive(thiserror::Error, Debug)]
6
+pub enum Error {
7
+    #[error(
8
+        "Couldn't convert key from bytes `{key_string}` into `{key_name}`, because of: {cause}"
9
+    )]
10
+    ConvertFromBytes {
11
+        key_name: &'static str,
12
+        key_string: String,
13
+        cause: String,
14
+    },
15
+    #[error(
16
+        "Couldn't convert key from string `{key_string}` into `{key_name}`, because of: {cause}"
17
+    )]
18
+    ConvertFromString {
19
+        key_name: &'static str,
20
+        key_string: String,
21
+        cause: String,
22
+    },
23
+    #[error("The key format `{0}` seems different from ed25519 format")]
24
+    UnknownKeyType(String),
25
+    #[error("Signature `{0}` verification failed")]
26
+    Verification(ED25519Signature),
27
+}
28
+
29
+impl Error {
30
+    pub(crate) fn from_string<T>(key_string: String, cause: String) -> Self {
31
+        Self::ConvertFromString {
32
+            key_name: std::any::type_name::<T>()
33
+                .rsplit("::")
34
+                .next()
35
+                .unwrap_or_default(),
36
+            key_string,
37
+            cause,
38
+        }
39
+    }
40
+
41
+    pub(crate) fn from_bytes<T>(data: &[u8], cause: String) -> Self {
42
+        Self::ConvertFromBytes {
43
+            key_name: std::any::type_name::<T>()
44
+                .rsplit("::")
45
+                .next()
46
+                .unwrap_or_default(),
47
+            key_string: bs58::encode(data).into_string(),
48
+            cause,
49
+        }
50
+    }
51
+}

+ 4
- 0
common-api/src/lib.rs 查看文件

@@ -0,0 +1,4 @@
1
+pub mod crypto;
2
+
3
+#[cfg(test)]
4
+mod tests {}

正在加载...
取消
保存