Skip to content

Commit

Permalink
Merge pull request #3 from rozbb/separate-out-mem-backed-tree
Browse files Browse the repository at this point in the history
Large refactor. See PR for details
  • Loading branch information
rozbb authored Nov 21, 2024
2 parents a3f3965 + 1e7e48a commit c51e6c3
Show file tree
Hide file tree
Showing 13 changed files with 1,132 additions and 767 deletions.
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Additions

* Added `indices_for_inclusion_proof()` and `indices_for_consistency_proof()` methods. These allow the construction of inclusion proofs for trees which do not fit into memory.
* Relatedly, added `InclusionProof::from_digests()` and `ConsistencyProof::from_digests()`

### Removals

* Removed `SimpleWriter` trait in favor of the pre-existing `digest::Update`
* Removed `serde` trait impls from `InclusionProof`, `ConsistencyProof`, and `RootHash`

### Changes

* Renamed the `CtMerkleTree` struct to `MemoryBackedTree`
* Renamed the `CanonicalSerialize` trait to `HashableLeaf`
* Changed argument to `MemoryBackedTree::prove_consistency` to be the number of additions, rather than the size of the prefix
* Made all verification methods panic-free
68 changes: 61 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ CT Merkle
[![Docs](https://docs.rs/ct-merkle/badge.svg)](https://docs.rs/ct-merkle)
[![CI](https://github.com/rozbb/ct-merkle/workflows/CI/badge.svg)](https://github.com/rozbb/ct-merkle/actions)

This is an implementation of the append-only log described in the [Certificate Transparency specification (RFC 6962)](https://datatracker.ietf.org/doc/html/rfc6962). The log is a Merkle tree, and its leaves are the items it contains.
This is an implementation of the Merkle tree functionality described in the [Certificate Transparency specification (RFC 6962)](https://datatracker.ietf.org/doc/html/rfc6962).
Two properties can be proven about trees:

The log has two important features:

1. **Inclusion proofs.** You can construct a succinct proof that a particular item appears in a given tree.
2. **Consistency proofs.** You can construct a succinct proof that one tree is a prefix of another tree, i.e., that tree #2 is the result of appending some number of items to the end of tree #1.
1. **Inclusion proofs** state that a a particular item appears in a given tree.
2. **Consistency proofs** state that one tree is a prefix of another tree, i.e., that tree #2 is the result of appending some number of items to the end of tree #1.

This crate provides an append-only memory-backed Merkle tree with inclusion and consistency proof functionality, as well as functions for proof verification.
In addition, this crate provides functions for building proofs when the full tree does not fit in memory, e.g., in Certificate Transparency.

Crate Features
--------------
Expand All @@ -19,8 +20,8 @@ Default feature flags: none

Feature flag list:

* `serde` - Implements `serde::Serialize` and `serde::Deserialize` for: `CtMerkleTree`, `RootHash`, `InclusionProof`, and `ConsistencyProof`
* `std` - Implements `std::error::Error` for all the error types
* `std` - Implements `std::error::Error` for all error types
* `serde` - Implements `serde::Serialize` and `serde::Deserialize` for `MemoryBackedTree`


License
Expand All @@ -38,3 +39,56 @@ Warning
-------

This code has not been audited in any sense of the word. Use it at your own peril.


Example usage
-------------
Below is an example of two ways to construct an inclusion proof.
```rust
# extern crate alloc;
# use alloc::{
# string::{String, ToString},
# vec::Vec,
# };
use ct_merkle::{
indices_for_inclusion_proof, InclusionProof,
mem_backed_tree::MemoryBackedTree
};
use sha2::Sha256;

# fn main() {
// Make a new tree whose leaves are strings
let mut tree = MemoryBackedTree::<Sha256, String>::new();
tree.push("hello".to_string());
tree.push("world".to_string());
let root = tree.root();

// Prove inclusion of the last item in the tree
let items_pushed = tree.len();
let item_to_prove = items_pushed - 1;
let inclusion_proof = tree.prove_inclusion(item_to_prove as usize);
// Verify the inclusion
assert!(root
.verify_inclusion(&"world", item_to_prove, &inclusion_proof)
.is_ok());

// Now imagine we don't have a memory-backed tree. We will get the indices for
// the hashes to fetch and then build the proof
let indices_to_fetch = indices_for_inclusion_proof(items_pushed, item_to_prove);

//
// Imagine here we fetch the indices in order and place them into `digests`...
//

# let digests: Vec<&digest::Output<Sha256>> = inclusion_proof
# .as_bytes()
# .chunks(32)
# .map(Into::into)
# .collect();
let inclusion_proof = InclusionProof::from_digests(digests);
// Verify the inclusion
assert!(root
.verify_inclusion(&"world", item_to_prove, &inclusion_proof)
.is_ok());
# }
```
Loading

0 comments on commit c51e6c3

Please sign in to comment.