From a8d76e337916729b5c235c2f3aa495b6c235b5a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20D=2E=20Rodas?= Date: Mon, 22 Jan 2024 23:14:29 -0300 Subject: [PATCH] Add support recover key (#5419) ## Description Add recover-public-key to forc-crypto This function is ported from https://github.com/FuelLabs/forc-wallet/pull/152 This PR depends on #5388 ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --- forc-plugins/forc-crypto/src/args.rs | 40 +++++------ .../forc-crypto/src/keys/get_public_key.rs | 67 +++++++++++++++++++ .../forc-crypto/src/{keygen => keys}/mod.rs | 1 + .../src/{keygen => keys}/new_key.rs | 2 - .../src/{keygen => keys}/parse_secret.rs | 2 - forc-plugins/forc-crypto/src/main.rs | 19 +++--- forc-plugins/forc-debug/README.md | 0 forc-plugins/forc-debug/docs/walkthrough.md | 0 .../forc-debug/examples/client_usage.rs | 0 .../forc-debug/examples/example_tx.json | 0 forc-plugins/forc-debug/src/lib.rs | 0 forc-plugins/forc-debug/src/names.rs | 0 .../forc-debug/tests/cli_integration.rs | 0 13 files changed, 100 insertions(+), 31 deletions(-) create mode 100644 forc-plugins/forc-crypto/src/keys/get_public_key.rs rename forc-plugins/forc-crypto/src/{keygen => keys}/mod.rs (94%) rename forc-plugins/forc-crypto/src/{keygen => keys}/new_key.rs (95%) rename forc-plugins/forc-crypto/src/{keygen => keys}/parse_secret.rs (95%) mode change 100755 => 100644 forc-plugins/forc-debug/README.md mode change 100755 => 100644 forc-plugins/forc-debug/docs/walkthrough.md mode change 100755 => 100644 forc-plugins/forc-debug/examples/client_usage.rs mode change 100755 => 100644 forc-plugins/forc-debug/examples/example_tx.json mode change 100755 => 100644 forc-plugins/forc-debug/src/lib.rs mode change 100755 => 100644 forc-plugins/forc-debug/src/names.rs mode change 100755 => 100644 forc-plugins/forc-debug/tests/cli_integration.rs diff --git a/forc-plugins/forc-crypto/src/args.rs b/forc-plugins/forc-crypto/src/args.rs index 233e86f7c62..71872bca9ac 100644 --- a/forc-plugins/forc-crypto/src/args.rs +++ b/forc-plugins/forc-crypto/src/args.rs @@ -71,31 +71,33 @@ fn read_as_binary(content: &Option) -> Vec { .unwrap_or_default() } +/// Reads the arg and returns a vector of bytes +/// +/// These are the rules +/// 1. If None, stdin is read. +/// 2. If it's a String and it happens to be a file path, its content will be returned +/// 3. If it's a String and it is "-", stdin is read +/// 4. If the string starts with "0x", it will be treated as a hex string. Only +/// fully valid hex strings are accepted. +/// 5. Otherwise the String will be converted to a vector of bytes +pub fn read_content_filepath_or_stdin(arg: Option) -> Vec { + match checked_read_file(&arg) { + Some(bytes) => bytes, + None => match checked_read_stdin(&arg, io::stdin().lock()) { + Some(bytes) => bytes, + None => read_as_binary(&arg), + }, + } +} + /// The HashArgs takes no or a single argument, it can be either a string or a /// path to a file. It can be consumed and converted to a Vec using the From /// trait. /// -/// The usage is as follows: -/// 1. Zero or one argument is accepted -/// 2. If no argument is passed, `stdin` is being read -/// 3. The argument will be checked to be a file path, if it is the content -/// will be ded from the file -/// 4. Otherwise, the content is treated as a string -/// 5. If the string is "-", `stdin` is being read -/// 6. If the string starts with "0x", it will be treated as a hex string. Only -/// fully valid hex strings are accepted. -/// 7. Any other string, or any malformed hex string will be treated as a -/// vector of bytes +/// This is a wrapper around `read_content_filepath_or_stdin` impl From for Vec { fn from(value: HashArgs) -> Self { - let arg = value.content_or_filepath; - match checked_read_file(&arg) { - Some(bytes) => bytes, - None => match checked_read_stdin(&arg, io::stdin().lock()) { - Some(bytes) => bytes, - None => read_as_binary(&arg), - }, - } + read_content_filepath_or_stdin(value.content_or_filepath) } } diff --git a/forc-plugins/forc-crypto/src/keys/get_public_key.rs b/forc-plugins/forc-crypto/src/keys/get_public_key.rs new file mode 100644 index 00000000000..c02dda04a46 --- /dev/null +++ b/forc-plugins/forc-crypto/src/keys/get_public_key.rs @@ -0,0 +1,67 @@ +use crate::args::read_content_filepath_or_stdin; +use anyhow::Result; +use fuel_crypto::{fuel_types::Address, Message, Signature}; +use fuels_core::types::bech32::Bech32Address; +use serde_json::json; + +forc_util::cli_examples! { + [ Get the public key from a message and its signature => crypto r#"get-public-key \ + 0x1eff08081394b72239a0cf7ff6b499213dcb7a338bedbd75d072d504588ef27a1f74d5ceb2f111ec02ede097fb09ed00aa9867922ed39299dae0b1afc0fa8661 \ + "This is a message that is signed""# ] +} + +/// Parse a secret key to view the associated public key +#[derive(Debug, clap::Args)] +#[clap( + author, + version, + about = "Get the public key from a message and its signature", + after_long_help = help(), +)] +pub struct Arg { + /// A private key in hex format + signature: Signature, + /// A message + message: Option, +} + +pub fn handler(arg: Arg) -> Result { + let message = Message::new(read_content_filepath_or_stdin(arg.message)); + let public_key = Signature::recover(&arg.signature, &message)?; + + let bytes = *public_key.hash(); + + let bech32 = Bech32Address::from(Address::from(bytes)); + let addr = Address::from(bytes); + + Ok(json!({ + "PublicKey": public_key.to_string(), + "Bech32": bech32.to_string(), + "Address": addr.to_string(), + })) +} + +#[cfg(test)] +mod test { + use std::str::FromStr; + + use super::*; + + #[test] + fn expect_output() { + let arg = Arg { + signature: Signature::from_str("0x1eff08081394b72239a0cf7ff6b499213dcb7a338bedbd75d072d504588ef27a1f74d5ceb2f111ec02ede097fb09ed00aa9867922ed39299dae0b1afc0fa8661").unwrap(), + message: Some("This is a message that is signed".to_string()), + }; + let json = handler(arg).unwrap(); + assert_eq!( + "fuel1fmmfhjapeak3knq96arrvttwrtmzghe0w9gx79gkcl2jhaweakdqfqhzdr", + json.as_object() + .unwrap() + .get("Bech32") + .unwrap() + .as_str() + .unwrap(), + ) + } +} diff --git a/forc-plugins/forc-crypto/src/keygen/mod.rs b/forc-plugins/forc-crypto/src/keys/mod.rs similarity index 94% rename from forc-plugins/forc-crypto/src/keygen/mod.rs rename to forc-plugins/forc-crypto/src/keys/mod.rs index 6958367dc3d..9741e32623c 100644 --- a/forc-plugins/forc-crypto/src/keygen/mod.rs +++ b/forc-plugins/forc-crypto/src/keys/mod.rs @@ -1,5 +1,6 @@ use clap::ValueEnum; +pub mod get_public_key; pub mod new_key; pub mod parse_secret; diff --git a/forc-plugins/forc-crypto/src/keygen/new_key.rs b/forc-plugins/forc-crypto/src/keys/new_key.rs similarity index 95% rename from forc-plugins/forc-crypto/src/keygen/new_key.rs rename to forc-plugins/forc-crypto/src/keys/new_key.rs index d84ff450eb2..449ee8884f5 100644 --- a/forc-plugins/forc-crypto/src/keygen/new_key.rs +++ b/forc-plugins/forc-crypto/src/keys/new_key.rs @@ -1,5 +1,3 @@ -//! This file will be hosted here until -//! https://github.com/FuelLabs/sway/issues/5170 is fixed use super::KeyType; use anyhow::Result; use fuel_core_types::{ diff --git a/forc-plugins/forc-crypto/src/keygen/parse_secret.rs b/forc-plugins/forc-crypto/src/keys/parse_secret.rs similarity index 95% rename from forc-plugins/forc-crypto/src/keygen/parse_secret.rs rename to forc-plugins/forc-crypto/src/keys/parse_secret.rs index 309af4fae2a..82f2cbf8c1b 100644 --- a/forc-plugins/forc-crypto/src/keygen/parse_secret.rs +++ b/forc-plugins/forc-crypto/src/keys/parse_secret.rs @@ -1,5 +1,3 @@ -//! This file will be hosted here until -//! https://github.com/FuelLabs/sway/issues/5170 is fixed use super::KeyType; use anyhow::Result; use fuel_core_types::{fuel_crypto::SecretKey, fuel_tx::Input}; diff --git a/forc-plugins/forc-crypto/src/main.rs b/forc-plugins/forc-crypto/src/main.rs index 9a3dd4f3858..b872264d4f6 100644 --- a/forc-plugins/forc-crypto/src/main.rs +++ b/forc-plugins/forc-crypto/src/main.rs @@ -13,7 +13,7 @@ use termion::screen::IntoAlternateScreen; mod address; mod args; mod keccak256; -mod keygen; +mod keys; mod sha256; const ABOUT: &str = "Forc plugin for hashing arbitrary data."; @@ -21,11 +21,12 @@ const ABOUT: &str = "Forc plugin for hashing arbitrary data."; fn help() -> &'static str { Box::leak( format!( - "EXAMPLES:\n{}{}{}{}", + "EXAMPLES:\n{}{}{}{}{}", args::examples(), address::examples(), - keygen::new_key::examples(), - keygen::parse_secret::examples(), + keys::new_key::examples(), + keys::parse_secret::examples(), + keys::get_public_key::examples(), ) .into_boxed_str(), ) @@ -42,8 +43,9 @@ pub enum Command { Keccak256(args::HashArgs), Sha256(args::HashArgs), Address(address::Args), - NewKey(keygen::new_key::Arg), - ParseSecret(keygen::parse_secret::Arg), + GetPublicKey(keys::get_public_key::Arg), + NewKey(keys::new_key::Arg), + ParseSecret(keys::parse_secret::Arg), } fn main() { @@ -58,10 +60,11 @@ fn run() -> Result<()> { let app = Command::parse(); let content = match app { Command::Keccak256(arg) => keccak256::hash(arg)?, + Command::GetPublicKey(arg) => keys::get_public_key::handler(arg)?, Command::Sha256(arg) => sha256::hash(arg)?, Command::Address(arg) => address::dump_address(arg.address)?, - Command::NewKey(arg) => keygen::new_key::handler(arg)?, - Command::ParseSecret(arg) => keygen::parse_secret::handler(arg)?, + Command::NewKey(arg) => keys::new_key::handler(arg)?, + Command::ParseSecret(arg) => keys::parse_secret::handler(arg)?, }; display_output(content) diff --git a/forc-plugins/forc-debug/README.md b/forc-plugins/forc-debug/README.md old mode 100755 new mode 100644 diff --git a/forc-plugins/forc-debug/docs/walkthrough.md b/forc-plugins/forc-debug/docs/walkthrough.md old mode 100755 new mode 100644 diff --git a/forc-plugins/forc-debug/examples/client_usage.rs b/forc-plugins/forc-debug/examples/client_usage.rs old mode 100755 new mode 100644 diff --git a/forc-plugins/forc-debug/examples/example_tx.json b/forc-plugins/forc-debug/examples/example_tx.json old mode 100755 new mode 100644 diff --git a/forc-plugins/forc-debug/src/lib.rs b/forc-plugins/forc-debug/src/lib.rs old mode 100755 new mode 100644 diff --git a/forc-plugins/forc-debug/src/names.rs b/forc-plugins/forc-debug/src/names.rs old mode 100755 new mode 100644 diff --git a/forc-plugins/forc-debug/tests/cli_integration.rs b/forc-plugins/forc-debug/tests/cli_integration.rs old mode 100755 new mode 100644