diff --git a/Cargo.lock b/Cargo.lock index 1231357..7b29b8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1814,7 +1814,7 @@ dependencies = [ [[package]] name = "terra-rust-api" -version = "1.2.17" +version = "1.2.18" dependencies = [ "anyhow", "base64", diff --git a/src/keys.rs b/src/keys.rs index ee18ab2..43ad36b 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -1,7 +1,7 @@ use anyhow::Result; use clap::{Parser, Subcommand}; use std::io::{self, BufRead}; -use terra_rust_api::PrivateKey; +use terra_rust_api::{PrivateKey, Signature}; use secp256k1::Secp256k1; use terra_rust_wallet::Wallet; @@ -42,6 +42,27 @@ pub enum KeysEnum { #[clap(name = "name", help = "the key with this name.")] name: String, }, + /// Sign a arbitrary string + /// + Sign { + #[clap(name = "signer", help = "the signer to sign the message.")] + signer: String, + #[clap(name = "message", help = "the message to sign.")] + message: String, + }, + /// Sign a arbitrary string + /// + Verify { + #[clap( + name = "public_key", + help = "the public key raw value (just the hex string)." + )] + public_key: String, + #[clap(name = "signature", help = "the signature")] + signature: String, + #[clap(name = "message", help = "the message to verify.")] + message: String, + }, /// List keys in the wallet List, } @@ -120,6 +141,24 @@ impl KeysCommand { let keys = wallet.list()?; println!("{:#?}", keys); } + KeysEnum::Sign { signer, message } => { + let secp = Secp256k1::new(); + + let from_key = wallet.get_private_key(&secp, &signer, seed)?; + // let signature = from_key.sign(&secp, &cli.message)?; + let signature = from_key.sign(&secp, &message)?; + println!("Signature: {}", signature.signature); + println!("Public Key: {}", signature.pub_key.value); + } + KeysEnum::Verify { + public_key, + signature, + message, + } => { + let secp = Secp256k1::new(); + Signature::verify(&secp, &public_key, &signature, &message)?; + println!("OK"); + } } Ok(()) } diff --git a/terra-rust-api/Cargo.toml b/terra-rust-api/Cargo.toml index e9d445e..b95bf78 100644 --- a/terra-rust-api/Cargo.toml +++ b/terra-rust-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "terra-rust-api" -version = "1.2.17" +version = "1.2.18" authors = ["PFC-Validator "] edition = "2018" license = "Apache-2.0" diff --git a/terra-rust-api/Changelog.md b/terra-rust-api/Changelog.md index 11ebd97..b6326ea 100644 --- a/terra-rust-api/Changelog.md +++ b/terra-rust-api/Changelog.md @@ -2,6 +2,8 @@ ## Debt ### support Variant::Bech32m in keygen? (https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) ## 1.2 +### 1.2.18 - 8-Mar-22 +* Add Signature::verify API call (just a wrapper to secp) ### 1.2.17 -25-Feb-22 * validators_at_height() function * RPCValidatorUpdate / power is field is not used at the moment.. so just ignore it diff --git a/terra-rust-api/src/errors.rs b/terra-rust-api/src/errors.rs index e7128f5..ef68d83 100644 --- a/terra-rust-api/src/errors.rs +++ b/terra-rust-api/src/errors.rs @@ -17,6 +17,8 @@ pub enum TerraRustAPIError { #[error(transparent)] ED25519(#[from] ::ed25519_dalek::ed25519::Error), #[error(transparent)] + DecodeError(#[from] ::base64::DecodeError), + #[error(transparent)] SubtleError(#[from] ::subtle_encoding::Error), #[error(transparent)] UTF8Error(#[from] FromUtf8Error), diff --git a/terra-rust-api/src/keys.rs b/terra-rust-api/src/keys.rs index 664c1f3..8deb4f8 100644 --- a/terra-rust-api/src/keys.rs +++ b/terra-rust-api/src/keys.rs @@ -2,7 +2,9 @@ // pub mod mnemonic_key; mod private; mod public; +mod signature; pub use private::PrivateKey; pub use public::PublicKey; +pub use signature::Signature; diff --git a/terra-rust-api/src/keys/private.rs b/terra-rust-api/src/keys/private.rs index 8ac6f4a..ba9e0e4 100644 --- a/terra-rust-api/src/keys/private.rs +++ b/terra-rust-api/src/keys/private.rs @@ -127,6 +127,7 @@ impl PrivateKey { blob: &str, ) -> Result { let pub_k = &self.private_key.private_key.public_key(secp); + let priv_k = self.private_key.private_key.key; let mut sha = Sha256::new(); let mut sha_result: [u8; 32] = [0; 32]; diff --git a/terra-rust-api/src/keys/public.rs b/terra-rust-api/src/keys/public.rs index 00d3dec..f902d02 100644 --- a/terra-rust-api/src/keys/public.rs +++ b/terra-rust-api/src/keys/public.rs @@ -4,6 +4,7 @@ use bitcoin::bech32::{decode, encode, u5, FromBase32, ToBase32, Variant}; use crypto::digest::Digest; use crypto::ripemd160::Ripemd160; use crypto::sha2::Sha256; + pub use ed25519_dalek::PublicKey as Ed25519; use serde::{Deserialize, Serialize}; static BECH32_PUBKEY_DATA_PREFIX_SECP256K1: [u8; 5] = [0xeb, 0x5a, 0xe9, 0x87, 0x21]; // "eb5ae98721"; @@ -383,6 +384,7 @@ mod tst { use dotenv::dotenv; #[allow(unused_imports)] use env_logger; + #[test] pub fn tst_conv() -> anyhow::Result<()> { let pub_key = PublicKey::from_account("terra1jnzv225hwl3uxc5wtnlgr8mwy6nlt0vztv3qqm")?; diff --git a/terra-rust-api/src/keys/signature.rs b/terra-rust-api/src/keys/signature.rs new file mode 100644 index 0000000..8c0208a --- /dev/null +++ b/terra-rust-api/src/keys/signature.rs @@ -0,0 +1,47 @@ +use crate::errors::TerraRustAPIError; +use crypto::sha2::Sha256; +use secp256k1::Message; +use secp256k1::Secp256k1; + +use crypto::digest::Digest; + +pub struct Signature {} +impl Signature { + pub fn verify( + secp: &Secp256k1, + pub_key: &str, + signature: &str, + blob: &str, + ) -> Result<(), TerraRustAPIError> { + let public = base64::decode(pub_key)?; + let sig = base64::decode(signature)?; + let pk = secp256k1::PublicKey::from_slice(public.as_slice())?; + let mut sha = Sha256::new(); + let mut sha_result: [u8; 32] = [0; 32]; + sha.input_str(blob); + sha.result(&mut sha_result); + + let message: Message = Message::from_slice(&sha_result)?; + let secp_sig = secp256k1::Signature::from_compact(sig.as_slice())?; + secp.verify(&message, &secp_sig, &pk)?; + Ok(()) + } +} +#[cfg(test)] +mod tst { + use super::*; + #[allow(unused_imports)] + use dotenv::dotenv; + #[allow(unused_imports)] + use env_logger; + #[test] + pub fn test_verify() -> anyhow::Result<()> { + let secp = Secp256k1::new(); + + let message = r#"{"account_number":"45","chain_id":"columbus-3-testnet","fee":{"amount":[{"amount":"698","denom":"uluna"}],"gas":"46467"},"memo":"","msgs":[{"type":"bank/MsgSend","value":{"amount":[{"amount":"100000000","denom":"uluna"}],"from_address":"terra1n3g37dsdlv7ryqftlkef8mhgqj4ny7p8v78lg7","to_address":"terra1wg2mlrxdmnnkkykgqg4znky86nyrtc45q336yv"}}],"sequence":"0"}"#; + let signature = "FJKAXRxNB5ruqukhVqZf3S/muZEUmZD10fVmWycdVIxVWiCXXFsUy2VY2jINEOUGNwfrqEZsT2dUfAvWj8obLg=="; + let pub_key = "AiMzHaA2bvnDXfHzkjMM+vkSE/p0ymBtAFKUnUtQAeXe"; + Signature::verify(&secp, pub_key, signature, message)?; + Ok(()) + } +} diff --git a/terra-rust-api/src/lib.rs b/terra-rust-api/src/lib.rs index 779c743..5d9c60f 100644 --- a/terra-rust-api/src/lib.rs +++ b/terra-rust-api/src/lib.rs @@ -96,7 +96,7 @@ pub use addressbook::AddressBook; pub use client::lcd_types::{LCDResult, LCDResultVec, LCDTypeValue}; pub use client::{auth_types, client_types, core_types, staking_types, tendermint_types}; pub use client::{GasOptions, Terra}; -pub use keys::{PrivateKey, PublicKey}; +pub use keys::{PrivateKey, PublicKey, Signature}; pub use messages::bank; pub use messages::wasm::MsgExecuteContract; pub use messages::Message;