1use ecdsa::signature::DigestVerifier;
2use k256::sha2::{Digest, Sha256};
3use serde::{Deserialize, Serialize};
4use std::str::FromStr;
5
6#[derive(Serialize, Deserialize)]
7pub struct PublicKey {
8 #[serde(rename = "type")]
9 pub sig_type: String,
10 #[serde(rename = "value")]
11 pub sig_value: String,
12}
13
14#[derive(Serialize, Deserialize)]
15pub struct Signature {
16 pub pub_key: PublicKey,
17 pub signature: String,
18}
19
20fn generate_amino_transaction_string(signer: &str, data: &str) -> String {
21 format!("{{\"account_number\":\"0\",\"chain_id\":\"\",\"fee\":{{\"amount\":[],\"gas\":\"0\"}},\"memo\":\"\",\"msgs\":[{{\"type\":\"sign/MsgSignData\",\"value\":{{\"data\":\"{}\",\"signer\":\"{}\"}}}}],\"sequence\":\"0\"}}", data, signer)
22}
23
24pub fn verify_arbitrary(
25 account_addr: &str,
26 pubkey: &str,
27 data: &[u8],
28 signature: &Signature,
29) -> bool {
30 let rpc_signature_to_compare = hex::encode(base64::decode(&signature.signature).unwrap());
31 let signature: k256::ecdsa::Signature =
32 ecdsa::Signature::from_str(&rpc_signature_to_compare).unwrap();
33
34 let digest = Sha256::new_with_prefix(generate_amino_transaction_string(
35 account_addr,
36 &base64::encode(data),
37 ));
38
39 let pk = tendermint::PublicKey::from_raw_secp256k1(base64::decode(pubkey).unwrap().as_slice())
40 .unwrap();
41 let vk = pk.secp256k1().unwrap();
42
43 let verification = vk.verify_digest(digest, &signature);
44
45 verification.is_ok()
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 fn get_signature() -> Signature {
53 Signature {
54 pub_key: PublicKey {
55 sig_type: String::from("tendermint/PubKeySecp256k1"),
56 sig_value: String::from("Avt8e5UqfoRAh0RBUzHCu9arv7UFEFdfcv657h6TtSZE"),
57 },
58 signature: String::from("9PrDYrTb1tv/TALC/lgRIIekfwNMBPOra0QpaAqNCbADXT8vR9n0SS7L2OSaXma3UMrOLGTbWlLDImNhcZVgzA==")
59 }
60 }
61
62 #[test]
63 fn it_verifies_signature() {
64 let signature = get_signature();
65
66 assert_eq!(
67 true,
68 verify_arbitrary(
69 "juno105asxv7pt0fzxlz642pf4svm29u39zxzdq2ad5",
70 "Avt8e5UqfoRAh0RBUzHCu9arv7UFEFdfcv657h6TtSZE",
71 b"test",
72 &signature
73 )
74 );
75 }
76
77 #[test]
78 fn it_doesnt_verifies_signature() {
79 let signature = get_signature();
80
81 assert_eq!(
82 false,
83 verify_arbitrary(
84 "juno105asxv7pt0fzxlz642pf4svm29u39zxzdq2ad5",
85 "Avt8e5UqfoRAh0RBUzHCu9arv7UFEFdfcv657h6TtSZE",
86 b"not test",
87 &signature
88 )
89 );
90 }
91}