OpenZeppelin / merkle-tree

A JavaScript library to generate merkle trees and merkle proofs.
MIT License
436 stars 106 forks source link

this library doesn't match with https://github.com/lambdaclass/merkle_patricia_tree and cita-trie #27

Closed GopherJ closed 9 months ago

GopherJ commented 9 months ago
//! # Basic example.
//!
//! Target hash extracted from here:
//!   https://github.com/ethereum/tests/blob/develop/TrieTests/trietest.json#L97-L104
//!
//! ## Dependencies
//!
//! ```toml
//! [dependencies]
//! cita_trie = "4.0.0"
//! hasher = "0.1.4"
//! hex-literal = "0.3.4"
//! memory-db = "0.31.0"
//! reference-trie = "0.26.0"
//! sha3 = "0.10.6"
//! trie-db = "0.24.0"
//!
//! [dependencies.patricia-merkle-tree]
//! git = "https://github.com/lambdaclass/merkle_patricia_tree"
//! ```

use cita_trie::{MemoryDB, PatriciaTrie, Trie};
use hasher::HasherKeccak;
use hex_literal::hex;
use patricia_merkle_tree::PatriciaMerkleTree;
use sha3::Keccak256;
use std::sync::Arc;

#[inline]
pub fn keccak(data: impl AsRef<[u8]>) -> [u8; 32] {
    Keccak256::digest(data).into()
}

fn main() {
    const DATA: &[(&[u8], &[u8])] = &[(b"abc", b"123"), (b"abcd", b"abcd"), (b"abc", b"abc")];
    const HASH: [u8; 32] = hex!("7a320748f780ad9ad5b0837302075ce0eeba6c26e3d8562c67ccc0f1b273298a");

    println!("Expected   : {HASH:02x?}");
    println!("Our    hash: {:02x?}", run_ours(DATA.iter().copied()));
    println!("Cita   hash: {:02x?}", run_cita(DATA.iter().copied()));
    println!("Parity hash: {:02x?}", run_parity(DATA.iter().copied()));
}

fn run_ours<'a>(data: impl Iterator<Item = (&'a [u8], &'a [u8])>) -> [u8; 32] {
    let mut trie = PatriciaMerkleTree::<_, _, Keccak256>::new();

    data.for_each(|(p, v)| {
        trie.insert(p, v);
    });

    trie.compute_hash().as_slice().try_into().unwrap()
}

fn run_cita<'a>(data: impl Iterator<Item = (&'a [u8], &'a [u8])>) -> [u8; 32] {
    let mem_db = Arc::new(MemoryDB::new(true));
    let hasher = Arc::new(HasherKeccak::new());

    let mut trie = PatriciaTrie::new(mem_db, hasher);

    data.for_each(|(p, v)| {
        trie.insert(p.to_vec(), v.to_vec()).unwrap();
    });

    trie.root().unwrap().try_into().unwrap()
}

fn run_parity<'a>(data: impl Iterator<Item = (&'a [u8], &'a [u8])>) -> [u8; 32] {
    use memory_db::{HashKey, MemoryDB};
    use reference_trie::ExtensionLayout;
    use trie_db::{NodeCodec, TrieDBMutBuilder, TrieHash, TrieLayout, TrieMut};

    let mut mem_db =
        MemoryDB::<_, HashKey<_>, _>::new(<ExtensionLayout as TrieLayout>::Codec::empty_node());
    let mut root = <TrieHash<ExtensionLayout>>::default();

    let mut trie = TrieDBMutBuilder::<ExtensionLayout>::new(&mut mem_db, &mut root).build();

    data.for_each(|(p, v)| {
        trie.insert(p, v).unwrap();
    });

    trie.commit();
    *trie.root()
}

versus:

  const values = [
    ["abc", "123"],
    ["abcd", "abcd"],
    ["abc", "abc"],
  ];

  // (2)
  const tree = StandardMerkleTree.of(values, ["string", "string"]); // 0x12c434992f743725d450dd2240dae6de7b9c019fe014efe2ca29f25c101a99cf
GopherJ commented 9 months ago

but @ethereumjs/trie matches:

import {bytesToUtf8, utf8ToBytes} from "@ethereumjs/util";
import {hexlify} from "ethers/lib/utils";
  const trie = await Trie.create();

  await trie.put(utf8ToBytes("abc"), utf8ToBytes("123"));
  await trie.put(utf8ToBytes("abcd"), utf8ToBytes("abcd"));
  await trie.put(utf8ToBytes("abc"), utf8ToBytes("abc"));
  console.log("Merkle Root:", hexlify(trie.root()));
Amxx commented 9 months ago

Hello @GopherJ

This library is designed to build "userspace" merkle tree that are verified onchain using this library. It is designed to match (as best as possible) this package, that we used to recommend.

This library is NOT about Patricia Merkle trees.

GopherJ commented 9 months ago

ok, my bad thanks