use serde::{Deserialize, Serialize};
use std::{
fmt,
hash::{Hash, Hasher as StdHasher},
str::FromStr,
};
use super::TreeHash;
use rs_merkle::{algorithms::Sha256, MerkleProof};
#[derive(
Default, Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Hash,
)]
pub struct CommitHash(#[serde(with = "hex::serde")] pub TreeHash);
impl AsRef<TreeHash> for CommitHash {
fn as_ref(&self) -> &TreeHash {
&self.0
}
}
impl From<&CommitHash> for [u8; 32] {
fn from(value: &CommitHash) -> Self {
value.0
}
}
impl fmt::Display for CommitHash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", hex::encode(self.0))
}
}
impl FromStr for CommitHash {
type Err = crate::Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let value = hex::decode(value)?;
let value: TreeHash = value.as_slice().try_into()?;
Ok(Self(value))
}
}
#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub enum Comparison {
Equal,
Contains(Vec<usize>),
#[default]
Unknown,
}
pub struct CommitProof {
pub root: CommitHash,
pub proof: MerkleProof<Sha256>,
pub length: usize,
pub indices: Vec<usize>,
}
impl Hash for CommitProof {
fn hash<H: StdHasher>(&self, state: &mut H) {
self.root.hash(state);
self.proof.proof_hashes().hash(state);
self.length.hash(state);
self.indices.hash(state);
}
}
impl PartialEq for CommitProof {
fn eq(&self, other: &Self) -> bool {
self.root == other.root
&& self.proof.proof_hashes() == other.proof.proof_hashes()
&& self.length == other.length
&& self.indices == other.indices
}
}
impl Eq for CommitProof {}
impl Clone for CommitProof {
fn clone(&self) -> Self {
let hashes = self.proof.proof_hashes().to_vec();
CommitProof {
root: self.root,
proof: MerkleProof::<Sha256>::new(hashes),
length: self.length,
indices: self.indices.clone(),
}
}
}
impl CommitProof {
pub fn root(&self) -> &CommitHash {
&self.root
}
pub fn len(&self) -> usize {
self.length
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn verify_leaves(
&self,
leaves: &[TreeHash],
) -> (bool, Vec<TreeHash>) {
let leaves_to_prove = self
.indices
.iter()
.filter_map(|i| leaves.get(*i))
.copied()
.collect::<Vec<_>>();
(
self.proof.verify(
self.root().into(),
&self.indices,
leaves_to_prove.as_slice(),
leaves.len(),
),
leaves_to_prove,
)
}
}
impl From<CommitProof> for (CommitHash, usize) {
fn from(value: CommitProof) -> Self {
(value.root, value.length)
}
}
impl From<CommitProof> for CommitHash {
fn from(value: CommitProof) -> Self {
value.root
}
}
impl Default for CommitProof {
fn default() -> Self {
Self {
root: Default::default(),
proof: MerkleProof::<Sha256>::new(vec![]),
length: 0,
indices: vec![],
}
}
}
impl fmt::Debug for CommitProof {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CommitProof")
.field("root", &self.root.to_string())
.field("length", &self.length)
.field("indices", &self.indices)
.finish()
}
}