From b86d53ce8be21e7d2d390b2dbfcb8679ee54b4be Mon Sep 17 00:00:00 2001 From: Cesar <142530682+cr-fuel@users.noreply.github.com> Date: Wed, 27 Sep 2023 16:54:31 -0400 Subject: [PATCH] WIP: #4318 `forc-crypto` plugin exposing a CLI for common-use cryptographic operations Supported algorithms: * [x] keccak256 * [x] sha256 * [ ] ecrecover * [x] bech32-to-hex * [x] hex-to-bech32 --- Cargo.lock | 94 +++++++++++++++++------ Cargo.toml | 8 +- forc-plugins/forc-crypto/Cargo.toml | 32 ++++++++ forc-plugins/forc-crypto/src/address.rs | 24 ++++++ forc-plugins/forc-crypto/src/content.rs | 55 +++++++++++++ forc-plugins/forc-crypto/src/ecrecover.rs | 7 ++ forc-plugins/forc-crypto/src/keccak256.rs | 7 ++ forc-plugins/forc-crypto/src/main.rs | 58 ++++++++++++++ forc-plugins/forc-crypto/src/sha256.rs | 7 ++ 9 files changed, 261 insertions(+), 31 deletions(-) create mode 100644 forc-plugins/forc-crypto/Cargo.toml create mode 100644 forc-plugins/forc-crypto/src/address.rs create mode 100644 forc-plugins/forc-crypto/src/content.rs create mode 100644 forc-plugins/forc-crypto/src/ecrecover.rs create mode 100644 forc-plugins/forc-crypto/src/keccak256.rs create mode 100644 forc-plugins/forc-crypto/src/main.rs create mode 100644 forc-plugins/forc-crypto/src/sha256.rs diff --git a/Cargo.lock b/Cargo.lock index 871c6d56cda..4ffba580261 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -468,7 +468,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" dependencies = [ - "sha2 0.10.7", + "sha2 0.10.8", "tinyvec", ] @@ -728,7 +728,7 @@ dependencies = [ "hmac", "k256", "serde", - "sha2 0.10.7", + "sha2 0.10.8", "thiserror", ] @@ -744,7 +744,7 @@ dependencies = [ "once_cell", "pbkdf2 0.12.2", "rand", - "sha2 0.10.7", + "sha2 0.10.8", "thiserror", ] @@ -763,7 +763,7 @@ dependencies = [ "ripemd", "serde", "serde_derive", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "thiserror", ] @@ -1470,7 +1470,7 @@ checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ "curve25519-dalek", "ed25519", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -1606,7 +1606,7 @@ dependencies = [ "scrypt", "serde", "serde_json", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "thiserror", "uuid", @@ -1849,6 +1849,31 @@ dependencies = [ "tracing", ] +[[package]] +name = "forc-crypto" +version = "0.46.0" +dependencies = [ + "anyhow", + "async-trait", + "clap 3.2.25", + "forc-tracing", + "forc-tx", + "fuel-crypto", + "fuels-core", + "futures", + "hex", + "rand", + "rpassword", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3", + "strum 0.25.0", + "strum_macros 0.25.2", + "tokio", + "tracing", +] + [[package]] name = "forc-doc" version = "0.46.1" @@ -2107,7 +2132,7 @@ checksum = "77ac38b692cf1d259c4576e96969ddc1b21880f3059744a730d1677b6f9fd4df" dependencies = [ "bitflags 1.3.2", "serde", - "strum", + "strum 0.24.1", ] [[package]] @@ -2198,7 +2223,7 @@ dependencies = [ "rand", "secp256k1 0.26.0", "serde", - "sha2 0.10.7", + "sha2 0.10.8", "zeroize", ] @@ -2283,7 +2308,7 @@ dependencies = [ "fuel-storage", "hashbrown 0.13.2", "hex", - "sha2 0.10.7", + "sha2 0.10.8", "thiserror", ] @@ -2309,7 +2334,7 @@ dependencies = [ "rand", "serde", "serde_json", - "strum", + "strum 0.24.1", "strum_macros 0.24.3", ] @@ -2386,7 +2411,7 @@ dependencies = [ "itertools", "rand", "serde", - "sha2 0.10.7", + "sha2 0.10.8", "tai64", "thiserror", "tokio", @@ -2430,8 +2455,8 @@ dependencies = [ "regex", "serde", "serde_json", - "sha2 0.10.7", - "strum", + "sha2 0.10.8", + "strum 0.24.1", "strum_macros 0.24.3", "thiserror", "uint", @@ -2476,8 +2501,8 @@ dependencies = [ "regex", "serde", "serde_json", - "sha2 0.10.7", - "strum", + "sha2 0.10.8", + "strum 0.24.1", "strum_macros 0.24.3", "thiserror", "tokio", @@ -3356,7 +3381,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "once_cell", - "sha2 0.10.7", + "sha2 0.10.8", "signature", ] @@ -3784,7 +3809,7 @@ dependencies = [ "core2", "digest 0.10.7", "multihash-derive", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "unsigned-varint", ] @@ -4142,7 +4167,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -4328,7 +4353,7 @@ checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" dependencies = [ "once_cell", "pest", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -4916,7 +4941,7 @@ dependencies = [ "primitive-types", "ripemd", "secp256k1 0.24.3", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "substrate-bn", ] @@ -5224,7 +5249,7 @@ dependencies = [ "hmac", "pbkdf2 0.11.0", "salsa20", - "sha2 0.10.7", + "sha2 0.10.8", ] [[package]] @@ -5486,9 +5511,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -5728,6 +5753,12 @@ dependencies = [ "strum_macros 0.24.3", ] +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + [[package]] name = "strum_macros" version = "0.21.1" @@ -5753,6 +5784,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.33", +] + [[package]] name = "substrate-bn" version = "0.6.0" @@ -5812,7 +5856,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.9.9", - "strum", + "strum 0.24.1", "sway-ast", "sway-error", "sway-ir", @@ -6313,7 +6357,7 @@ dependencies = [ "pbkdf2 0.11.0", "rand", "rustc-hash", - "sha2 0.10.7", + "sha2 0.10.8", "thiserror", "unicode-normalization", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 667446d510a..c033c921236 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "forc", "forc-pkg", "forc-plugins/forc-client", + "forc-plugins/forc-crypto", "forc-plugins/forc-doc", "forc-plugins/forc-fmt", "forc-plugins/forc-lsp", @@ -24,11 +25,7 @@ members = [ "swayfmt", "test", ] -exclude = [ - "examples/*", - "swayfmt/test_macros", - "forc-test/test_data" -] +exclude = ["examples/*", "swayfmt/test_macros", "forc-test/test_data"] [workspace.dependencies] # Dependencies from the `fuel-core` repository: @@ -54,4 +51,3 @@ authors = ["Fuel Labs "] homepage = "https://fuel.network/" license = "Apache-2.0" repository = "https://github.com/FuelLabs/sway" - diff --git a/forc-plugins/forc-crypto/Cargo.toml b/forc-plugins/forc-crypto/Cargo.toml new file mode 100644 index 00000000000..fea90513ff6 --- /dev/null +++ b/forc-plugins/forc-crypto/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "forc-crypto" +version = "0.46.0" +description = "A `forc` plugin for interacting with a fuel's crypto library." +authors.workspace = true +edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.75" +async-trait = "0.1.58" +clap = { version = "3", features = ["derive", "env"] } +forc-tracing = { version = "0.46.0", path = "../../forc-tracing" } +fuel-crypto = { workspace = true } +fuels-core = { workspace = true } +forc-tx = { version = "0.46.0", path = "../forc-tx" } +futures = "0.3" +hex = "0.4.3" +rand = "0.8" +rpassword = "7.2" +serde = "1.0" +serde_json = "1" +sha2 = "0.10.8" +sha3 = "0.10.8" +strum = "0.25.0" +strum_macros = "0.25.2" +tokio = { version = "1.8", features = ["macros", "rt-multi-thread", "process"] } +tracing = "0.1" diff --git a/forc-plugins/forc-crypto/src/address.rs b/forc-plugins/forc-crypto/src/address.rs new file mode 100644 index 00000000000..3709082aea5 --- /dev/null +++ b/forc-plugins/forc-crypto/src/address.rs @@ -0,0 +1,24 @@ +use std::str::FromStr; + +use fuel_crypto::fuel_types::Address; +use fuels_core::types::bech32::Bech32Address; + +pub fn dump_address>(data: T) -> String { + let bytes_32: Result<[u8; 32], _> = data.as_ref().try_into(); + let (bech32, addr) = if let Ok(bytes) = bytes_32 { + let addr = Address::from(bytes); + (Bech32Address::from(addr), addr) + } else if let Ok(string) = String::from_utf8(data.as_ref().to_owned()) { + if let Ok(bech32) = Bech32Address::from_str(&string) { + (bech32.clone(), Address::from(bech32)) + } else if let Ok(addr) = Address::from_str(&string) { + (Bech32Address::from(addr), addr) + } else { + panic!("{} cannot be parsed to a valid address", string); + } + } else { + panic!("{} cannot be parsed to a valid address", hex::encode(data)); + }; + + format!("Bench32: {}\nAddress: 0x{}\n", bech32, addr,) +} diff --git a/forc-plugins/forc-crypto/src/content.rs b/forc-plugins/forc-crypto/src/content.rs new file mode 100644 index 00000000000..e32aed93227 --- /dev/null +++ b/forc-plugins/forc-crypto/src/content.rs @@ -0,0 +1,55 @@ +use std::str::FromStr; +use std::{ + fs::read, + io::{self, Read}, +}; + +#[derive(Debug, PartialEq)] +pub enum Content { + Path(std::path::PathBuf, Vec), + Raw(Vec), +} + +impl Content { + pub fn from_hex_or_(input: Vec) -> Vec { + if let Ok(text) = String::from_utf8(input.clone()) { + if let Some(text) = text.strip_prefix("0x") { + if let Ok(bin) = hex::decode(text) { + return bin; + } + } + text.as_bytes().to_vec() + } else { + input + } + } +} + +impl FromStr for Content { + type Err = anyhow::Error; + + fn from_str(s: &str) -> std::result::Result { + if s == "-" { + let mut buffer = vec![]; + let _ = io::stdin().lock().read_to_end(&mut buffer)?; + Ok(Content::Raw(Self::from_hex_or_(buffer))) + } else { + let path = std::path::PathBuf::from(s); + if path.exists() { + let content = read(&path).unwrap(); + Ok(Content::Path(path, Self::from_hex_or_(content))) + } else { + Ok(Content::Raw(Self::from_hex_or_(s.as_bytes().to_vec()))) + } + } + } +} + +impl AsRef<[u8]> for Content { + fn as_ref(&self) -> &[u8] { + match self { + Content::Path(_, content) => content.as_ref(), + Content::Raw(raw) => raw.as_ref(), + } + } +} diff --git a/forc-plugins/forc-crypto/src/ecrecover.rs b/forc-plugins/forc-crypto/src/ecrecover.rs new file mode 100644 index 00000000000..1ddabbfa0d6 --- /dev/null +++ b/forc-plugins/forc-crypto/src/ecrecover.rs @@ -0,0 +1,7 @@ +use fuel_crypto::Signature; + +pub fn ecrecover>(data: T) -> Vec { + let bytes = <[u8; Signature::LEN]>::try_from(data.as_ref()).expect("invalid input"); + let _ = Signature::from_bytes(bytes); + todo!() +} diff --git a/forc-plugins/forc-crypto/src/keccak256.rs b/forc-plugins/forc-crypto/src/keccak256.rs new file mode 100644 index 00000000000..1502417e052 --- /dev/null +++ b/forc-plugins/forc-crypto/src/keccak256.rs @@ -0,0 +1,7 @@ +use sha3::{Digest, Keccak256}; + +pub fn hash>(data: T) -> Vec { + let mut hasher = Keccak256::new(); + hasher.update(data); + hasher.finalize().to_vec() +} diff --git a/forc-plugins/forc-crypto/src/main.rs b/forc-plugins/forc-crypto/src/main.rs new file mode 100644 index 00000000000..4359c1e1686 --- /dev/null +++ b/forc-plugins/forc-crypto/src/main.rs @@ -0,0 +1,58 @@ +//! A `forc` plugin for converting a given string o path to their hash + +use anyhow::Result; +use clap::Parser; +use forc_tracing::{init_tracing_subscriber, println_error}; +use std::default::Default; +use strum_macros::EnumString; + +mod address; +mod content; +mod ecrecover; +mod keccak256; +mod sha256; + +#[derive(Parser, Debug, PartialEq, EnumString)] +#[clap(rename_all = "verbatim")] +pub enum Algorithm { + Keccak256, + Sha256, + EcRecover, + Address, +} + +#[derive(Debug, Parser)] +#[clap( + name = "forc-crypto", + about = "Forc plugin for hashing arbitrary data.", + version +)] +pub struct App { + #[clap(rename_all = "verbatim")] + pub algorithm: Algorithm, + /// Path to the project, if not specified, current working directory will be used. + pub content: content::Content, +} + +fn main() { + init_tracing_subscriber(Default::default()); + if let Err(err) = run() { + println_error("Formatting skipped due to error."); + println_error(&format!("{}", err)); + std::process::exit(1); + } +} + +fn run() -> Result<()> { + let app = App::parse(); + + let content = match app.algorithm { + Algorithm::Keccak256 => hex::encode(keccak256::hash(app.content)), + Algorithm::Sha256 => hex::encode(sha256::hash(app.content)), + Algorithm::EcRecover => hex::encode(ecrecover::ecrecover(app.content)), + Algorithm::Address => address::dump_address(app.content), + }; + + print!("{}", content); + Ok(()) +} diff --git a/forc-plugins/forc-crypto/src/sha256.rs b/forc-plugins/forc-crypto/src/sha256.rs new file mode 100644 index 00000000000..a0a21029b7d --- /dev/null +++ b/forc-plugins/forc-crypto/src/sha256.rs @@ -0,0 +1,7 @@ +use sha2::{Digest, Sha256}; + +pub fn hash>(data: T) -> Vec { + let mut hasher = Sha256::new(); + hasher.update(data); + hasher.finalize().to_vec() +}