lens_client/crypto/
mod.rs

1use k256::ecdsa::SigningKey;
2use sha3::{Digest, Keccak256};
3use std::io::Read;
4use std::path::Path;
5
6use secp256k1::{PublicKey, Secp256k1, SecretKey};
7
8pub struct Wallet {
9    pub keystore: eth_keystore::EthKeystore,
10    pub private_key: Option<Vec<u8>>,
11    pub public_key: Option<PublicKey>,
12    pub name: String,
13    pub signing_key: SigningKey,
14    pub address: String,
15    pub path: String,
16}
17
18/// Generate a new wallet with a random private key.
19/// The wallet will be saved to the given path.
20/// The wallet will be encrypted with the given password.
21/// NOTE: only for development purposes or applications running on your user device.
22/// DO NOT use this in your backend of a web application, as the wallet is stored on your backend.
23///
24/// Probably unsafe to use in production. Always prefer to just receive signatures from the user client.
25pub fn generate_wallet(
26    path: String,
27    password: String,
28    name: Option<&str>,
29    with_keys: bool,
30) -> Result<Wallet, eth_keystore::KeystoreError> {
31    let mut rng = rand::thread_rng();
32    let dir = Path::new(&path);
33    let (_private_key, name) = eth_keystore::new(dir, &mut rng, password.clone(), name)?;
34
35    let mut file = std::fs::File::open(format!("{}/{}", path, name))?;
36    let mut contents = String::new();
37    file.read_to_string(&mut contents)?;
38
39    let wallet = keystore_to_wallet(contents, &path, &name, &password, with_keys)?;
40
41    return Ok(wallet);
42}
43
44pub fn load_wallet(
45    path: &String,
46    name: &String,
47    password: String,
48) -> Result<Wallet, eth_keystore::KeystoreError> {
49    let mut file = std::fs::File::open(format!("{}/{}", path, name)).unwrap();
50    let mut contents = String::new();
51    file.read_to_string(&mut contents).unwrap();
52
53    let wallet = keystore_to_wallet(contents, path, name, &password, true)?;
54
55    return Ok(wallet);
56}
57
58pub fn keystore_to_wallet(
59    keystore_string: String,
60    path: &String,
61    name: &String,
62    password: &String,
63    with_keys: bool,
64) -> Result<Wallet, eth_keystore::KeystoreError> {
65    let keystore: eth_keystore::EthKeystore = serde_json::from_str(&keystore_string)?;
66
67    let private_key = eth_keystore::decrypt_key(format!("{}/{}", path.clone(), name), password)?;
68
69    let mut k = None;
70    let mut pk = None;
71    let signing_key = k256::ecdsa::SigningKey::from_bytes(&private_key).unwrap();
72
73    let secp = Secp256k1::new();
74    let secret_key = SecretKey::from_slice(&private_key).expect("32 bytes, within curve order");
75    let secp256k1_public_key = PublicKey::from_secret_key(&secp, &secret_key);
76
77    let pub_key_bytes = &secp256k1_public_key.serialize_uncompressed()[1..];
78
79    let mut hasher: Keccak256 = Keccak256::new();
80    hasher.update(pub_key_bytes);
81    let hash = hasher.finalize();
82
83    let hash_hex = hex::encode(hash).to_string();
84
85    let address = eth_checksum::checksum(&format!("0x{}", &hash_hex[24..]));
86
87    if with_keys {
88        k = Some(private_key);
89        pk = Some(secp256k1_public_key);
90    }
91
92    let wallet = Wallet {
93        keystore,
94        private_key: k,
95        public_key: pk,
96        name: name.to_string(),
97        signing_key: signing_key,
98        address: address,
99        path: path.clone(),
100    };
101
102    Ok(wallet)
103}
104
105use ethers_signers::LocalWallet;
106use ethers_signers::Signer as EthSigner;
107
108/// Main sign function
109/// Takes a message and returns a signature
110pub fn sign_message(wallet: &Wallet, message: &[u8]) -> String {
111    let mut signature = String::new();
112    async_std::task::block_on(async {
113        let wallet = hex::encode(&wallet.private_key.as_ref().unwrap())
114            .parse::<LocalWallet>()
115            .unwrap();
116
117        signature = wallet.sign_message(message).await.unwrap().to_string();
118    });
119
120    let hex_signature = signature;
121
122    return format!("{}", hex_signature);
123}