Skip to content
This repository has been archived by the owner on Jun 25, 2021. It is now read-only.

Commit

Permalink
feat: move section_key into SectionAuthorityProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
maqi authored and dirvine committed May 10, 2021
1 parent 4c9091f commit 7d2d476
Show file tree
Hide file tree
Showing 21 changed files with 323 additions and 227 deletions.
10 changes: 4 additions & 6 deletions examples/minimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,12 +288,10 @@ async fn handle_event(index: usize, node: &mut Routing, event: Event) -> bool {
remaining,
added,
removed,
} => {
info!(
"Node #{} adults changed - remaining: {:?}, added: {:?}, removed: {:?}",
index, remaining, added, removed
)
}
} => info!(
"Node #{} adults changed - remaining: {:?}, added: {:?}, removed: {:?}",
index, remaining, added, removed
),
}

true
Expand Down
95 changes: 50 additions & 45 deletions src/agreement/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
messages::{Message, Variant},
node::Node,
routing::command::{self, Command},
section::{SectionAuthorityProvider, SectionKeyShare},
section::{EldersInfo, SectionAuthorityProvider, SectionKeyShare},
supermajority,
};
use bls_dkg::key_gen::{message::Message as DkgMessage, KeyGen};
Expand Down Expand Up @@ -43,17 +43,17 @@ pub struct DkgKey {
}

impl DkgKey {
pub fn new(section_auth: &SectionAuthorityProvider, generation: u64) -> Self {
pub fn new(elders_info: &EldersInfo, generation: u64) -> Self {
// Calculate the hash without involving serialization to avoid having to return `Result`.
let mut hasher = Sha3::v256();
let mut hash = Digest256::default();

for peer in section_auth.peers() {
for peer in elders_info.peers() {
hasher.update(&peer.name().0);
}

hasher.update(&section_auth.prefix.name().0);
hasher.update(&section_auth.prefix.bit_count().to_le_bytes());
hasher.update(&elders_info.prefix.name().0);
hasher.update(&elders_info.prefix.bit_count().to_le_bytes());
hasher.finalize(&mut hash);

Self { hash, generation }
Expand Down Expand Up @@ -106,28 +106,31 @@ impl DkgVoter {
&mut self,
keypair: &Keypair,
dkg_key: DkgKey,
section_auth: SectionAuthorityProvider,
elders_info: EldersInfo,
) -> Vec<DkgCommand> {
if self.sessions.contains_key(&dkg_key) {
trace!("DKG for {} already in progress", section_auth);
trace!("DKG for {:?} already in progress", elders_info);
return vec![];
}

let name = crypto::name(&keypair.public);
let participant_index = if let Some(index) = section_auth.position(&name) {
let participant_index = if let Some(index) = elders_info.position(&name) {
index
} else {
error!(
"DKG for {} failed to start: {} is not a participant",
section_auth, name
"DKG for {:?} failed to start: {} is not a participant",
elders_info, name
);
return vec![];
};

// Special case: only one participant.
if section_auth.elders.len() == 1 {
if elders_info.elders.len() == 1 {
let secret_key_set = bls::SecretKeySet::random(0, &mut rand::thread_rng());

let section_auth = SectionAuthorityProvider::from_elders_info(
elders_info,
secret_key_set.public_keys(),
);
return vec![DkgCommand::HandleOutcome {
section_auth,
outcome: SectionKeyShare {
Expand All @@ -138,16 +141,16 @@ impl DkgVoter {
}];
}

let threshold = supermajority(section_auth.elders.len()) - 1;
let participants = section_auth.elders.keys().copied().collect();
let threshold = supermajority(elders_info.elders.len()) - 1;
let participants = elders_info.elders.keys().copied().collect();

match KeyGen::initialize(name, threshold, participants) {
Ok((key_gen, message)) => {
trace!("DKG for {} starting", section_auth);
trace!("DKG for {:?} starting", elders_info);

let mut session = Session {
key_gen,
section_auth,
elders_info,
participant_index,
timer_token: 0,
failures: DkgFailureProofSet::default(),
Expand Down Expand Up @@ -175,7 +178,7 @@ impl DkgVoter {
}
Err(error) => {
// TODO: return a separate error here.
error!("DKG for {} failed to start: {}", section_auth, error);
error!("DKG for {:?} failed to start: {}", elders_info, error);
vec![]
}
}
Expand Down Expand Up @@ -223,7 +226,7 @@ impl DkgVoter {

// Data for a DKG participant.
struct Session {
section_auth: SectionAuthorityProvider,
elders_info: EldersInfo,
participant_index: usize,
key_gen: KeyGen,
timer_token: u64,
Expand Down Expand Up @@ -264,7 +267,7 @@ impl Session {
}

fn recipients(&self) -> Vec<SocketAddr> {
self.section_auth
self.elders_info
.elders
.values()
.enumerate()
Expand Down Expand Up @@ -300,7 +303,7 @@ impl Session {
return vec![];
}

trace!("DKG for {} progressing", self.section_auth);
trace!("DKG for {:?} progressing", self.elders_info);

match self.key_gen.timed_phase_transition(&mut rand::thread_rng()) {
Ok(messages) => {
Expand All @@ -313,7 +316,7 @@ impl Session {
commands
}
Err(error) => {
trace!("DKG for {} failed: {}", self.section_auth, error);
trace!("DKG for {:?} failed: {}", self.elders_info, error);
self.report_failure(dkg_key, BTreeSet::new(), keypair)
}
}
Expand All @@ -336,15 +339,15 @@ impl Session {
};

// Less than 100% participation
if !participants.iter().eq(self.section_auth.elders.keys()) {
if !participants.iter().eq(self.elders_info.elders.keys()) {
trace!(
"DKG for {} failed: unexpected participants: {:?}",
self.section_auth,
"DKG for {:?} failed: unexpected participants: {:?}",
self.elders_info,
participants.iter().format(", ")
);

let non_participants: BTreeSet<_> = self
.section_auth
.elders_info
.elders
.keys()
.filter_map(|elder| {
Expand All @@ -368,17 +371,21 @@ impl Session {
.public_key_share(self.participant_index)
!= outcome.secret_key_share.public_key_share()
{
trace!("DKG for {} failed: corrupted outcome", self.section_auth);
trace!("DKG for {:?} failed: corrupted outcome", self.elders_info);
return self.report_failure(dkg_key, BTreeSet::new(), keypair);
}

trace!(
"DKG for {} complete: {:?}",
self.section_auth,
"DKG for {:?} complete: {:?}",
self.elders_info,
outcome.public_key_set.public_key()
);

self.complete = true;
let section_auth = SectionAuthorityProvider::from_elders_info(
self.elders_info.clone(),
outcome.public_key_set.clone(),
);

let outcome = SectionKeyShare {
public_key_set: outcome.public_key_set,
Expand All @@ -387,7 +394,7 @@ impl Session {
};

vec![DkgCommand::HandleOutcome {
section_auth: self.section_auth.clone(),
section_auth,
outcome,
}]
}
Expand Down Expand Up @@ -422,7 +429,7 @@ impl Session {
proof: DkgFailureProof,
) -> Option<DkgCommand> {
if !self
.section_auth
.elders_info
.elders
.contains_key(&crypto::name(&proof.public_key))
{
Expand All @@ -441,7 +448,7 @@ impl Session {
}

fn check_failure_agreement(&mut self) -> Option<DkgCommand> {
if self.failures.has_agreement(&self.section_auth) {
if self.failures.has_agreement(&self.elders_info) {
self.complete = true;

Some(DkgCommand::HandleFailureAgreement(mem::take(
Expand Down Expand Up @@ -508,27 +515,27 @@ impl DkgFailureProofSet {

// Check whether we have enough proofs to reach agreement on the failure. The contained proofs
// are assumed valid.
fn has_agreement(&self, section_auth: &SectionAuthorityProvider) -> bool {
has_failure_agreement(section_auth.elders.len(), self.proofs.len())
fn has_agreement(&self, elders_info: &EldersInfo) -> bool {
has_failure_agreement(elders_info.elders.len(), self.proofs.len())
}

pub fn verify(&self, section_auth: &SectionAuthorityProvider, generation: u64) -> bool {
pub fn verify(&self, elders_info: &EldersInfo, generation: u64) -> bool {
let hash = failure_proof_hash(
&DkgKey::new(section_auth, generation),
&DkgKey::new(elders_info, generation),
&self.non_participants,
);
let votes = self
.proofs
.iter()
.filter(|proof| {
section_auth
elders_info
.elders
.contains_key(&crypto::name(&proof.public_key))
})
.filter(|proof| proof.public_key.verify(&hash, &proof.signature).is_ok())
.count();

has_failure_agreement(section_auth.elders.len(), votes)
has_failure_agreement(elders_info.elders.len(), votes)
}
}

Expand Down Expand Up @@ -710,11 +717,10 @@ mod tests {
crypto::gen_keypair(&Prefix::default().range_inclusive(), MIN_ADULT_AGE),
gen_addr(),
);
let section_auth =
SectionAuthorityProvider::new(iter::once(node.peer()), Prefix::default());
let dkg_key = DkgKey::new(&section_auth, 0);
let elders_info = EldersInfo::new(iter::once(node.peer()), Prefix::default());
let dkg_key = DkgKey::new(&elders_info, 0);

let commands = voter.start(&node.keypair, dkg_key, section_auth);
let commands = voter.start(&node.keypair, dkg_key, elders_info);
assert_matches!(&commands[..], &[DkgCommand::HandleOutcome { .. }]);
}

Expand All @@ -733,9 +739,8 @@ mod tests {
let mut rng = SmallRng::seed_from_u64(seed);
let mut messages = Vec::new();

let section_auth =
SectionAuthorityProvider::new(nodes.iter().map(Node::peer), Prefix::default());
let dkg_key = DkgKey::new(&section_auth, 0);
let elders_info = EldersInfo::new(nodes.iter().map(Node::peer), Prefix::default());
let dkg_key = DkgKey::new(&elders_info, 0);

let mut actors: HashMap<_, _> = nodes
.into_iter()
Expand All @@ -745,7 +750,7 @@ mod tests {
for actor in actors.values_mut() {
let commands = actor
.voter
.start(&actor.node.keypair, dkg_key, section_auth.clone());
.start(&actor.node.keypair, dkg_key, elders_info.clone());

for command in commands {
messages.extend(actor.handle(command, &dkg_key))
Expand Down
Loading

0 comments on commit 7d2d476

Please sign in to comment.