Skip to content

Commit

Permalink
Merge pull request #6 from securesecrets/wasm-10.1
Browse files Browse the repository at this point in the history
Added new deps signature verification method
  • Loading branch information
FloppyDisck authored Jun 16, 2022
2 parents f70c137 + 3a30a50 commit b078f07
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 54 deletions.
5 changes: 2 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
14 changes: 14 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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
}
89 changes: 49 additions & 40 deletions src/permit.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -29,43 +28,32 @@ pub fn bech32_to_canonical(addr: &str) -> CanonicalAddr {

impl<T: Clone + Serialize> Permit<T> {
pub fn create_signed_tx(&self, msg_type: Option<String>) -> SignedTx<T> {
SignedTx::from_permit(&self, msg_type)
SignedTx::from_permit(self, msg_type)
}

/// Returns the permit signer
pub fn validate(&self, msg_type: Option<String>) -> StdResult<PubKeyValue> {
Permit::validate_signed_tx(&self.signature, &self.create_signed_tx(msg_type))
pub fn validate<A: Api>(&self, api: &A, msg_type: Option<String>) -> StdResult<PubKeyValue> {
Permit::validate_signed_tx(api, &self.signature, &self.create_signed_tx(msg_type))
}

pub fn validate_signed_tx(signature: &PermitSignature, signed_tx: &SignedTx<T>) -> StdResult<PubKeyValue> {
pub fn validate_signed_tx<A: Api>(
api: &A,
signature: &PermitSignature,
signed_tx: &SignedTx<T>,
) -> StdResult<PubKeyValue> {
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()))
}
Expand All @@ -75,7 +63,8 @@ impl<T: Clone + Serialize> Permit<T> {
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)]
Expand Down Expand Up @@ -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),
Expand All @@ -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";
Expand Down Expand Up @@ -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())
}
}
}
22 changes: 16 additions & 6 deletions src/transaction.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -39,8 +40,17 @@ impl PubKeyValue {
CanonicalAddr(Binary(hasher.finalize().to_vec()))
}

pub fn as_humanaddr<A: Api>(&self, api: &A) -> StdResult<HumanAddr> {
api.human_address(&self.as_canonical())
pub fn as_humanaddr(&self, perfix: Option<&str>) -> StdResult<HumanAddr> {
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()))?,
))
}
}

Expand All @@ -56,7 +66,7 @@ impl<T: Clone + Serialize> TxMsg<T> {
pub fn new(params: T, msg_type: Option<String>) -> Self {
Self {
r#type: msg_type.unwrap_or("signature_proof".to_string()),
value: params.clone(),
value: params,
}
}
}
Expand Down Expand Up @@ -85,7 +95,7 @@ impl<T: Clone + Serialize> SignedTx<T> {
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()),
}
Expand Down
11 changes: 6 additions & 5 deletions src/viewing_keys.rs
Original file line number Diff line number Diff line change
@@ -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<const KEY_SIZE: usize>: ToString {
fn compare_hashes(s1: &[u8], s2: &[u8]) -> bool {
Expand Down Expand Up @@ -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();
Expand All @@ -63,4 +64,4 @@ mod viewing_key_tests {
assert!(!pwd.compare(&wrong_hashed));
assert!(!Key::compare_hashes(&hashed, &wrong_hashed));
}
}
}

0 comments on commit b078f07

Please sign in to comment.