diff --git a/Cargo.lock b/Cargo.lock index eae548c..1d6409a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -453,18 +453,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -563,6 +563,7 @@ name = "zk-kit-imt" version = "0.0.7" dependencies = [ "hex", + "thiserror", "tiny-keccak", ] @@ -592,4 +593,5 @@ name = "zk-kit-smt" version = "0.0.7" dependencies = [ "num-bigint", + "thiserror", ] diff --git a/crates/imt/Cargo.toml b/crates/imt/Cargo.toml index c356ebf..38202b4 100644 --- a/crates/imt/Cargo.toml +++ b/crates/imt/Cargo.toml @@ -8,4 +8,5 @@ description = "Incremental Merkle Tree" [dependencies] hex = "0.4.3" +thiserror = "2" tiny-keccak = { version = "2.0.0", features = ["keccak"] } diff --git a/crates/imt/src/errors.rs b/crates/imt/src/errors.rs new file mode 100644 index 0000000..9796b08 --- /dev/null +++ b/crates/imt/src/errors.rs @@ -0,0 +1,16 @@ +use thiserror::Error; + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum ImtError { + #[error("Too many leaves: got {got}, max for arity {arity} and depth {depth} is max {max}")] + TooManyLeaves { + got: usize, + arity: usize, + depth: usize, + max: usize, + }, + #[error("The tree is full")] + TreeFull, + #[error("The leaf does not exist in this tree")] + NotContained, +} diff --git a/crates/imt/src/imt.rs b/crates/imt/src/imt.rs index f65b42c..9736faf 100644 --- a/crates/imt/src/imt.rs +++ b/crates/imt/src/imt.rs @@ -1,3 +1,5 @@ +use crate::errors::ImtError; + pub struct IMT { nodes: Vec>, zeroes: Vec, @@ -23,9 +25,16 @@ impl IMT { zero_value: IMTNode, arity: usize, leaves: Vec, - ) -> Result { - if leaves.len() > arity.pow(depth as u32) { - return Err("The tree cannot contain more than arity^depth leaves"); + ) -> Result { + let got = leaves.len(); + let max = arity.pow(depth as u32); + if got > max { + return Err(ImtError::TooManyLeaves { + got, + arity, + depth, + max, + }); } let mut imt = IMT { @@ -93,9 +102,9 @@ impl IMT { self.nodes.get(0)?.iter().position(|n| n == &leaf) } - pub fn insert(&mut self, leaf: IMTNode) -> Result<(), &'static str> { + pub fn insert(&mut self, leaf: IMTNode) -> Result<(), ImtError> { if self.nodes[0].len() >= self.arity.pow(self.depth as u32) { - return Err("The tree is full"); + return Err(ImtError::TreeFull); } let index = self.nodes[0].len(); @@ -103,9 +112,9 @@ impl IMT { self.update(index, self.nodes[0][index].clone()) } - pub fn update(&mut self, mut index: usize, new_leaf: IMTNode) -> Result<(), &'static str> { + pub fn update(&mut self, mut index: usize, new_leaf: IMTNode) -> Result<(), ImtError> { if index >= self.nodes[0].len() { - return Err("The leaf does not exist in this tree"); + return Err(ImtError::NotContained); } let mut node = new_leaf; @@ -138,13 +147,13 @@ impl IMT { Ok(()) } - pub fn delete(&mut self, index: usize) -> Result<(), &'static str> { + pub fn delete(&mut self, index: usize) -> Result<(), ImtError> { self.update(index, self.zeroes[0].clone()) } - pub fn create_proof(&self, index: usize) -> Result { + pub fn create_proof(&self, index: usize) -> Result { if index >= self.nodes[0].len() { - return Err("The leaf does not exist in this tree"); + return Err(ImtError::NotContained); } let mut siblings = Vec::with_capacity(self.depth); diff --git a/crates/imt/src/lib.rs b/crates/imt/src/lib.rs index 3ca61dd..a47da0d 100644 --- a/crates/imt/src/lib.rs +++ b/crates/imt/src/lib.rs @@ -1,2 +1,5 @@ +pub mod errors; pub mod hash; pub mod imt; + +pub use errors::ImtError; diff --git a/crates/smt/Cargo.toml b/crates/smt/Cargo.toml index 910a1dc..6c30faf 100644 --- a/crates/smt/Cargo.toml +++ b/crates/smt/Cargo.toml @@ -10,3 +10,4 @@ description = "Sparse Merkle Tree" [dependencies] num-bigint = "0.4.6" +thiserror = "2" diff --git a/crates/smt/src/errors.rs b/crates/smt/src/errors.rs new file mode 100644 index 0000000..5fb3fe4 --- /dev/null +++ b/crates/smt/src/errors.rs @@ -0,0 +1,13 @@ +use thiserror::Error; + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum SMTError { + #[error("Key {0} already exists")] + KeyAlreadyExist(String), + #[error("Key {0} does not exist")] + KeyDoesNotExist(String), + #[error("Parameter {name} must be a {expected_type}")] + InvalidParameterType { name: String, expected_type: String }, + #[error("Invalid sibling index")] + InvalidSiblingIndex, +} diff --git a/crates/smt/src/lib.rs b/crates/smt/src/lib.rs index 6d39c77..9478b18 100644 --- a/crates/smt/src/lib.rs +++ b/crates/smt/src/lib.rs @@ -1,2 +1,5 @@ +pub mod errors; pub mod smt; mod utils; + +pub use errors::SMTError; diff --git a/crates/smt/src/smt.rs b/crates/smt/src/smt.rs index 682bae9..6c24d3a 100644 --- a/crates/smt/src/smt.rs +++ b/crates/smt/src/smt.rs @@ -2,35 +2,13 @@ use std::{collections::HashMap, str::FromStr}; use num_bigint::BigInt; +pub use crate::errors::SMTError; use crate::utils::{ get_first_common_elements, get_index_of_last_non_zero_element, is_hexadecimal, key_to_path, }; use std::fmt; -#[derive(Debug, PartialEq)] -pub enum SMTError { - KeyAlreadyExist(String), - KeyDoesNotExist(String), - InvalidParameterType(String, String), - InvalidSiblingIndex, -} - -impl fmt::Display for SMTError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SMTError::KeyAlreadyExist(s) => write!(f, "Key {} already exists", s), - SMTError::KeyDoesNotExist(s) => write!(f, "Key {} does not exist", s), - SMTError::InvalidParameterType(p, t) => { - write!(f, "Parameter {} must be a {}", p, t) - }, - SMTError::InvalidSiblingIndex => write!(f, "Invalid sibling index"), - } - } -} - -impl std::error::Error for SMTError {} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Node { Str(String), @@ -55,10 +33,10 @@ impl FromStr for Node { } else if is_hexadecimal(s) { Ok(Node::Str(s.to_string())) } else { - Err(SMTError::InvalidParameterType( - s.to_string(), - "BigInt or hexadecimal string".to_string(), - )) + Err(SMTError::InvalidParameterType { + name: s.to_string(), + expected_type: "BigInt or hexadecimal string".to_string(), + }) } } }