From 975cc45196d26a9c415db7aa53038c3bebe8a9da Mon Sep 17 00:00:00 2001 From: Zero Hero <0xzerohero@gmail.com> Date: Sat, 8 Jul 2023 18:16:46 +0300 Subject: [PATCH 1/4] feat(signers): add Wallet::encrypt_keystore --- ethers-signers/src/wallet/private_key.rs | 67 ++++++++++++++++++++---- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/ethers-signers/src/wallet/private_key.rs b/ethers-signers/src/wallet/private_key.rs index e90578502..abae91ba6 100644 --- a/ethers-signers/src/wallet/private_key.rs +++ b/ethers-signers/src/wallet/private_key.rs @@ -84,6 +84,30 @@ impl Wallet { Ok(Self { signer, address, chain_id: 1 }) } + /// Creates a new encrypted JSON with the provided private key and password and stores it in the + /// provided directory. Returns a tuple (Wallet, String) of the wallet instance for the + /// keystore with its random UUID. Accepts an optional name for the keystore file. If `None`, + /// the keystore is stored as the stringified UUID. + #[cfg(not(target_arch = "wasm32"))] + pub fn encrypt_keystore( + keypath: P, + rng: &mut R, + pk: B, + password: S, + name: Option<&str>, + ) -> Result<(Self, String), WalletError> + where + P: AsRef, + R: Rng + CryptoRng, + B: AsRef<[u8]>, + S: AsRef<[u8]>, + { + let uuid = eth_keystore::encrypt_key(keypath, rng, &pk, password, name)?; + let signer = SigningKey::from_slice(pk.as_ref())?; + let address = secret_key_to_address(&signer); + Ok((Self { signer, address, chain_id: 1 }, uuid)) + } + /// Creates a new random keypair seeded with the provided RNG pub fn new(rng: &mut R) -> Self { let signer = SigningKey::random(rng); @@ -164,6 +188,7 @@ mod tests { use super::*; use crate::{LocalWallet, Signer}; use ethers_core::types::Address; + use rand::RngCore; use tempfile::tempdir; #[test] @@ -183,27 +208,49 @@ mod tests { } } - #[tokio::test] - async fn encrypted_json_keystore() { - // create and store a random encrypted JSON keystore in this directory - let dir = tempdir().unwrap(); - let mut rng = rand::thread_rng(); - let (key, uuid) = - Wallet::::new_keystore(&dir, &mut rng, "randpsswd", None).unwrap(); - - // sign a message using the above key + async fn test_encrypted_json_keystore(key: Wallet, uuid: &str, dir: &Path) { + // sign a message using the given key let message = "Some data"; let signature = key.sign_message(message).await.unwrap(); // read from the encrypted JSON keystore and decrypt it, while validating that the // signatures produced by both the keys should match - let path = Path::new(dir.path()).join(uuid); + let path = Path::new(dir).join(uuid); let key2 = Wallet::::decrypt_keystore(path.clone(), "randpsswd").unwrap(); + let signature2 = key2.sign_message(message).await.unwrap(); assert_eq!(signature, signature2); + std::fs::remove_file(&path).unwrap(); } + #[tokio::test] + async fn encrypted_json_keystore_new() { + // create and store an encrypted JSON keystore in this directory + let dir = tempdir().unwrap(); + let mut rng = rand::thread_rng(); + let (key, uuid) = + Wallet::::new_keystore(&dir, &mut rng, "randpsswd", None).unwrap(); + + test_encrypted_json_keystore(key, &uuid, dir.path()).await; + } + + #[tokio::test] + async fn encrypted_json_keystore_from_pk() { + // create and store an encrypted JSON keystore in this directory + let dir = tempdir().unwrap(); + let mut rng = rand::thread_rng(); + // Construct a 32-byte random private key. + let mut private_key = [0u8; 32]; + rng.fill_bytes(private_key.as_mut_slice()); + + let (key, uuid) = + Wallet::::encrypt_keystore(&dir, &mut rng, private_key, "randpsswd", None) + .unwrap(); + + test_encrypted_json_keystore(key, &uuid, dir.path()).await; + } + #[tokio::test] async fn signs_msg() { let message = "Some data"; From 19a88010dfb351fb851f14be3c07f5d46733d209 Mon Sep 17 00:00:00 2001 From: Zero Hero <0xzerohero@gmail.com> Date: Sun, 9 Jul 2023 11:18:31 +0300 Subject: [PATCH 2/4] chore(signers): use a non-random private key --- ethers-signers/src/wallet/private_key.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ethers-signers/src/wallet/private_key.rs b/ethers-signers/src/wallet/private_key.rs index abae91ba6..29c9989ed 100644 --- a/ethers-signers/src/wallet/private_key.rs +++ b/ethers-signers/src/wallet/private_key.rs @@ -188,7 +188,6 @@ mod tests { use super::*; use crate::{LocalWallet, Signer}; use ethers_core::types::Address; - use rand::RngCore; use tempfile::tempdir; #[test] @@ -241,8 +240,7 @@ mod tests { let dir = tempdir().unwrap(); let mut rng = rand::thread_rng(); // Construct a 32-byte random private key. - let mut private_key = [0u8; 32]; - rng.fill_bytes(private_key.as_mut_slice()); + let private_key = "6f142508b4eea641e33cb2a0161221105086a84584c74245ca463a49effea30b"; let (key, uuid) = Wallet::::encrypt_keystore(&dir, &mut rng, private_key, "randpsswd", None) From d8eb74dbc2ebda86167c2cb61024d642d397db9f Mon Sep 17 00:00:00 2001 From: Zero Hero <0xzerohero@gmail.com> Date: Sun, 9 Jul 2023 11:21:35 +0300 Subject: [PATCH 3/4] chore(signers): fix comment --- ethers-signers/src/wallet/private_key.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ethers-signers/src/wallet/private_key.rs b/ethers-signers/src/wallet/private_key.rs index 29c9989ed..7173b6cb6 100644 --- a/ethers-signers/src/wallet/private_key.rs +++ b/ethers-signers/src/wallet/private_key.rs @@ -239,7 +239,6 @@ mod tests { // create and store an encrypted JSON keystore in this directory let dir = tempdir().unwrap(); let mut rng = rand::thread_rng(); - // Construct a 32-byte random private key. let private_key = "6f142508b4eea641e33cb2a0161221105086a84584c74245ca463a49effea30b"; let (key, uuid) = From 15c5784273aca93b1724c201139b4d91f93c5806 Mon Sep 17 00:00:00 2001 From: Zero Hero <0xzerohero@gmail.com> Date: Fri, 21 Jul 2023 13:25:47 +0300 Subject: [PATCH 4/4] chore(signers): fix encrypted_json_keystore_from_pk test --- ethers-signers/src/wallet/private_key.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ethers-signers/src/wallet/private_key.rs b/ethers-signers/src/wallet/private_key.rs index 7173b6cb6..00206df6f 100644 --- a/ethers-signers/src/wallet/private_key.rs +++ b/ethers-signers/src/wallet/private_key.rs @@ -239,7 +239,10 @@ mod tests { // create and store an encrypted JSON keystore in this directory let dir = tempdir().unwrap(); let mut rng = rand::thread_rng(); - let private_key = "6f142508b4eea641e33cb2a0161221105086a84584c74245ca463a49effea30b"; + + let private_key = + hex::decode("6f142508b4eea641e33cb2a0161221105086a84584c74245ca463a49effea30b") + .unwrap(); let (key, uuid) = Wallet::::encrypt_keystore(&dir, &mut rng, private_key, "randpsswd", None)