#![cfg_attr(not(feature = "std"), no_std)] use ghost_traits::hashing::GhostHasher; use sp_core::H256; use sp_io::hashing::{blake2_256, keccak_256, sha2_256}; pub mod bounded_bitmap; pub mod hash_chain; pub mod merkle_tree; pub mod networks; pub mod utxo; pub mod lcg; pub type AuthIndexU8 = u8; pub type AuthIndexU16 = u16; pub type AuthIndexU32 = u32; pub type AuthIndexU64 = u64; pub type AuthIndexU128 = u128; pub type BitmapChunkU8 = u8; pub type BitmapChunkU16 = u16; pub type BitmapChunkU32 = u32; pub type BitmapChunkU64 = u64; pub type BitmapChunkU128 = u128; pub type DkgIndexU8 = u8; pub type DkgIndexU16 = u16; pub type DkgIndexU32 = u32; pub type DkgIndexU64 = u64; pub type DkgIndexU128 = u128; pub type NetworkIdU8 = u8; pub type NetworkIdU16 = u16; pub type NetworkIdU32 = u32; pub type NetworkIdU64 = u64; pub type NetworkIdU128 = u128; pub fn get_byzantium_quorum_threshold(value: I) -> I where I: num_traits::PrimInt, { let zero = I::zero(); let one = I::one(); let three = one + one + one; if value == zero { return zero; } let f = (value - one) / three; value - f } macro_rules! impl_ghost_hasher { ( struct $name:ident; hash_type: $hash_type:ty; hash_bytes_len: $hash_bytes_len:expr; fn hash($data:ident) -> $hash_res:expr ) => { pub struct $name; impl GhostHasher for $name { type Hash = $hash_type; type HashBytes = [u8; $hash_bytes_len]; fn hash($data: &[u8]) -> Self::Hash { $hash_res } fn hash_len() -> usize { $hash_bytes_len } fn empty() -> Self::Hash { <$hash_type>::zero() } fn combine_hashes(left: Self::Hash, right: Self::Hash) -> Self::Hash { let mut combined = [0u8; $hash_bytes_len * 2]; combined[..$hash_bytes_len].copy_from_slice(left.as_ref()); combined[$hash_bytes_len..].copy_from_slice(right.as_ref()); Self::hash(&combined) } fn combine_hashes_prefixed(p: u8, l: Self::Hash, r: Self::Hash) -> Self::Hash { let mut combined = [p; $hash_bytes_len * 2 + 1]; combined[1..1 + $hash_bytes_len].copy_from_slice(l.as_ref()); combined[1 + $hash_bytes_len..].copy_from_slice(r.as_ref()); Self::hash(&combined) } } }; } impl_ghost_hasher!( struct SubstrateBlake2Hasher; hash_type: H256; hash_bytes_len: 32; fn hash(data) -> H256::from(blake2_256(data)) ); impl_ghost_hasher!( struct SubstrateKeccakHasher; hash_type: H256; hash_bytes_len: 32; fn hash(data) -> H256::from(keccak_256(data)) ); impl_ghost_hasher!( struct UtxoSha2Hasher; hash_type: H256; hash_bytes_len: 32; fn hash(data) -> { let first_pass: [u8; 32] = sha2_256(data); let second_pass: [u8; 32] = sha2_256(&first_pass); H256::from(second_pass) } ); #[cfg(test)] mod tests { use super::*; #[test] fn test_bft_threshold_standard_paper_cases() { // Lower boundaries (f increases here) assert_eq!(get_byzantium_quorum_threshold(1u32), 1); assert_eq!(get_byzantium_quorum_threshold(4u32), 3); assert_eq!(get_byzantium_quorum_threshold(7u32), 5); assert_eq!(get_byzantium_quorum_threshold(10u32), 7); // Upper boundaries (max nodes for a given 'f') assert_eq!(get_byzantium_quorum_threshold(3u32), 3); assert_eq!(get_byzantium_quorum_threshold(6u32), 5); assert_eq!(get_byzantium_quorum_threshold(9u32), 7); } #[test] fn test_bft_threshold_zero_nodes() { assert_eq!(get_byzantium_quorum_threshold(0u32), 0); } #[test] fn test_bft_threshold_integer_boundaries() { let max_val = usize::MAX; let expected_f = (max_val - 1) / 3; let expected_honest = max_val - expected_f; assert_eq!(get_byzantium_quorum_threshold(max_val), expected_honest); } #[test] fn test_bft_threshold_different_types() { assert_eq!(get_byzantium_quorum_threshold(4u8), 3u8); assert_eq!(get_byzantium_quorum_threshold(4u64), 3u64); assert_eq!(get_byzantium_quorum_threshold(4usize), 3usize); } }