1use base64::{engine::general_purpose, Engine as _};
2use bip39::Mnemonic;
3use schnorrkel::{PublicKey, SecretKey};
4use scrypt::{scrypt, Params as ScryptParams};
5use serde::{Deserialize, Serialize};
6use sodiumoxide::crypto::secretbox;
7use sodiumoxide::crypto::secretbox::{Key, Nonce};
8use sp_core::crypto::Ss58Codec;
9use sp_core::{sr25519, ByteArray, Pair};
10use std::fmt;
11
12const PKCS8_HEADER: &[u8] = &[48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32];
13const PKCS8_DIVIDER: &[u8] = &[161, 35, 3, 33, 0];
14const SEC_LENGTH: usize = 64;
15const PUB_LENGTH: usize = 32;
16
17#[derive(Serialize, Deserialize, Debug)]
18struct Encoding {
19 content: Vec<String>,
20 #[serde(rename = "type")]
21 enc_type: Vec<String>,
22 version: String,
23}
24
25#[derive(Serialize, Deserialize, Debug)]
26struct Meta {
27 #[serde(rename = "genesisHash")]
28 genesis_hash: Option<String>,
29 name: String,
30 #[serde(rename = "whenCreated")]
31 when_created: Option<u64>,
32}
33
34#[derive(Serialize, Deserialize, Debug)]
35struct JsonStructure {
36 encoded: String,
37 encoding: Encoding,
38 address: String,
39 meta: Meta,
40}
41
42#[derive(Clone)]
43pub struct Keypair {
44 ss58_address: Option<String>,
45 public_key: Option<String>,
46 private_key: Option<String>,
47 ss58_format: u8,
48 seed_hex: Option<Vec<u8>>,
49 crypto_type: u8,
50 mnemonic: Option<String>,
51 pair: Option<sr25519::Pair>,
52}
53
54impl Keypair {
55 pub fn new(
67 ss58_address: Option<String>,
68 public_key: Option<String>,
69 private_key: Option<String>,
70 ss58_format: u8,
71 seed_hex: Option<Vec<u8>>,
72 crypto_type: u8,
73 ) -> Result<Self, String> {
74 if crypto_type != 1 {
75 return Err(format!("Unsupported crypto type: {}.", crypto_type));
76 }
77
78 let mut ss58_address_res = ss58_address.clone();
79 let mut public_key_res = public_key;
80
81 if let Some(private_key_str) = &private_key {
82 let private_key_bytes =
83 hex::decode(private_key_str.trim_start_matches("0x")).expect("");
84
85 if private_key_bytes.len() != 64 {
86 return Err("Secret key should be 64 bytes long.".to_string());
87 }
88
89 }
91
92 if let Some(public_key_str) = &public_key_res {
94 let public_key_vec = hex::decode(public_key_str.trim_start_matches("0x"))
95 .map_err(|e| format!("Invalid `public_key` string: {}", e))?;
96
97 let public_key_array: [u8; 32] = public_key_vec
98 .try_into()
99 .map_err(|_| "Public key must be 32 bytes long.")?;
100
101 let public_key = sr25519::Public::from_raw(public_key_array);
102
103 ss58_address_res = Option::from(public_key.to_ss58check());
104 }
105
106 if let Some(ss58_address_str) = ss58_address.clone() {
108 let public_key = sr25519::Public::from_ss58check(&ss58_address_str)
109 .map_err(|e| format!("Invalid SS58 address: {}", e))?;
110
111 public_key_res = Some(hex::encode(public_key.to_raw()));
112 }
113
114 let kp = Keypair {
115 ss58_address: ss58_address_res,
116 public_key: public_key_res,
117 private_key,
118 ss58_format,
119 seed_hex,
120 crypto_type,
121 mnemonic: None,
122 pair: None,
123 };
124
125 if kp.public_key.is_none() {
127 return Err("No SS58 formatted address or public key provided.".to_string());
128 }
129 Ok(kp)
130 }
131
132 fn __str__(&self) -> Result<String, String> {
133 match self.ss58_address() {
134 Some(address) => Ok(format!("<Keypair (address={})>", address)),
135 None => Ok("<Keypair (address=None)>".to_string()),
136 }
137 }
138
139 fn __repr__(&self) -> Result<String, String> {
140 self.__str__()
141 }
142
143 pub fn generate_mnemonic(n_words: usize) -> Result<String, String> {
150 let mnemonic = Mnemonic::generate(n_words).map_err(|e| e.to_string())?;
151 Ok(mnemonic.to_string())
152 }
153
154 pub fn create_from_mnemonic(mnemonic: &str) -> Result<Self, String> {
161 let (pair, seed_vec) =
162 sr25519::Pair::from_phrase(mnemonic, None).map_err(|e| e.to_string())?;
163
164 let kp = Keypair {
165 mnemonic: Some(mnemonic.to_string()),
166 seed_hex: Some(seed_vec.to_vec()),
167 pair: Some(pair),
168 ..Default::default()
169 };
170 Ok(kp)
171 }
172
173 pub fn create_from_seed(seed: Vec<u8>) -> Result<Self, String> {
180 let pair = sr25519::Pair::from_seed_slice(&seed)
181 .map_err(|e| format!("Failed to create pair from seed: {}", e))?;
182
183 let kp = Keypair {
184 seed_hex: Some(seed.to_vec()),
185 pair: Some(pair),
186 ..Default::default()
187 };
188 Ok(kp)
189 }
190
191 pub fn create_from_private_key(private_key: &str) -> Result<Self, String> {
198 let private_key_vec = hex::decode(private_key.trim_start_matches("0x"))
199 .map_err(|e| format!("Invalid `private_key` string: {}", e))?;
200
201 let pair = sr25519::Pair::from_seed_slice(&private_key_vec)
202 .map_err(|e| format!("Failed to create pair from private key: {}", e))?;
203
204 let kp = Keypair {
205 pair: Some(pair),
206 ..Default::default()
207 };
208 Ok(kp)
209 }
210
211 pub fn create_from_encrypted_json(
219 json_data: &str,
220 passphrase: &str,
221 ) -> Result<Keypair, String> {
222 fn pad_right(mut data: Vec<u8>, total_len: usize, pad_byte: u8) -> Vec<u8> {
224 if data.len() < total_len {
225 let pad_len = total_len - data.len();
226 data.extend(vec![pad_byte; pad_len]);
227 }
228 data
229 }
230
231 pub fn pair_from_ed25519_secret_key(secret: &[u8], pubkey: &[u8]) -> ([u8; 64], [u8; 32]) {
232 match (
233 SecretKey::from_ed25519_bytes(secret),
234 PublicKey::from_bytes(pubkey),
235 ) {
236 (Ok(s), Ok(k)) => (s.to_bytes(), k.to_bytes()),
237 _ => panic!("Invalid secret or pubkey provided."),
238 }
239 }
240
241 fn decode_pkcs8(
244 ciphertext: &[u8],
245 ) -> Result<([u8; SEC_LENGTH], [u8; PUB_LENGTH]), &'static str> {
246 let mut current_offset = 0;
247 let header = &ciphertext[current_offset..current_offset + PKCS8_HEADER.len()];
248 if header != PKCS8_HEADER {
249 return Err("Invalid Pkcs8 header found in body");
250 }
251 current_offset += PKCS8_HEADER.len();
252 let secret_key = &ciphertext[current_offset..current_offset + SEC_LENGTH];
253 let mut secret_key_array = [0u8; SEC_LENGTH];
254 secret_key_array.copy_from_slice(secret_key);
255 current_offset += SEC_LENGTH;
256 let divider = &ciphertext[current_offset..current_offset + PKCS8_DIVIDER.len()];
257 if divider != PKCS8_DIVIDER {
258 return Err("Invalid Pkcs8 divider found in body");
259 }
260 current_offset += PKCS8_DIVIDER.len();
261 let public_key = &ciphertext[current_offset..current_offset + PUB_LENGTH];
262 let mut public_key_array = [0u8; PUB_LENGTH];
263 public_key_array.copy_from_slice(public_key);
264 Ok((secret_key_array, public_key_array))
265 }
266
267 let json_data: JsonStructure = serde_json::from_str(json_data).unwrap();
268
269 if json_data.encoding.version != "3" {
270 return Err("Unsupported JSON format".to_string());
271 }
272
273 let mut encrypted = general_purpose::STANDARD
274 .decode(json_data.encoded)
275 .map_err(|e| e.to_string())?;
276
277 let password = if json_data.encoding.enc_type.contains(&"scrypt".to_string()) {
278 let salt = &encrypted[0..32];
279 let n = u32::from_le_bytes(encrypted[32..36].try_into().unwrap());
280 let p = u32::from_le_bytes(encrypted[36..40].try_into().unwrap());
281 let r = u32::from_le_bytes(encrypted[40..44].try_into().unwrap());
282 let log_n: u8 = n.ilog2() as u8;
283
284 let params = ScryptParams::new(log_n, r, p, 32).map_err(|e| e.to_string())?;
285 let mut derived_key = vec![0u8; 32];
286 scrypt(passphrase.as_bytes(), salt, ¶ms, &mut derived_key)
287 .map_err(|e| e.to_string())?;
288 encrypted = encrypted[44..].to_vec();
289 derived_key
290 } else {
291 let mut derived_key = passphrase.as_bytes().to_vec();
292 derived_key = pad_right(derived_key, 32, 0x00);
293 derived_key
294 };
295
296 let nonce_bytes = &encrypted[0..24];
297 let nonce = Nonce::from_slice(nonce_bytes)
298 .ok_or("Invalid nonce length")
299 .map_err(|e| e.to_string())?;
300 let message = &encrypted[24..];
301
302 let key = Key::from_slice(&password).ok_or("Invalid key length")?;
303 let decrypted_data = secretbox::open(message, &nonce, &key)
304 .map_err(|_| "Failed to decrypt data".to_string())?;
305 let (private_key, public_key) =
306 decode_pkcs8(&decrypted_data).map_err(|_| "Failed to decode PKCS8 data".to_string())?;
307
308 let (secret, converted_public_key) =
309 pair_from_ed25519_secret_key(&private_key[..], &public_key[..]);
310
311 let keypair = match json_data.encoding.content.iter().any(|c| c == "sr25519") {
312 true => {
313 assert_eq!(public_key, converted_public_key);
314 Keypair::create_from_private_key(&hex::encode(secret))
315 }
316 _ => return Err("Unsupported keypair type.".to_string()),
317 };
318
319 keypair
320 }
321
322 pub fn create_from_uri(uri: &str) -> Result<Self, String> {
329 let pair = Pair::from_string(uri, None).map_err(|e| e.to_string())?;
330
331 let kp = Keypair {
332 pair: Some(pair),
333 ..Default::default()
334 };
335 Ok(kp)
336 }
337
338 pub fn sign(&self, data: Vec<u8>) -> Result<Vec<u8>, String> {
345 let pair = self
347 .pair
348 .as_ref()
349 .ok_or_else(|| "No private key set to create signatures".to_string())?;
350
351 let signature = match self.crypto_type {
353 1 => {
354 pair.sign(&data)
356 }
357 _ => {
358 return Err("Crypto type not supported.".to_string());
359 }
360 };
361
362 Ok(signature.to_vec())
363 }
364
365 pub fn verify(&self, data: Vec<u8>, signature: Vec<u8>) -> Result<bool, String> {
373 let public_key = if let Some(public_key_str) = &self.public_key {
375 hex::decode(public_key_str.trim_start_matches("0x"))
376 .map_err(|e| format!("Invalid `public_key` string: {:?}", e))?
377 } else if let Some(pair) = &self.pair {
378 pair.public().to_vec()
379 } else {
380 return Err("No public key or pair available.".to_string());
381 };
382
383 let public = sr25519::Public::from_raw(
384 <[u8; 32]>::try_from(public_key)
385 .map_err(|e| format!("Invalid public key length: {:?}", e))?,
386 );
387
388 let signature = sr25519::Signature::from_slice(&signature)
390 .map_err(|_| "Invalid signature".to_string())?;
391
392 let verified = match self.crypto_type {
394 1 => {
395 sr25519::Pair::verify(&signature, &data, &public)
397 }
398 _ => {
399 return Err("Crypto type not supported".to_string());
400 }
401 };
402
403 if !verified {
405 let wrapped_data = [b"<Bytes>", data.as_slice(), b"</Bytes>"].concat();
406 let verified_wrapped = match self.crypto_type {
407 1 => {
408 sr25519::Pair::verify(&signature, wrapped_data, &public)
410 }
411 _ => {
412 return Err("Crypto type not supported".to_string());
413 }
414 };
415
416 Ok(verified_wrapped)
417 } else {
418 Ok(verified)
419 }
420 }
421
422 pub fn ss58_address(&self) -> Option<String> {
424 match &self.pair {
425 Some(pair) => {
426 let ss58_address = pair.public().to_ss58check();
427 Some(ss58_address)
428 }
429 None => self.ss58_address.clone(),
430 }
431 }
432
433 pub fn public_key(&self) -> Result<Option<Vec<u8>>, String> {
435 if let Some(pair) = &self.pair {
436 let public_key_vec = pair.public().to_vec();
437 Ok(Some(public_key_vec))
438 } else if let Some(public_key) = &self.public_key {
439 let public_key_vec = hex::decode(public_key.trim_start_matches("0x"))
440 .map_err(|e| format!("Invalid `public_key` string: {}", e))?;
441 Ok(Some(public_key_vec))
442 } else {
443 Ok(None)
444 }
445 }
446
447 pub fn ss58_format(&self) -> u8 {
449 self.ss58_format
450 }
451
452 pub fn seed_hex(&self) -> Option<Vec<u8>> {
453 self.seed_hex.clone()
454 }
455
456 pub fn crypto_type(&self) -> u8 {
458 self.crypto_type
459 }
460
461 pub fn set_crypto_type(&mut self, crypto_type: u8) {
466 self.crypto_type = crypto_type;
467 }
468
469 pub fn mnemonic(&self) -> Option<String> {
471 self.mnemonic.clone()
472 }
473
474 pub fn private_key(&self) -> Result<Option<Vec<u8>>, String> {
476 match &self.pair {
477 Some(pair) => {
478 let seed = pair.to_raw_vec();
479 Ok(Some(seed))
480 }
481 None => {
482 if let Some(private_key) = &self.private_key {
483 Ok(Some(private_key.as_bytes().to_vec()))
484 } else {
485 Ok(None)
486 }
487 }
488 }
489 }
490}
491
492impl Default for Keypair {
494 fn default() -> Self {
495 Keypair {
496 ss58_address: None,
497 public_key: None,
498 private_key: None,
499 ss58_format: 42,
500 seed_hex: None,
501 crypto_type: 1,
502 mnemonic: None,
503 pair: None,
504 }
505 }
506}
507
508impl fmt::Display for Keypair {
509 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
510 let address = self.ss58_address();
511 match address {
512 Some(addr) => write!(f, "<Keypair (address={})>", addr),
513 None => write!(f, "<Keypair (address=None)>"),
514 }
515 }
516}
517
518impl fmt::Debug for Keypair {
519 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
520 let address = self.ss58_address();
521 match address {
522 Some(addr) => write!(f, "<Keypair (address={})>", addr),
523 None => write!(f, "<Keypair (address=None)>"),
524 }
525 }
526}