use sn_interface::messaging::system::{DkgFailureSig, DkgFailureSigSet, DkgSessionId};
use sn_interface::network_knowledge::{supermajority, ElderCandidates};
use sn_interface::types::keys::ed25519::{self, Digest256, Keypair, Verifier};
use std::collections::BTreeSet;
use tiny_keccak::{Hasher, Sha3};
use xor_name::XorName;
pub(crate) trait DkgSessionIdUtils {
fn new(elder_candidates: &ElderCandidates, generation: u64) -> Self;
}
impl DkgSessionIdUtils for DkgSessionId {
fn new(elder_candidates: &ElderCandidates, generation: u64) -> Self {
let mut hasher = Sha3::v256();
let mut hash = Digest256::default();
for peer in elder_candidates.names() {
hasher.update(&peer.0);
}
hasher.update(&elder_candidates.prefix().name().0);
hasher.update(&elder_candidates.prefix().bit_count().to_le_bytes());
hasher.finalize(&mut hash);
Self { hash, generation }
}
}
pub(crate) trait DkgFailureSigUtils {
fn new(
keypair: &Keypair,
failed_participants: &BTreeSet<XorName>,
dkg_key: &DkgSessionId,
) -> Self;
fn verify(&self, dkg_key: &DkgSessionId, failed_participants: &BTreeSet<XorName>) -> bool;
}
impl DkgFailureSigUtils for DkgFailureSig {
fn new(
keypair: &Keypair,
failed_participants: &BTreeSet<XorName>,
dkg_key: &DkgSessionId,
) -> Self {
DkgFailureSig {
public_key: keypair.public,
signature: ed25519::sign(&hashed_failure(dkg_key, failed_participants), keypair),
}
}
fn verify(&self, dkg_key: &DkgSessionId, failed_participants: &BTreeSet<XorName>) -> bool {
let hash = hashed_failure(dkg_key, failed_participants);
self.public_key.verify(&hash, &self.signature).is_ok()
}
}
pub(crate) trait DkgFailureSigSetUtils {
fn insert(&mut self, sig: DkgFailureSig, failed_participants: &BTreeSet<XorName>) -> bool;
fn has_agreement(&self, elder_candidates: &ElderCandidates) -> bool;
fn verify(&self, elder_candidates: &ElderCandidates, generation: u64) -> bool;
}
impl DkgFailureSigSetUtils for DkgFailureSigSet {
fn insert(&mut self, sig: DkgFailureSig, failed_participants: &BTreeSet<XorName>) -> bool {
if self.failed_participants.is_empty() {
self.failed_participants = failed_participants.clone();
}
if self
.sigs
.iter()
.all(|existing_sig| existing_sig.public_key != sig.public_key)
{
self.sigs.push(sig);
true
} else {
false
}
}
fn has_agreement(&self, elder_candidates: &ElderCandidates) -> bool {
has_failure_agreement(elder_candidates.len(), self.sigs.len())
}
fn verify(&self, elder_candidates: &ElderCandidates, generation: u64) -> bool {
let hash = hashed_failure(
&DkgSessionId::new(elder_candidates, generation),
&self.failed_participants,
);
let votes = self
.sigs
.iter()
.filter(|sig| {
elder_candidates.contains(&ed25519::name(&sig.public_key))
&& sig.public_key.verify(&hash, &sig.signature).is_ok()
})
.count();
has_failure_agreement(elder_candidates.len(), votes)
}
}
fn has_failure_agreement(num_participants: usize, num_votes: usize) -> bool {
num_votes > num_participants - supermajority(num_participants)
}
fn hashed_failure(dkg_key: &DkgSessionId, failed_participants: &BTreeSet<XorName>) -> Digest256 {
let mut hasher = Sha3::v256();
let mut hash = Digest256::default();
hasher.update(&dkg_key.hash);
hasher.update(&dkg_key.generation.to_le_bytes());
for name in failed_participants.iter() {
hasher.update(&name.0);
}
hasher.update(b"failure");
hasher.finalize(&mut hash);
hash
}