Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Rust implementations of MerkleTree / Proof / SparseMerkleTree to use non-keccak256 hash functions #2388

Closed
serejke opened this issue Jun 14, 2023 · 2 comments

Comments

@serejke
Copy link
Contributor

serejke commented Jun 14, 2023

Overview

For non-EVM chains integration it may be necessary to use a hash function other than keccak256. For instance, we're working on Cardano integration. Cardano does not have a native support of keccak256, and implementing it in a smart contract is computationally/gas unfeasible. We've opened a CIP for keccak256 support, but it may take several months to a year to make into the Cardano mainnet. For now the only option is to use blake2b (256) for MerkleTree (on-chain and off-chain) on Cardano side.

Description

This task is about refactoring the off-chain agents to make the hash-function customizable. For simplicity, the new hash function must return H256. Returning a different value would require a massive refactoring throughout the whole codebase. So hash functions with a bigger hash size will not be supported for now.

pub(super) fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 {

hash_concat(left, right) strictly depends on Keccak256.

Suggestion

I see a couple of ways to resolving this:

Add a trait HashFunction

pub trait HashFunction {
    fn hash_concat(&self, left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256;
}

pub struct Keccak256HashFunction;

impl HashFunction for Keccak256HashFunction {
    fn hash_concat(&self, left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 {
        H256::from_slice(Keccak256::new().chain(left).chain(right).finalize().as_slice())
    }
}

pub struct Blake2b256HashFunction;

impl HashFunction for Blake2b256HashFunction {
    fn hash_concat(&self, left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 {
        let mut hasher = Blake2b::new();        
        hasher.update(left);
        hasher.update(right);
        let result = hasher.finalize();
        H256::from_slice(result.as_slice())
    }
}

Then pass the HashFunction trait to the hash_concat.

  • dynamically as &dyn HashFunction — then we need to store the object reference in all dependent structs
  • statically as &HashFunction — then all the dependent structs need to have a generic parameter and own the function

Using cargo feature flags

// accumulator/mod.rs

#[cfg(feature = "keccak256")]
pub use keccak256::hash_concat;

#[cfg(feature = "blake2b256")]
pub use blake2b256::hash_concat;

// accumulator/mod.rs Cargo.toml

[features]
default = ["keccak256"]

// Cargo.toml
[dependencies]
accumulator = { version = "*", features = ["blake2b256"] }
@nambrot
Copy link
Contributor

nambrot commented Jun 14, 2023

Related to #2258, I'll try to capture it more broadly as well

@nambrot
Copy link
Contributor

nambrot commented Jun 16, 2023

Tried to capture it comprehensively at #2399

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

No branches or pull requests

3 participants