1extern crate rand;
2
3use anyhow::Result;
4use bip39::{Language, Mnemonic};
5use hmac::{Hmac, Mac};
6use pbkdf2::pbkdf2;
7use serde_json::json;
8use sha2::{Digest, Sha512};
9use sha3::Keccak256;
10use zeroize::Zeroize;
11
12use crate::{
13 crypto::{
14 private_key::{PrivateKey, PRIVATE_KEY_LENGTH},
15 public_key::PublicKey,
16 },
17 data::{address::Address, transaction::Transaction},
18};
19
20const REWA_COIN_TYPE: u32 = 508;
21const HARDENED: u32 = 0x80000000;
22
23type HmacSha521 = Hmac<Sha512>;
24
25#[derive(Copy, Clone, Debug)]
26pub struct Wallet {
27 priv_key: PrivateKey,
28}
29
30impl Wallet {
31 pub fn generate_mnemonic() -> Mnemonic {
33 Mnemonic::generate_in(Language::English, 24).unwrap()
34 }
35
36 fn seed_from_mnemonic(mnemonic: Mnemonic, password: &str) -> [u8; 64] {
37 let mut salt = String::with_capacity(8 + password.len());
38 salt.push_str("mnemonic");
39 salt.push_str(password);
40
41 let mut seed = [0u8; 64];
42
43 let _ = pbkdf2::<Hmac<Sha512>>(
44 mnemonic.to_string().as_bytes(),
45 salt.as_bytes(),
46 2048,
47 &mut seed,
48 );
49
50 salt.zeroize();
51
52 seed
53 }
54
55 pub fn get_private_key_from_mnemonic(
56 mnemonic: Mnemonic,
57 account: u32,
58 address_index: u32,
59 ) -> PrivateKey {
60 let seed = Self::seed_from_mnemonic(mnemonic, "");
61
62 let serialized_key_len = 32;
63 let hardened_child_padding: u8 = 0;
64
65 let mut digest =
66 HmacSha521::new_from_slice(b"ed25519 seed").expect("HMAC can take key of any size");
67 digest.update(&seed);
68 let intermediary: Vec<u8> = digest.finalize().into_bytes().into_iter().collect();
69 let mut key = intermediary[..serialized_key_len].to_vec();
70 let mut chain_code = intermediary[serialized_key_len..].to_vec();
71
72 for child_idx in [
73 44 | HARDENED,
74 REWA_COIN_TYPE | HARDENED,
75 account | HARDENED, HARDENED,
77 address_index | HARDENED, ] {
79 let mut buff = [vec![hardened_child_padding], key.clone()].concat();
80 buff.push((child_idx >> 24) as u8);
81 buff.push((child_idx >> 16) as u8);
82 buff.push((child_idx >> 8) as u8);
83 buff.push(child_idx as u8);
84
85 digest =
86 HmacSha521::new_from_slice(&chain_code).expect("HMAC can take key of any size");
87 digest.update(&buff);
88 let intermediary: Vec<u8> = digest.finalize().into_bytes().into_iter().collect();
89 key = intermediary[..serialized_key_len].to_vec();
90 chain_code = intermediary[serialized_key_len..].to_vec();
91 }
92
93 PrivateKey::from_bytes(key.as_slice()).unwrap()
94 }
95
96 pub fn from_private_key(priv_key: &str) -> Result<Self> {
97 let pri_key = PrivateKey::from_hex_str(priv_key)?;
98 Ok(Self { priv_key: pri_key })
99 }
100
101 pub fn from_pem_file(file_path: &str) -> Result<Self> {
102 let contents = std::fs::read_to_string(file_path).unwrap();
103 Self::from_pem_file_contents(contents)
104 }
105
106 pub fn from_pem_file_contents(contents: String) -> Result<Self> {
107 let x = pem::parse(contents)?;
108 let x = x.contents()[..PRIVATE_KEY_LENGTH].to_vec();
109 let priv_key_str = std::str::from_utf8(x.as_slice())?;
110 let pri_key = PrivateKey::from_hex_str(priv_key_str)?;
111 Ok(Self { priv_key: pri_key })
112 }
113
114 pub fn address(&self) -> Address {
115 let public_key = PublicKey::from(&self.priv_key);
116 Address::from(&public_key)
117 }
118
119 pub fn sign_tx(&self, unsign_tx: &Transaction) -> [u8; 64] {
120 let mut unsign_tx = unsign_tx.clone();
121 unsign_tx.signature = None;
122
123 let mut tx_bytes = json!(unsign_tx).to_string().as_bytes().to_vec();
124
125 let should_sign_on_tx_hash = unsign_tx.version >= 2 && unsign_tx.options & 1 > 0;
126 if should_sign_on_tx_hash {
127 let mut h = Keccak256::new();
128 h.update(tx_bytes);
129 tx_bytes = h.finalize().as_slice().to_vec();
130 }
131
132 self.priv_key.sign(tx_bytes)
133 }
134}