forked from ghostchain/ghost-node
128 lines
4.5 KiB
Rust
128 lines
4.5 KiB
Rust
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<AuthIndex, ExodusError> for NetworkCurve {
|
|
type Hash = <SubstrateBlake2Hasher as GhostHasher>::Hash;
|
|
|
|
fn build_merkle_tree<C, V, F>(
|
|
values: &BTreeMap<Identifier<C>, V>,
|
|
serialize_fn: F,
|
|
) -> Result<Vec<Self::Hash>, ExodusError>
|
|
where
|
|
C: frost_core::Ciphersuite,
|
|
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
|
F: Fn(&V) -> Result<Vec<u8>, ExodusError>
|
|
{
|
|
use ghost_helpers::merkle_tree::generate_tree;
|
|
|
|
type CField<C> = <<C as Ciphersuite>::Group as Group>::Field;
|
|
|
|
let max_index = values.keys()
|
|
.next_back()
|
|
.and_then(|id| {
|
|
let id_scalar = id.to_scalar();
|
|
let id_bytes = <CField<C> as frost_core::Field>::serialize(&id_scalar);
|
|
Self::convert_identifier_to_index(id_bytes.as_ref()).ok()
|
|
})
|
|
.ok_or(ExodusError::IncorrectNumberOfIdentifiers)?;
|
|
|
|
generate_tree::<SubstrateBlake2Hasher, _, _, _, _>(
|
|
max_index,
|
|
values.iter(),
|
|
|(identifier, value)| {
|
|
let id_scalar = identifier.to_scalar();
|
|
let id_bytes = <CField<C> 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::<u8>::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<C, V, F>(
|
|
values: &BTreeMap<Identifier<C>, V>,
|
|
merkle_tree: &[Self::Hash],
|
|
authority_index: AuthIndex,
|
|
serialize_fn: F,
|
|
) -> Result<(Vec<u8>, Vec<Self::Hash>), ExodusError>
|
|
where
|
|
C: frost_core::Ciphersuite,
|
|
<<C as Ciphersuite>::Group as Group>::Field: frost_core::Field,
|
|
F: Fn(&V) -> Result<Vec<u8>, ExodusError>
|
|
{
|
|
use ghost_helpers::merkle_tree::generate_proof;
|
|
|
|
type CField<C> = <<C as Ciphersuite>::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 = <CField<C> 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::<SubstrateBlake2Hasher, _>(
|
|
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::<SubstrateBlake2Hasher, _>(
|
|
&preimage,
|
|
merkle_proof,
|
|
merkle_root,
|
|
authority_index,
|
|
);
|
|
|
|
is_verified.then(|| ()).ok_or(ExodusError::InvalidMerkleProof)
|
|
}
|
|
}
|