kujira_std/
merkle.rs

1use cosmwasm_schema::cw_serde;
2use cosmwasm_std::StdError;
3use hex::FromHexError;
4use sha2::Digest;
5use std::convert::TryInto;
6use thiserror::Error;
7
8#[cw_serde]
9pub struct Merkle {
10    root: String,
11}
12
13pub type Proof = Vec<String>;
14
15#[derive(Error, Debug, PartialEq)]
16pub enum Error {
17    #[error("{0}")]
18    Std(#[from] StdError),
19
20    #[error("{0}")]
21    Hex(#[from] FromHexError),
22
23    #[error("Wrong length")]
24    WrongLength {},
25
26    #[error("Verification failed")]
27    VerificationFailed {},
28}
29
30impl Merkle {
31    pub fn new(root: String) -> Result<Self, Error> {
32        let mut root_buf: [u8; 32] = [0; 32];
33        hex::decode_to_slice(&root, &mut root_buf)?;
34
35        Ok(Self { root })
36    }
37
38    pub fn verify(&self, proof: Proof, input: String) -> Result<(), Error> {
39        let hash = sha2::Sha256::digest(input.as_bytes())
40            .as_slice()
41            .try_into()
42            .map_err(|_| Error::WrongLength {})?;
43
44        let hash = proof.into_iter().try_fold(hash, |hash, p| {
45            let mut proof_buf = [0; 32];
46            hex::decode_to_slice(p, &mut proof_buf)?;
47            let mut hashes = [hash, proof_buf];
48            hashes.sort_unstable();
49            sha2::Sha256::digest(hashes.concat())
50                .as_slice()
51                .try_into()
52                .map_err(|_| Error::WrongLength {})
53        })?;
54
55        let mut root_buf: [u8; 32] = [0; 32];
56        hex::decode_to_slice(self.root.clone(), &mut root_buf)?;
57        if root_buf != hash {
58            return Err(Error::VerificationFailed {});
59        }
60        Ok(())
61    }
62}