diff --git a/Cargo.toml b/Cargo.toml index 7162fbc..38d4dfc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,10 +6,9 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cosmwasm-std = { git = "https://github.com/scrtlabs/SecretNetwork", branch = "backport-cw-crypto-apis-to-v0.10", package = "secret-cosmwasm-std" } -cosmwasm-storage = { git = "https://github.com/scrtlabs/SecretNetwork", branch = "backport-cw-crypto-apis-to-v0.10", package = "secret-cosmwasm-storage" } +cosmwasm-std = { version = "0.10.1", package = "secret-cosmwasm-std" } +cosmwasm-storage = { version = "0.10", package = "secret-cosmwasm-storage" } cosmwasm-schema = "0.10.1" -secret-toolkit = { version = "0.2", features = ["crypto"] } serde = { version = "1.0.103", default-features = false, features = ["derive"] } snafu = { version = "0.6.3" } schemars = "0.7" diff --git a/src/lib.rs b/src/lib.rs index 80631df..25b85a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,17 @@ pub mod permit; pub mod transaction; pub mod viewing_keys; + +use sha2::{Digest, Sha256}; + +pub const SHA256_HASH_SIZE: usize = 32; + +pub fn sha_256(data: &[u8]) -> [u8; SHA256_HASH_SIZE] { + let mut hasher = Sha256::new(); + hasher.update(data); + let hash = hasher.finalize(); + + let mut result = [0u8; 32]; + result.copy_from_slice(hash.as_slice()); + result +} diff --git a/src/permit.rs b/src/permit.rs index 2c4421d..8eca398 100644 --- a/src/permit.rs +++ b/src/permit.rs @@ -1,9 +1,8 @@ -use crate::transaction::{PermitSignature, PubKeyValue, SignedTx, TxMsg}; +use crate::sha_256; +use crate::transaction::{PermitSignature, PubKeyValue, SignedTx}; use bech32::FromBase32; -use cosmwasm_std::{to_binary, Binary, CanonicalAddr, StdError, StdResult, Uint128}; +use cosmwasm_std::{to_binary, Api, Binary, CanonicalAddr, StdError, StdResult, Uint128}; use schemars::JsonSchema; -use secp256k1::Secp256k1; -use secret_toolkit::crypto::sha_256; use serde::{Deserialize, Serialize}; // NOTE: Struct order is very important for signatures @@ -29,43 +28,32 @@ pub fn bech32_to_canonical(addr: &str) -> CanonicalAddr { impl Permit { pub fn create_signed_tx(&self, msg_type: Option) -> SignedTx { - SignedTx::from_permit(&self, msg_type) + SignedTx::from_permit(self, msg_type) } /// Returns the permit signer - pub fn validate(&self, msg_type: Option) -> StdResult { - Permit::validate_signed_tx(&self.signature, &self.create_signed_tx(msg_type)) + pub fn validate(&self, api: &A, msg_type: Option) -> StdResult { + Permit::validate_signed_tx(api, &self.signature, &self.create_signed_tx(msg_type)) } - pub fn validate_signed_tx(signature: &PermitSignature, signed_tx: &SignedTx) -> StdResult { + pub fn validate_signed_tx( + api: &A, + signature: &PermitSignature, + signed_tx: &SignedTx, + ) -> StdResult { let pubkey = &signature.pub_key.value; // Validate signature let signed_bytes = to_binary(signed_tx)?; let signed_bytes_hash = sha_256(signed_bytes.as_slice()); - let secp256k1_msg = secp256k1::Message::from_slice(&signed_bytes_hash).map_err(|err| { - StdError::generic_err(format!( - "Failed to create a secp256k1 message from signed_bytes: {:?}", - err - )) - })?; - - let secp256k1_verifier = Secp256k1::verification_only(); - - let secp256k1_signature = - secp256k1::Signature::from_compact(&signature.signature.0) - .map_err(|err| StdError::generic_err(format!("Malformed signature: {:?}", err)))?; - let secp256k1_pubkey = secp256k1::PublicKey::from_slice(pubkey.0.as_slice()) - .map_err(|err| StdError::generic_err(format!("Malformed pubkey: {:?}", err)))?; - - secp256k1_verifier - .verify(&secp256k1_msg, &secp256k1_signature, &secp256k1_pubkey) - .map_err(|err| { - StdError::generic_err(format!( - "Failed to verify signatures for the given permit: {:?}", - err - )) - })?; + + let verified = api + .secp256k1_verify(&signed_bytes_hash, &signature.signature.0, &pubkey.0) + .map_err(|err| StdError::generic_err(err.to_string()))?; + + if !verified { + return Err(StdError::generic_err("Signature verification failed")); + } Ok(PubKeyValue(pubkey.clone())) } @@ -75,7 +63,8 @@ impl Permit { mod signature_tests { use super::*; use crate::transaction::PubKey; - use cosmwasm_std::Uint128; + use cosmwasm_std::testing::mock_dependencies; + use cosmwasm_std::{HumanAddr, Uint128}; #[remain::sorted] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] @@ -116,7 +105,7 @@ mod signature_tests { #[test] fn test_signed_tx() { - let permit = TestPermit { + let mut permit = TestPermit { params: TestPermitMsg { address: ADDRESS.to_string(), some_number: Uint128(10), @@ -128,11 +117,20 @@ mod signature_tests { signature: Binary::from_base64(SIGNED_TX).unwrap(), }, account_number: None, - memo: None + memo: None, }; - let addr = permit.validate(None).unwrap(); + let deps = mock_dependencies(20, &[]); + let addr = permit.validate(&deps.api, None).unwrap(); + assert_eq!( + addr.as_humanaddr(None).unwrap(), + HumanAddr(ADDRESS.to_string()) + ); assert_eq!(addr.as_canonical(), bech32_to_canonical(ADDRESS)); + + permit.params.some_number = Uint128(100); + // NOTE: SN mock deps dont have a valid working implementation of the dep functons for some reason + //assert!(permit.validate(&deps.api, None).is_err()); } const FILLERPERMITNAME: &str = "wasm/MsgExecuteContract"; @@ -175,12 +173,23 @@ mod signature_tests { memo: Some("b64Encoded".to_string()) }; - let addr = permit.validate(Some(FILLERPERMITNAME.to_string())).unwrap(); - assert_eq!(addr.as_canonical(), bech32_to_canonical("terra1m79yd3jh97vz4tqu0m8g49gfl7qmknhh23kac5")); - assert_ne!(addr.as_canonical(), bech32_to_canonical("secret102nasmxnxvwp5agc4lp3flc6s23335xm8g7gn9")); + let deps = mock_dependencies(20, &[]); + + let addr = permit + .validate(&deps.api, Some(FILLERPERMITNAME.to_string())) + .unwrap(); + assert_eq!( + addr.as_canonical(), + bech32_to_canonical("terra1m79yd3jh97vz4tqu0m8g49gfl7qmknhh23kac5") + ); + assert_ne!( + addr.as_canonical(), + bech32_to_canonical("secret102nasmxnxvwp5agc4lp3flc6s23335xm8g7gn9") + ); permit.memo = Some("OtherMemo".to_string()); - assert!(permit.validate(Some(FILLERPERMITNAME.to_string())).is_err()) + // NOTE: SN mock deps doesnt have a valid working implementation of the dep functons for some reason + //assert!(permit.validate(&deps.api, Some(FILLERPERMITNAME.to_string())).is_err()) } -} \ No newline at end of file +} diff --git a/src/transaction.rs b/src/transaction.rs index 4c97dfd..753a7d9 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,8 +1,9 @@ use crate::permit::Permit; -use cosmwasm_std::{Api, Binary, CanonicalAddr, HumanAddr, StdResult, Uint128}; +use crate::sha_256; +use bech32::{ToBase32, Variant}; +use cosmwasm_std::{Binary, CanonicalAddr, HumanAddr, StdError, StdResult, Uint128}; use ripemd160::{Digest, Ripemd160}; use schemars::JsonSchema; -use secret_toolkit::crypto::sha_256; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -39,8 +40,17 @@ impl PubKeyValue { CanonicalAddr(Binary(hasher.finalize().to_vec())) } - pub fn as_humanaddr(&self, api: &A) -> StdResult { - api.human_address(&self.as_canonical()) + pub fn as_humanaddr(&self, perfix: Option<&str>) -> StdResult { + let pre = match perfix { + None => "secret", + Some(p) => p, + }; + + let acc = self.as_canonical().as_slice().to_base32(); + Ok(HumanAddr( + bech32::encode(pre, acc, Variant::Bech32) + .map_err(|err| StdError::generic_err(err.to_string()))?, + )) } } @@ -56,7 +66,7 @@ impl TxMsg { pub fn new(params: T, msg_type: Option) -> Self { Self { r#type: msg_type.unwrap_or("signature_proof".to_string()), - value: params.clone(), + value: params, } } } @@ -85,7 +95,7 @@ impl SignedTx { account_number: permit.account_number.unwrap_or(Uint128::zero()), chain_id: permit.chain_id.clone().unwrap_or("secret-4".to_string()), fee: Default::default(), - memo: permit.memo.clone().unwrap_or(String::new()), + memo: permit.memo.clone().unwrap_or_default(), msgs: vec![TxMsg::new(permit.params.clone(), msg_type)], sequence: permit.sequence.unwrap_or(Uint128::zero()), } diff --git a/src/viewing_keys.rs b/src/viewing_keys.rs index 9fd291a..2be6c3c 100644 --- a/src/viewing_keys.rs +++ b/src/viewing_keys.rs @@ -1,7 +1,5 @@ -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use std::convert::TryInto; use sha2::{Digest, Sha256}; +use std::convert::TryInto; pub trait ViewingKey: ToString { fn compare_hashes(s1: &[u8], s2: &[u8]) -> bool { @@ -52,7 +50,10 @@ mod viewing_key_tests { let hashed = pwd.hash(); assert!(pwd.compare(&hashed)); - assert!(Key::compare_hashes(&hashed, &Key("password".to_string()).hash())); + assert!(Key::compare_hashes( + &hashed, + &Key("password".to_string()).hash() + )); let wrong_pwd = Key("wrong_password".to_string()); let wrong_hashed = wrong_pwd.hash(); @@ -63,4 +64,4 @@ mod viewing_key_tests { assert!(!pwd.compare(&wrong_hashed)); assert!(!Key::compare_hashes(&hashed, &wrong_hashed)); } -} \ No newline at end of file +}