bvs_library/testing/
account.rs1use base64::{engine::general_purpose, Engine as _};
2use bech32::{self, ToBase32, Variant};
3use cosmwasm_std::Addr;
4use ripemd::Ripemd160;
5use secp256k1::{ecdsa::Signature, Message, PublicKey, Secp256k1, SecretKey};
6use sha2::{Digest, Sha256};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
9pub struct Account {
10 secret_key: SecretKey,
11 pub public_key: PublicKey,
12 pub address: Addr,
13}
14
15impl Account {
16 pub fn new(s: impl Into<String>) -> Self {
18 let s = s.into();
19
20 let secp = Secp256k1::new();
22
23 let seed = Sha256::digest(s.as_bytes()).to_vec();
25
26 let secret_key = SecretKey::from_slice(&seed).unwrap();
28
29 let public_key = PublicKey::from_secret_key(&secp, &secret_key);
31
32 let public_key_bytes = public_key.serialize();
34
35 let sha256_result = Sha256::digest(public_key_bytes);
37
38 let ripemd160_result = Ripemd160::digest(sha256_result);
40
41 let address =
43 bech32::encode("cosmwasm", ripemd160_result.to_base32(), Variant::Bech32).unwrap();
44
45 Account {
46 secret_key,
47 public_key,
48 address: Addr::unchecked(address),
49 }
50 }
51
52 pub fn sign(&self, message_hash: Vec<u8>) -> Signature {
56 let secp = Secp256k1::signing_only();
58
59 let hash_bytes: [u8; 32] = message_hash
61 .as_slice()
62 .try_into()
63 .expect("hash length is not 32 bytes");
64
65 secp.sign_ecdsa(&Message::from_digest(hash_bytes), &self.secret_key)
67 }
68
69 pub fn message_hash(message: String) -> Vec<u8> {
73 let hash = Sha256::digest(message.as_bytes());
75 hash.to_vec()
76 }
77
78 pub fn public_key_base64(&self) -> String {
80 general_purpose::STANDARD.encode(self.public_key.serialize())
81 }
82}
83
84impl Default for Account {
85 fn default() -> Self {
86 Account::new("test".to_string())
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use cosmwasm_crypto::secp256k1_verify;
94
95 #[test]
96 fn test_new() {
97 let account = Account::new("seed".to_string());
98 assert_eq!(
99 account.public_key.to_string(),
100 "02c8f031561c4758c9551cff47246f2c347189fe684c04da35cf88e813f810e3c2"
101 );
102 assert_eq!(
103 account.address.to_string(),
104 "cosmwasm1efqyslkz34qurfjajpruzwv5v22c65kq5y4r46"
105 );
106 }
107
108 #[test]
109 fn test_sign() {
110 let account = Account::new("seed".to_string());
111 let message = "hello".to_string();
112 let message_hash = Account::message_hash(message.clone());
113 let signature = account.sign(message_hash.clone());
114 assert_eq!(signature.to_string(), "3044022067e20eddd4e86a76c80382e80852ffbccd3131962070ee1ad524a798be5d83cb022000d7a45e0faa08dee805381df8c4a7ead53f8e319c69bd67fa3cc031ef519cbb");
115
116 let verify_res = secp256k1_verify(
118 &message_hash,
119 &signature.serialize_compact(),
120 &account.public_key.serialize(),
121 )
122 .unwrap();
123 assert!(verify_res);
124 }
125}