Skip to content

Commit

Permalink
refactor(circuits): prove_insertion and batch merkle proof circuit docs
Browse files Browse the repository at this point in the history
  • Loading branch information
distractedm1nd committed Aug 1, 2024
1 parent c4d31e1 commit f53ffa9
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 37 deletions.
28 changes: 28 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 11 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,32 @@ categories = ["no-std"]
readme = "README.md"

[features]
default = ["std"]
default = ["std", "bls"]
std = [
"serde/std",
"serde/std",
"num/std",
"num-bigint/std",
"num-traits/std",
"num-bigint/std",
"num-traits/std",
"borsh/std",
"hex/std",
]
bls = ["std", "bls12_381"]

[dependencies]
borsh = { version = "1.5.1", features = ["derive"], default-features = false }
num = { version = "0.4.0", default-features = false }
serde = { version = "1.0.151", features = ["derive", "rc"], default-features = false }
serde = { version = "1.0.151", features = [
"derive",
"rc",
], default-features = false }
anyhow = { version = "1.0.44", default-features = false }
serde_json = { version = "1.0.79", optional = true }
sha2 = { version = "0.10.8", default-features = false }
num-bigint = { version = "0.4.6", default-features = false }
num-traits = { version = "0.2.19", default-features = false }
hex = { version = "0.4.3", default-features = false }
bls12_381 = { version = "0.8.0", default-features = false, optional = true }


[dev-dependencies]
criterion = "0.3"
Expand Down
42 changes: 38 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,62 @@ pub mod node;
pub mod tree;

use alloc::string::ToString;
use anyhow::Result;
use anyhow::{anyhow, Result};
use borsh::{BorshDeserialize, BorshSerialize};
use error::MerkleTreeError;
use error::{MerkleTreeError, MerkleTreeResult};
use num_bigint::BigUint;
use num_traits::Num;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};

#[cfg(feature = "bls")]
use bls12_381::Scalar;

#[derive(
Serialize, Deserialize, BorshSerialize, BorshDeserialize, Debug, Clone, Copy, PartialEq, Eq,
)]
pub struct Hash([u8; 32]);

#[cfg(feature = "bls")]
impl TryFrom<Hash> for Scalar {
type Error = anyhow::Error;

fn try_from(value: Hash) -> Result<Scalar, Self::Error> {
let mut byte_array = [0u8; 32];
byte_array.copy_from_slice(value.as_ref());
byte_array.reverse();

let val =
[
u64::from_le_bytes(
byte_array[0..8].try_into().map_err(|_| {
anyhow!(format!("slice to array: [0..8] for hash: {value:?}"))
})?,
),
u64::from_le_bytes(byte_array[8..16].try_into().map_err(|_| {
anyhow!(format!("slice to array: [8..16] for hash: {value:?}"))
})?),
u64::from_le_bytes(byte_array[16..24].try_into().map_err(|_| {
anyhow!(format!("slice to array: [16..24] for hash: {value:?}"))
})?),
u64::from_le_bytes(byte_array[24..32].try_into().map_err(|_| {
anyhow!(format!("slice to array: [24..42] for hash: {value:?}"))
})?),
];

Ok(Scalar::from_raw(val))
}
}

impl Hash {
pub const fn new(bytes: [u8; 32]) -> Self {
Hash(bytes)
}

pub fn from_hex(hex_str: &str) -> Result<Self, MerkleTreeError> {
pub fn from_hex(hex_str: &str) -> MerkleTreeResult<Self> {
let mut bytes = [0u8; 32];
hex::decode_to_slice(hex_str, &mut bytes)
.map_err(|e| MerkleTreeError::InvalidFormatError(e.to_string()))?;
.map_err(|e| anyhow!(MerkleTreeError::InvalidFormatError(e.to_string())))?;
Ok(Hash(bytes))
}

Expand Down
52 changes: 24 additions & 28 deletions src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ use num_bigint::BigInt;
use num_bigint::Sign;
use serde::{Deserialize, Serialize};

use crate::error::MerkleTreeError;
use crate::error::{MerkleTreeError, MerkleTreeResult};
use crate::node::{InnerNode, LeafNode, Node};
use crate::{sha256_mod, Hash};
use anyhow::anyhow;

// `MerkleProof` contains the root hash and a `Vec<Node>>` following the path from the leaf to the root.
#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down Expand Up @@ -173,8 +174,8 @@ impl IndexedMerkleTree {
/// * `nodes` - A vector of `Node` elements from which the Merkle tree will be built.
///
/// # Returns
/// A `Result<Self, MerkleTreeError>` representing the initialized tree or an error.
pub fn new(nodes: Vec<Node>) -> Result<Self, MerkleTreeError> {
/// A `MerkleTreeResult<Self>` representing the initialized tree or an error.
pub fn new(nodes: Vec<Node>) -> MerkleTreeResult<Self> {
// TODO(@distractedm1nd): Issue #3
let parsed_nodes = set_left_sibling_status_for_nodes(nodes);

Expand All @@ -191,8 +192,8 @@ impl IndexedMerkleTree {
/// * `size` - The number of nodes in the tree.
///
/// # Returns
/// A `Result<Self, MerkleTreeError>` representing the initialized tree or an error.
pub fn new_with_size(size: usize) -> Result<Self, MerkleTreeError> {
/// A `MerkleTreeResult<Self>` representing the initialized tree or an error.
pub fn new_with_size(size: usize) -> MerkleTreeResult<Self> {
let mut nodes: Vec<Node> = Vec::with_capacity(2 * size + 1);
let empty_hash = Node::HEAD;
let tail = Node::TAIL;
Expand Down Expand Up @@ -250,15 +251,15 @@ impl IndexedMerkleTree {
/// # Returns
///
/// * `Result<(), MerkleTreeError>` - A result indicating the success or failure of the operation.
fn calculate_root(&mut self) -> Result<(), MerkleTreeError> {
fn calculate_root(&mut self) -> MerkleTreeResult<()> {
// self.rebuild_tree_from_leaves();
self.rebuild_tree_from_leaves();

// set root not as left sibling
let root = self
.nodes
.last_mut()
.ok_or(MerkleTreeError::EmptyMerkleTreeError)?; // TODO: are there possible other Errors? is it possible at all to have an empty tree at this point?
.ok_or(anyhow!(MerkleTreeError::EmptyMerkleTreeError))?; // TODO: are there possible other Errors? is it possible at all to have an empty tree at this point?
root.set_left_sibling_value(false);

Ok(())
Expand All @@ -267,16 +268,16 @@ impl IndexedMerkleTree {
/// # Returns
///
/// The current root node of the Indexed Merkle tree.
pub fn get_root(&self) -> Result<&Node, MerkleTreeError> {
pub fn get_root(&self) -> MerkleTreeResult<&Node> {
self.nodes
.last()
.ok_or(MerkleTreeError::EmptyMerkleTreeError)
.ok_or(anyhow!(MerkleTreeError::EmptyMerkleTreeError))
}

/// # Returns
///
/// The current commitment (hash of the root node) of the Indexed Merkle tree.
pub fn get_commitment(&self) -> Result<Hash, MerkleTreeError> {
pub fn get_commitment(&self) -> MerkleTreeResult<Hash> {
Ok(self.get_root()?.get_hash())
}

Expand Down Expand Up @@ -358,10 +359,10 @@ impl IndexedMerkleTree {
///
/// # Returns
/// A `Result<MerkleProof, MerkleTreeError>` containing the membership proof or an error.
pub fn generate_membership_proof(&self, index: usize) -> Result<MerkleProof, MerkleTreeError> {
pub fn generate_membership_proof(&self, index: usize) -> MerkleTreeResult<MerkleProof> {
// if the index is outside of the valid range of the tree, there is no proof
if index >= self.nodes.len() {
return Err(MerkleTreeError::IndexError(index.to_string()));
return Err(anyhow!(MerkleTreeError::IndexError(index.to_string())));
}

let mut proof_path: Vec<Node> = Vec::new();
Expand Down Expand Up @@ -402,15 +403,15 @@ impl IndexedMerkleTree {
/// * `node` - A reference to the `Node` for which the non-membership proof is required.
///
/// # Returns
/// A `Result<NonMembershipProof, MerkleTreeError>` containing the non-membership proof and
/// A `MerkleTreeResult<NonMembershipProof>` containing the non-membership proof and
/// the index of the "closest" valid node, or an error.
pub fn generate_non_membership_proof(
&self,
node: &Node,
) -> Result<NonMembershipProof, MerkleTreeError> {
) -> MerkleTreeResult<NonMembershipProof> {
let given_node_as_leaf = match node {
Node::Leaf(leaf) => leaf,
_ => return Err(MerkleTreeError::NotFoundError("Leaf".to_string())),
_ => return Err(anyhow!(MerkleTreeError::NotFoundError("Leaf".to_string()))),
};

let mut found_index = None;
Expand All @@ -434,7 +435,7 @@ impl IndexedMerkleTree {
closest_index: found_index.unwrap(),
missing_node: given_node_as_leaf.clone(),
}),
None => Err(MerkleTreeError::MerkleProofError),
None => Err(anyhow!(MerkleTreeError::MerkleProofError)),
}
}

Expand All @@ -449,12 +450,8 @@ impl IndexedMerkleTree {
/// * `new_node` - The new state of the node.
///
/// # Returns
/// A `Result<UpdateProof, MerkleTreeError>` containing the the old root, the old proof, the new root and the new proof.
pub fn update_node(
&mut self,
index: usize,
new_node: Node,
) -> Result<UpdateProof, MerkleTreeError> {
/// A `MerkleTreeResult<UpdateProof, MerkleTreeError>` containing the the old root, the old proof, the new root and the new proof.
pub fn update_node(&mut self, index: usize, new_node: Node) -> MerkleTreeResult<UpdateProof> {
// generate old proof
let old_proof = self.generate_membership_proof(index)?;

Expand Down Expand Up @@ -484,13 +481,13 @@ impl IndexedMerkleTree {
/// * `new_node` - The new node to be inserted.
///
/// # Returns
/// A `Result<(MerkleProof, UpdateProof, UpdateProof), MerkleTreeError>` containing the non-membership proof and two update proofs.
pub fn insert_node(&mut self, new_node: &mut Node) -> Result<InsertProof, MerkleTreeError> {
/// A `MerkleTreeResult<InsertProof>` containing the non-membership proof and two update proofs.
pub fn insert_node(&mut self, new_node: &mut Node) -> MerkleTreeResult<InsertProof> {
// perform non-membership check in order to return the index of the node to be changed
let non_membership_proof = self.generate_non_membership_proof(new_node)?;

if non_membership_proof.merkle_proof.path.first().is_none() {
return Err(MerkleTreeError::MerkleProofError);
return Err(anyhow!(MerkleTreeError::MerkleProofError));
}

// generate first update proof, changing only the next pointer from the old node
Expand Down Expand Up @@ -701,12 +698,11 @@ pub fn set_left_sibling_status_for_nodes(nodes: Vec<Node>) -> Vec<Node> {
/// * `input_order` - A vector of strings representing the desired order of leaf labels.
///
/// # Returns
/// A `Result<Vec<Node>, MerkleTreeError>` representing the sorted nodes or an error.

/// A `MerkleTreeResult<Vec<Node>>` representing the sorted nodes or an error.
pub fn resort_nodes_by_input_order(
nodes: Vec<Node>,
input_order: Vec<Hash>,
) -> Result<Vec<Node>, MerkleTreeError> {
) -> MerkleTreeResult<Vec<Node>> {
let valid_nodes: Vec<_> = nodes
.into_iter()
.filter_map(|node| {
Expand Down

0 comments on commit f53ffa9

Please sign in to comment.