#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
use core::marker::PhantomData;
use sha2::{Digest as _, Sha256};
pub mod path;
pub mod subtree;
#[cfg(feature = "std")]
pub mod node;
#[cfg(feature = "std")]
pub mod db;
#[cfg(feature = "std")]
pub mod tx;
#[cfg(feature = "std")]
pub mod fs;
pub mod encode;
pub mod wasm;
pub type Hash = [u8; 32];
const LEAF_TAG: u8 = 0x00;
const INTERNAL_TAG: u8 = 0x01;
#[derive(Clone)]
pub struct Sha256Hasher;
const DEFAULT_CACHE_SIZE: usize = 1024 * 1024 * 1024;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Clone, Debug)]
pub struct Configuration<Hasher: NodeHasher> {
pub cache_size: usize,
pub auto_hash_index: bool,
pub hash_index_pruning: Option<usize>,
_marker: PhantomData<Hasher>,
}
#[derive(Debug)]
pub enum Error {
#[cfg(feature = "std")]
IO(std::io::Error),
Verify(VerifyError),
Encode(EncodeError),
}
#[derive(Debug)]
pub enum VerifyError {
KeyExists,
IncompleteProof,
KeyNotFound,
RootMismatch,
}
#[derive(Debug)]
pub enum EncodeError {
BufferTooSmall,
InvalidData(&'static str),
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
#[cfg(feature = "std")]
Error::IO(err) => write!(f, "IO error: {}", err),
Error::Verify(err) => write!(f, "Verification error: {}", err),
Error::Encode(err) => write!(f, "Encode error: {}", err),
}
}
}
impl core::fmt::Display for VerifyError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
VerifyError::KeyExists => write!(f, "Key already exists"),
VerifyError::IncompleteProof => write!(f, "Incomplete proof"),
VerifyError::KeyNotFound => write!(f, "Key not found"),
VerifyError::RootMismatch => write!(f, "Root mismatch"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl core::fmt::Display for EncodeError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
EncodeError::BufferTooSmall => write!(f, "Buffer too small"),
EncodeError::InvalidData(str) => write!(f, "Invalid data: {}", *str),
}
}
}
impl<Hasher: NodeHasher> Default for Configuration<Hasher> {
fn default() -> Self {
Self::new()
}
}
impl<Hasher: NodeHasher> Configuration<Hasher> {
pub fn new() -> Self {
Self {
cache_size: DEFAULT_CACHE_SIZE,
auto_hash_index: false,
hash_index_pruning: Some(120),
_marker: PhantomData,
}
}
pub fn with_cache_size(mut self, size: usize) -> Self {
self.cache_size = size;
self
}
pub fn with_auto_hash_index(mut self, enabled: bool) -> Self {
self.auto_hash_index = enabled;
self
}
pub fn with_hash_index_pruning(mut self, keep: Option<usize>) -> Self {
self.hash_index_pruning = keep;
self
}
}
pub trait NodeHasher: Clone {
fn hash(data: &[u8]) -> Hash;
fn hash_leaf(key: &[u8], value_hash: &[u8]) -> Hash;
fn hash_internal(prefix: &[u8], left: &[u8], right: &[u8]) -> Hash;
}
impl Configuration<Sha256Hasher> {
pub fn standard() -> Self {
Self::new().with_cache_size(DEFAULT_CACHE_SIZE)
}
}
impl NodeHasher for Sha256Hasher {
fn hash(data: &[u8]) -> Hash {
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize().as_slice().try_into().unwrap()
}
fn hash_leaf(key: &[u8], value_hash: &[u8]) -> Hash {
let mut hasher = Sha256::new();
hasher.update([LEAF_TAG]);
hasher.update(key);
hasher.update(value_hash);
hasher.finalize().as_slice().try_into().unwrap()
}
fn hash_internal(prefix: &[u8], left: &[u8], right: &[u8]) -> Hash {
let mut hasher = Sha256::new();
hasher.update([INTERNAL_TAG]);
let bit_len = prefix[0];
hasher.update([bit_len]);
hasher.update(&prefix[1..]);
hasher.update(left);
hasher.update(right);
hasher.finalize().as_slice().try_into().unwrap()
}
}
#[cfg(feature = "std")]
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error::IO(err)
}
}
#[cfg(feature = "std")]
impl From<std::io::ErrorKind> for Error {
fn from(kind: std::io::ErrorKind) -> Self {
Error::IO(std::io::Error::from(kind))
}
}
impl From<VerifyError> for Error {
fn from(err: VerifyError) -> Self {
Error::Verify(err)
}
}