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( size_hint: usize, values: &BTreeMap, V>, update_preimage_buffer: F, ) -> Result, ExodusError> where C: frost_core::Ciphersuite, <::Group as Group>::Field: frost_core::Field, F: Fn(&V, &mut Vec) -> Result<(), ExodusError> { use ghost_helpers::merkle_tree::{generate_tree, MerkleTreeError}; 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)?; let maybe_tree = generate_tree::( max_index, size_hint, values.iter(), |(identifier, value), buffer| { 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())?; buffer.extend_from_slice(id_bytes.as_ref()); update_preimage_buffer(value, buffer)?; Ok(index as usize) }); match maybe_tree { Ok(tree) => Ok(tree), Err(MerkleTreeError::Generate(exodus_err)) => Err(exodus_err), Err(MerkleTreeError::InvalidIndex) => Err(ExodusError::TreeGenerationFailed), Err(MerkleTreeError::Empty) => Err(ExodusError::IncorrectNumberOfIdentifiers), } } 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, MerkleTreeError}; 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)?; 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, ).map_err(|err| match err { MerkleTreeError::Generate(exodus_err) => exodus_err, MerkleTreeError::InvalidIndex => ExodusError::TreeGenerationFailed, MerkleTreeError::Empty => ExodusError::IncorrectNumberOfIdentifiers, })?; 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) } }