Skip to content

Commit

Permalink
Tendermint merkle hash (#21)
Browse files Browse the repository at this point in the history
* tendermint_hash

* document and link to tree

* update to use less copy

* removed let binding and added a test

* Fix warnings

* Improve feature granularity in maybestd to fix warns

* fmt

---------

Co-authored-by: Connor O'Hara <[email protected]>
Co-authored-by: Preston Evans <[email protected]>
  • Loading branch information
3 people authored Apr 25, 2024
1 parent 89f8cef commit ac03d7c
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ borsh = { version = "0.10.0", optional = true }
borsh = { version = "0.10.0" }
serde_json = "1.0.96"
postcard = { version = "1.0.4" }
tendermint = {version = "0.35.0"}

[features]
default = ["std"]
Expand Down
13 changes: 10 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ extern crate alloc;

mod maybestd {
#[cfg(not(feature = "std"))]
pub use alloc::{boxed, collections, format, string, vec};
pub use alloc::{boxed, vec};
#[cfg(all(not(feature = "std"), feature = "serde"))]
pub use alloc::{format, string};
#[cfg(not(feature = "std"))]
pub use core::{cmp, fmt, hash, marker, mem, ops};
#[cfg(feature = "std")]
pub use std::{boxed, cmp, collections, fmt, format, hash, marker, mem, ops, string, vec};
pub use std::{boxed, cmp, fmt, hash, marker, mem, ops, vec};
#[cfg(all(feature = "std", feature = "serde"))]
pub use std::{format, string};

pub mod hash_or_btree_map {
#[cfg(not(feature = "std"))]
Expand All @@ -46,6 +50,9 @@ use simple_merkle::{
mod namespaced_hash;
pub use namespaced_hash::*;

mod tendermint_hash;
pub use tendermint_hash::*;

// pub mod db;
pub mod nmt_proof;
pub mod simple_merkle;
Expand Down Expand Up @@ -414,7 +421,7 @@ pub enum RangeProofType {

#[cfg(test)]
mod tests {
use crate::maybestd::{format, vec::Vec};
use crate::maybestd::vec::Vec;
use crate::NamespaceMerkleHasher;
use crate::{
namespaced_hash::{NamespaceId, NamespacedSha2Hasher},
Expand Down
72 changes: 72 additions & 0 deletions src/tendermint_hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use sha2::{Digest, Sha256};

use crate::simple_merkle::tree::MerkleHash;

const LEAF_PREFIX: &[u8] = &[0];
const INNER_PREFIX: &[u8] = &[1];

fn leaf_hash(bytes: &[u8]) -> [u8; 32] {
//hash([LEAF_PREFIX, bytes].concat().as_slice())
let mut hasher = Sha256::new();
hasher.update(LEAF_PREFIX);
hasher.update(bytes);
hasher.finalize().into()
}

fn inner_hash(left: &[u8], right: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(INNER_PREFIX);
hasher.update(left);
hasher.update(right);
hasher.finalize().into()
}

/// A sha256 hasher, compatible with [Tendermint merkle hash](https://github.com/informalsystems/tendermint-rs/blob/979456c9f33463944f97f7ea3900640e59f7ea6d/tendermint/src/merkle.rs)
pub struct TmSha2Hasher;

impl Default for TmSha2Hasher {
fn default() -> Self {
Self::new()
}
}

impl TmSha2Hasher {
/// Create a new instance of the hasher
pub fn new() -> Self {
TmSha2Hasher
}
}

impl MerkleHash for TmSha2Hasher {
type Output = [u8; 32];

const EMPTY_ROOT: Self::Output = [
227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36, 39, 174, 65,
228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85,
];

fn hash_leaf(&self, data: &[u8]) -> Self::Output {
leaf_hash(data)
}
fn hash_nodes(&self, left: &Self::Output, right: &Self::Output) -> Self::Output {
inner_hash(left, right)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{MemDb, MerkleTree};
use tendermint::merkle::simple_hash_from_byte_vectors;
#[test]
fn test_tm_hash_matches_upstream() {
let leaves: Vec<&[u8]> = vec![b"leaf_1", b"leaf_2", b"leaf_3", b"leaf_4"];
let hasher = TmSha2Hasher {};
let mut tree: MerkleTree<MemDb<[u8; 32]>, TmSha2Hasher> = MerkleTree::with_hasher(hasher);
leaves.iter().for_each(|leaf| {
tree.push_raw_leaf(leaf);
});
let hash_from_byte_slices = simple_hash_from_byte_vectors::<Sha256>(leaves.as_slice());
assert_eq!(tree.root().as_ref(), &hash_from_byte_slices);
}
}

0 comments on commit ac03d7c

Please sign in to comment.