Skip to content

Commit

Permalink
add high-level function to validate a merkle set proof, given one ite…
Browse files Browse the repository at this point in the history
…m and the root hash
  • Loading branch information
arvidn committed Apr 19, 2024
1 parent 9058c12 commit 98a39c8
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 3 deletions.
15 changes: 13 additions & 2 deletions crates/chia-consensus/benches/merkle-set.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use chia_consensus::merkle_tree::MerkleSet;
use chia_consensus::merkle_tree::{validate_merkle_proof, MerkleSet};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::rngs::SmallRng;
use rand::{Rng, SeedableRng};
Expand Down Expand Up @@ -45,7 +45,7 @@ fn run(c: &mut Criterion) {
);
}

group.bench_function("deserialize_proof", |b| {
group.bench_function("parse_proof", |b| {
b.iter(|| {
let start = Instant::now();
for p in &proofs {
Expand All @@ -54,6 +54,17 @@ fn run(c: &mut Criterion) {
start.elapsed()
})
});
let root = &tree.get_root();
use std::iter::zip;
group.bench_function("validate_merkle_proof", |b| {
b.iter(|| {
let start = Instant::now();
for (p, leaf) in zip(&proofs, &leafs) {
assert!(validate_merkle_proof(&p, leaf, root))
}
start.elapsed()
})
});
}

criterion_group!(merkle_set, run);
Expand Down
8 changes: 8 additions & 0 deletions crates/chia-consensus/src/merkle_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,14 @@ fn pad_middles_for_proof_gen(proof: &mut Vec<u8>, left: &[u8; 32], right: &[u8;
}
}

pub fn validate_merkle_proof(proof: &[u8], item: &[u8; 32], root: &[u8; 32]) -> bool {
let tree = MerkleSet::from_proof(proof).expect("failed to parse proof");
if tree.get_root() != *root {
return false;
}
matches!(tree.generate_proof(item), Ok(Some(_)))
}

#[cfg(feature = "py-bindings")]
#[pymethods]
impl MerkleSet {
Expand Down
3 changes: 3 additions & 0 deletions tests/test_merkle_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
MerkleSet as RustMerkleSet,
deserialize_proof as ru_deserialize_proof,
compute_merkle_set_root,
validate_merkle_proof,
)
from random import Random
from merkle_set import (
Expand All @@ -29,6 +30,8 @@ def check_proof(
assert included
assert proof == proof2

assert validate_merkle_proof(proof, item, root)


def check_tree(leafs: List[bytes32]) -> None:
ru_tree = RustMerkleSet(leafs)
Expand Down
6 changes: 6 additions & 0 deletions wheel/generate_type_stubs.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ def deserialize_proof(
proof: bytes
) -> MerkleSet: ...
def validate_merkle_proof(
proof: bytes,
item: bytes32,
root: bytes32,
) -> bool: ...
COND_ARGS_NIL: int = ...
NO_UNKNOWN_CONDS: int = ...
STRICT_ARGS_COUNT: int = ...
Expand Down
6 changes: 6 additions & 0 deletions wheel/python/chia_rs/chia_rs.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ def deserialize_proof(
proof: bytes
) -> MerkleSet: ...

def validate_merkle_proof(
proof: bytes,
item: bytes32,
root: bytes32,
) -> bool: ...

COND_ARGS_NIL: int = ...
NO_UNKNOWN_CONDS: int = ...
STRICT_ARGS_COUNT: int = ...
Expand Down
9 changes: 8 additions & 1 deletion wheel/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use chia_consensus::gen::run_puzzle::run_puzzle as native_run_puzzle;
use chia_consensus::gen::solution_generator::solution_generator as native_solution_generator;
use chia_consensus::gen::solution_generator::solution_generator_backrefs as native_solution_generator_backrefs;
use chia_consensus::merkle_set::compute_merkle_set_root as compute_merkle_root_impl;
use chia_consensus::merkle_tree::MerkleSet;
use chia_consensus::merkle_tree::{validate_merkle_proof, MerkleSet};
use chia_protocol::{
BlockRecord, Bytes32, ChallengeBlockInfo, ChallengeChainSubSlot, ClassgroupElement, Coin,
CoinSpend, CoinState, CoinStateUpdate, EndOfSubSlotBundle, Foliage, FoliageBlockData,
Expand Down Expand Up @@ -82,6 +82,12 @@ pub fn deserialize_proof(proof: &[u8]) -> PyResult<MerkleSet> {
MerkleSet::from_proof(proof).map_err(|_| PyValueError::new_err("Invalid proof"))
}

#[pyfunction]
#[pyo3(name = "validate_merkle_proof")]
pub fn py_validate_merkle_proof(proof: &[u8], item: Bytes32, root: Bytes32) -> bool {
validate_merkle_proof(proof, (&item).into(), (&root).into())
}

#[pyfunction]
pub fn tree_hash(py: Python, blob: PyBuffer<u8>) -> PyResult<&PyBytes> {
if !blob.is_c_contiguous() {
Expand Down Expand Up @@ -358,6 +364,7 @@ pub fn chia_rs(_py: Python, m: &PyModule) -> PyResult<()> {
// merkle tree
m.add_class::<MerkleSet>()?;
m.add_function(wrap_pyfunction!(deserialize_proof, m)?)?;
m.add_function(wrap_pyfunction!(py_validate_merkle_proof, m)?)?;

// clvm functions
m.add("COND_ARGS_NIL", COND_ARGS_NIL)?;
Expand Down

0 comments on commit 98a39c8

Please sign in to comment.