use sp_std::{collections::btree_map::BTreeMap, vec::Vec, result::Result}; use frost_core::{Ciphersuite, Group, Identifier}; use ghost_helpers::SubstrateBlake2Hasher; use ghost_traits::{ exodus::{MerkleTreeBuilder, IdentifierConverter}, hashing::GhostHasher, }; use crate::{AuthIndex, ExodusError, NetworkCurve}; impl MerkleTreeBuilder for NetworkCurve { type Hash = ::Hash; fn build_merkle_tree( values: &BTreeMap, V>, serialize_fn: F, ) -> Result, ExodusError> where C: frost_core::Ciphersuite, <::Group as Group>::Field: frost_core::Field, F: Fn(&V) -> Result, ExodusError> { use ghost_helpers::merkle_tree::generate_tree; type CField = <::Group as Group>::Field; let max_index = values.keys() .next_back() .and_then(|id| { let id_scalar = id.to_scalar(); let id_bytes = as frost_core::Field>::serialize(&id_scalar); Self::convert_identifier_to_index(id_bytes.as_ref()).ok() }) .ok_or(ExodusError::IncorrectNumberOfIdentifiers)?; generate_tree::( max_index, values.iter(), |(identifier, value)| { let id_scalar = identifier.to_scalar(); let id_bytes = as frost_core::Field>::serialize(&id_scalar); let index = Self::convert_identifier_to_index(id_bytes.as_ref())?; let value_bytes = serialize_fn(value).map_err(|_| ExodusError::SerializationError)?; // NOTE: revisit // Is it possible to use [u8; CONSTANT] where constant is // purely dependant on provided generic. let mut preimage = Vec::::with_capacity(id_bytes.as_ref().len() + value_bytes.len()); preimage.extend_from_slice(id_bytes.as_ref()); preimage.extend_from_slice(value_bytes.as_ref()); Ok((index as usize, preimage)) }) } fn generate_merkle_proof_from_tree( values: &BTreeMap, V>, merkle_tree: &[Self::Hash], authority_index: AuthIndex, serialize_fn: F, ) -> Result<(Vec, Vec), ExodusError> where C: frost_core::Ciphersuite, <::Group as Group>::Field: frost_core::Field, F: Fn(&V) -> Result, ExodusError> { use ghost_helpers::merkle_tree::generate_proof; type CField = <::Group as Group>::Field; let non_zero_index = Self::non_zero_index(authority_index)?; let identifier = Identifier::try_from(non_zero_index) .map_err(|_| ExodusError::InvalidParticipantId)?; let value = values.get(&identifier).ok_or(ExodusError::InvalidParticipantId)?; let value_bytes = serialize_fn(&value).map_err(|_| ExodusError::SerializationError)?; let max_index = values.keys() .next_back() .and_then(|id| { let id_scalar = id.to_scalar(); let id_bytes = as frost_core::Field>::serialize(&id_scalar); Self::convert_identifier_to_index(id_bytes.as_ref()).ok() }) .ok_or(ExodusError::IncorrectNumberOfIdentifiers)?; let proof = generate_proof::( merkle_tree, max_index, authority_index, ); Ok((value_bytes, proof)) } fn verify_merkle_proof( &self, values: &[u8], merkle_proof: &[Self::Hash], merkle_root: Self::Hash, authority_index: AuthIndex, ) -> Result<(), ExodusError> { use ghost_helpers::merkle_tree::verify_tree_proof; let preimage = with_ciphersuite!(self, |f| { let non_zero_index = Self::non_zero_index(authority_index)?; let identifier = f::Identifier::try_from(non_zero_index) .map_err(|_| ExodusError::InvalidParticipantId)?; let mut preimage = identifier.serialize(); preimage.extend_from_slice(values); Ok(preimage) })?; let is_verified = verify_tree_proof::( &preimage, merkle_proof, merkle_root, authority_index, ); is_verified.then(|| ()).ok_or(ExodusError::InvalidMerkleProof) } }