mirror of https://github.com/poanetwork/hbbft.git
Merge pull request #79 from poanetwork/afck-keygen-node-id
Make SyncKeyGen NodeUid-aware.
This commit is contained in:
commit
8afcc46227
|
@ -104,7 +104,7 @@ impl Signature {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A secret key, or a secret key share.
|
/// A secret key, or a secret key share.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct SecretKey(Fr);
|
pub struct SecretKey(Fr);
|
||||||
|
|
||||||
impl Default for SecretKey {
|
impl Default for SecretKey {
|
||||||
|
|
|
@ -390,8 +390,8 @@ impl BivarPoly {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A commitment to a bivariate polynomial.
|
/// A commitment to a symmetric bivariate polynomial.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct BivarCommitment {
|
pub struct BivarCommitment {
|
||||||
/// The polynomial's degree in each of the two variables.
|
/// The polynomial's degree in each of the two variables.
|
||||||
degree: usize,
|
degree: usize,
|
||||||
|
|
|
@ -3,12 +3,11 @@ use std::collections::{BTreeMap, BTreeSet, HashSet, VecDeque};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::{cmp, iter};
|
use std::{cmp, iter, mem};
|
||||||
|
|
||||||
use bincode;
|
use bincode;
|
||||||
use rand;
|
use rand;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::{Deserialize, Serialize};
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use common_subset::{self, CommonSubset};
|
use common_subset::{self, CommonSubset};
|
||||||
use crypto::{Ciphertext, DecryptionShare};
|
use crypto::{Ciphertext, DecryptionShare};
|
||||||
|
@ -63,7 +62,7 @@ pub struct HoneyBadger<Tx, NodeUid> {
|
||||||
|
|
||||||
impl<Tx, NodeUid> DistAlgorithm for HoneyBadger<Tx, NodeUid>
|
impl<Tx, NodeUid> DistAlgorithm for HoneyBadger<Tx, NodeUid>
|
||||||
where
|
where
|
||||||
Tx: Eq + Hash + Serialize + DeserializeOwned + Debug,
|
Tx: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
|
||||||
NodeUid: Ord + Clone + Debug,
|
NodeUid: Ord + Clone + Debug,
|
||||||
{
|
{
|
||||||
type NodeUid = NodeUid;
|
type NodeUid = NodeUid;
|
||||||
|
@ -119,7 +118,7 @@ where
|
||||||
// TODO: Use a threshold encryption scheme to encrypt the proposed transactions.
|
// TODO: Use a threshold encryption scheme to encrypt the proposed transactions.
|
||||||
impl<Tx, NodeUid> HoneyBadger<Tx, NodeUid>
|
impl<Tx, NodeUid> HoneyBadger<Tx, NodeUid>
|
||||||
where
|
where
|
||||||
Tx: Eq + Hash + Serialize + DeserializeOwned + Debug,
|
Tx: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
|
||||||
NodeUid: Ord + Clone + Debug,
|
NodeUid: Ord + Clone + Debug,
|
||||||
{
|
{
|
||||||
/// Returns a new Honey Badger instance with the given parameters, starting at epoch `0`.
|
/// Returns a new Honey Badger instance with the given parameters, starting at epoch `0`.
|
||||||
|
@ -156,6 +155,11 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Empties and returns the transaction buffer.
|
||||||
|
pub fn drain_buffer(&mut self) -> Vec<Tx> {
|
||||||
|
mem::replace(&mut self.buffer, Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
/// Proposes a new batch in the current epoch.
|
/// Proposes a new batch in the current epoch.
|
||||||
fn propose(&mut self) -> HoneyBadgerResult<()> {
|
fn propose(&mut self) -> HoneyBadgerResult<()> {
|
||||||
let proposal = self.choose_transactions()?;
|
let proposal = self.choose_transactions()?;
|
||||||
|
|
|
@ -136,7 +136,7 @@ impl<'a, D: DistAlgorithm + 'a> Iterator for OutputIter<'a, D> {
|
||||||
/// use this construction to zero out the section of heap memory that is
|
/// use this construction to zero out the section of heap memory that is
|
||||||
/// allocated for `secret_key` when the corresponding instance of
|
/// allocated for `secret_key` when the corresponding instance of
|
||||||
/// `NetworkInfo` goes out of scope.
|
/// `NetworkInfo` goes out of scope.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NetworkInfo<NodeUid> {
|
pub struct NetworkInfo<NodeUid> {
|
||||||
our_uid: NodeUid,
|
our_uid: NodeUid,
|
||||||
all_uids: BTreeSet<NodeUid>,
|
all_uids: BTreeSet<NodeUid>,
|
||||||
|
|
|
@ -34,25 +34,27 @@
|
||||||
|
|
||||||
use std::collections::btree_map::Entry;
|
use std::collections::btree_map::Entry;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use bincode;
|
||||||
|
use clear_on_drop::ClearOnDrop;
|
||||||
|
use pairing::bls12_381::{Fr, G1Affine};
|
||||||
|
use pairing::{CurveAffine, Field};
|
||||||
|
use rand::OsRng;
|
||||||
|
|
||||||
use crypto::poly::{BivarCommitment, BivarPoly, Poly};
|
use crypto::poly::{BivarCommitment, BivarPoly, Poly};
|
||||||
use crypto::serde_impl::field_vec::FieldWrap;
|
use crypto::serde_impl::field_vec::FieldWrap;
|
||||||
use crypto::{Ciphertext, PublicKey, PublicKeySet, SecretKey};
|
use crypto::{Ciphertext, PublicKey, PublicKeySet, SecretKey};
|
||||||
|
|
||||||
use bincode;
|
|
||||||
use pairing::bls12_381::{Fr, G1Affine};
|
|
||||||
use pairing::{CurveAffine, Field};
|
|
||||||
use rand::OsRng;
|
|
||||||
|
|
||||||
// TODO: No need to send our own row and value to ourselves.
|
// TODO: No need to send our own row and value to ourselves.
|
||||||
|
|
||||||
/// A commitment to a bivariate polynomial, and for each node, an encrypted row of values.
|
/// A commitment to a bivariate polynomial, and for each node, an encrypted row of values.
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
#[derive(Deserialize, Serialize, Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct Propose(BivarCommitment, Vec<Ciphertext>);
|
pub struct Propose(BivarCommitment, Vec<Ciphertext>);
|
||||||
|
|
||||||
/// A confirmation that we have received a node's proposal and verified our row against the
|
/// A confirmation that we have received a node's proposal and verified our row against the
|
||||||
/// commitment. For each node, it contains one encrypted value of our row.
|
/// commitment. For each node, it contains one encrypted value of our row.
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
#[derive(Deserialize, Serialize, Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct Accept(u64, Vec<Ciphertext>);
|
pub struct Accept(u64, Vec<Ciphertext>);
|
||||||
|
|
||||||
/// The information needed to track a single proposer's secret sharing process.
|
/// The information needed to track a single proposer's secret sharing process.
|
||||||
|
@ -84,33 +86,37 @@ impl ProposalState {
|
||||||
/// A synchronous algorithm for dealerless distributed key generation.
|
/// A synchronous algorithm for dealerless distributed key generation.
|
||||||
///
|
///
|
||||||
/// It requires that all nodes handle all messages in the exact same order.
|
/// It requires that all nodes handle all messages in the exact same order.
|
||||||
pub struct SyncKeyGen {
|
pub struct SyncKeyGen<NodeUid> {
|
||||||
/// Our node index.
|
/// Our node index.
|
||||||
our_idx: u64,
|
our_idx: u64,
|
||||||
/// Our secret key.
|
/// Our secret key.
|
||||||
sec_key: SecretKey,
|
sec_key: SecretKey,
|
||||||
/// The public keys of all nodes, by node index.
|
/// The public keys of all nodes, by node index.
|
||||||
pub_keys: Vec<PublicKey>,
|
pub_keys: BTreeMap<NodeUid, PublicKey>,
|
||||||
/// Proposed bivariate polynomial.
|
/// Proposed bivariate polynomial.
|
||||||
proposals: BTreeMap<u64, ProposalState>,
|
proposals: BTreeMap<u64, ProposalState>,
|
||||||
/// The degree of the generated polynomial.
|
/// The degree of the generated polynomial.
|
||||||
threshold: usize,
|
threshold: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SyncKeyGen {
|
impl<NodeUid: Ord + Debug> SyncKeyGen<NodeUid> {
|
||||||
/// Creates a new `SyncKeyGen` instance, together with the `Propose` message that should be
|
/// Creates a new `SyncKeyGen` instance, together with the `Propose` message that should be
|
||||||
/// broadcast.
|
/// broadcast.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
our_idx: u64,
|
our_uid: &NodeUid,
|
||||||
sec_key: SecretKey,
|
sec_key: SecretKey,
|
||||||
pub_keys: Vec<PublicKey>,
|
pub_keys: BTreeMap<NodeUid, PublicKey>,
|
||||||
threshold: usize,
|
threshold: usize,
|
||||||
) -> (SyncKeyGen, Propose) {
|
) -> (SyncKeyGen<NodeUid>, Propose) {
|
||||||
|
let our_idx = pub_keys
|
||||||
|
.keys()
|
||||||
|
.position(|uid| uid == our_uid)
|
||||||
|
.expect("missing pub key for own ID") as u64;
|
||||||
let mut rng = OsRng::new().expect("OS random number generator");
|
let mut rng = OsRng::new().expect("OS random number generator");
|
||||||
let our_proposal = BivarPoly::random(threshold, &mut rng);
|
let our_proposal = BivarPoly::random(threshold, &mut rng);
|
||||||
let commit = our_proposal.commitment();
|
let commit = our_proposal.commitment();
|
||||||
let rows: Vec<_> = pub_keys
|
let rows: Vec<_> = pub_keys
|
||||||
.iter()
|
.values()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, pk)| {
|
.map(|(i, pk)| {
|
||||||
let row = our_proposal.row(i as u64 + 1);
|
let row = our_proposal.row(i as u64 + 1);
|
||||||
|
@ -131,9 +137,16 @@ impl SyncKeyGen {
|
||||||
/// Handles a `Propose` message. If it is valid, returns an `Accept` message to be broadcast.
|
/// Handles a `Propose` message. If it is valid, returns an `Accept` message to be broadcast.
|
||||||
pub fn handle_propose(
|
pub fn handle_propose(
|
||||||
&mut self,
|
&mut self,
|
||||||
sender_idx: u64,
|
sender_id: &NodeUid,
|
||||||
Propose(commit, rows): Propose,
|
Propose(commit, rows): Propose,
|
||||||
) -> Option<Accept> {
|
) -> Option<Accept> {
|
||||||
|
let sender_idx =
|
||||||
|
if let Some(sender_idx) = self.pub_keys.keys().position(|uid| uid == sender_id) {
|
||||||
|
sender_idx as u64
|
||||||
|
} else {
|
||||||
|
debug!("Unknown sender {:?}", sender_id);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
let commit_row = commit.row(self.our_idx + 1);
|
let commit_row = commit.row(self.our_idx + 1);
|
||||||
match self.proposals.entry(sender_idx) {
|
match self.proposals.entry(sender_idx) {
|
||||||
Entry::Occupied(_) => return None, // Ignore multiple proposals.
|
Entry::Occupied(_) => return None, // Ignore multiple proposals.
|
||||||
|
@ -150,7 +163,7 @@ impl SyncKeyGen {
|
||||||
// The row is valid: now encrypt one value for each node.
|
// The row is valid: now encrypt one value for each node.
|
||||||
let values = self
|
let values = self
|
||||||
.pub_keys
|
.pub_keys
|
||||||
.iter()
|
.values()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, pk)| {
|
.map(|(idx, pk)| {
|
||||||
let val = row.evaluate(idx as u64 + 1);
|
let val = row.evaluate(idx as u64 + 1);
|
||||||
|
@ -163,7 +176,14 @@ impl SyncKeyGen {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles an `Accept` message.
|
/// Handles an `Accept` message.
|
||||||
pub fn handle_accept(&mut self, sender_idx: u64, accept: Accept) {
|
pub fn handle_accept(&mut self, sender_id: &NodeUid, accept: Accept) {
|
||||||
|
let sender_idx =
|
||||||
|
if let Some(sender_idx) = self.pub_keys.keys().position(|uid| uid == sender_id) {
|
||||||
|
sender_idx as u64
|
||||||
|
} else {
|
||||||
|
debug!("Unknown sender {:?}", sender_id);
|
||||||
|
return;
|
||||||
|
};
|
||||||
if let Err(err) = self.handle_accept_or_err(sender_idx, accept) {
|
if let Err(err) = self.handle_accept_or_err(sender_idx, accept) {
|
||||||
debug!("Invalid accept from node {}: {}", sender_idx, err);
|
debug!("Invalid accept from node {}: {}", sender_idx, err);
|
||||||
}
|
}
|
||||||
|
@ -194,7 +214,7 @@ impl SyncKeyGen {
|
||||||
///
|
///
|
||||||
/// These are only secure if `is_ready` returned `true`. Otherwise it is not guaranteed that
|
/// These are only secure if `is_ready` returned `true`. Otherwise it is not guaranteed that
|
||||||
/// none of the nodes knows the secret master key.
|
/// none of the nodes knows the secret master key.
|
||||||
pub fn generate(&self) -> (PublicKeySet, SecretKey) {
|
pub fn generate(&self) -> (PublicKeySet, ClearOnDrop<Box<SecretKey>>) {
|
||||||
let mut pk_commit = Poly::zero().commitment();
|
let mut pk_commit = Poly::zero().commitment();
|
||||||
let mut sk_val = Fr::zero();
|
let mut sk_val = Fr::zero();
|
||||||
for proposal in self
|
for proposal in self
|
||||||
|
@ -206,7 +226,8 @@ impl SyncKeyGen {
|
||||||
let row: Poly = Poly::interpolate(proposal.values.iter().take(self.threshold + 1));
|
let row: Poly = Poly::interpolate(proposal.values.iter().take(self.threshold + 1));
|
||||||
sk_val.add_assign(&row.evaluate(0));
|
sk_val.add_assign(&row.evaluate(0));
|
||||||
}
|
}
|
||||||
(pk_commit.into(), SecretKey::from_value(sk_val))
|
let sk = ClearOnDrop::new(Box::new(SecretKey::from_value(sk_val)));
|
||||||
|
(pk_commit.into(), sk)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles an `Accept` message or returns an error string.
|
/// Handles an `Accept` message or returns an error string.
|
||||||
|
|
|
@ -19,6 +19,8 @@ extern crate hbbft;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
mod network;
|
mod network;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ extern crate log;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
mod network;
|
mod network;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ extern crate hbbft;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
mod network;
|
mod network;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ extern crate hbbft;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
mod network;
|
mod network;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ extern crate log;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
mod network;
|
mod network;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use hbbft::crypto::SecretKeySet;
|
||||||
use hbbft::messaging::{DistAlgorithm, NetworkInfo, Target, TargetedMessage};
|
use hbbft::messaging::{DistAlgorithm, NetworkInfo, Target, TargetedMessage};
|
||||||
|
|
||||||
/// A node identifier. In the tests, nodes are simply numbered.
|
/// A node identifier. In the tests, nodes are simply numbered.
|
||||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)]
|
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub struct NodeUid(pub usize);
|
pub struct NodeUid(pub usize);
|
||||||
|
|
||||||
/// A "node" running an instance of the algorithm `D`.
|
/// A "node" running an instance of the algorithm `D`.
|
||||||
|
|
|
@ -15,16 +15,19 @@ fn test_sync_key_gen_with(threshold: usize, node_num: usize) {
|
||||||
|
|
||||||
// Generate individual key pairs for encryption. These are not suitable for threshold schemes.
|
// Generate individual key pairs for encryption. These are not suitable for threshold schemes.
|
||||||
let sec_keys: Vec<SecretKey> = (0..node_num).map(|_| SecretKey::new(&mut rng)).collect();
|
let sec_keys: Vec<SecretKey> = (0..node_num).map(|_| SecretKey::new(&mut rng)).collect();
|
||||||
let pub_keys: Vec<PublicKey> = sec_keys.iter().map(|sk| sk.public_key()).collect();
|
let pub_keys: BTreeMap<usize, PublicKey> = sec_keys
|
||||||
|
.iter()
|
||||||
|
.map(|sk| sk.public_key())
|
||||||
|
.enumerate()
|
||||||
|
.collect();
|
||||||
|
|
||||||
// Create the `SyncKeyGen` instances and initial proposals.
|
// Create the `SyncKeyGen` instances and initial proposals.
|
||||||
let mut nodes = Vec::new();
|
let mut nodes = Vec::new();
|
||||||
let proposals: Vec<_> = sec_keys
|
let proposals: Vec<_> = sec_keys
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, sk)| {
|
.map(|(id, sk)| {
|
||||||
let (sync_key_gen, proposal) =
|
let (sync_key_gen, proposal) = SyncKeyGen::new(&id, sk, pub_keys.clone(), threshold);
|
||||||
SyncKeyGen::new(idx as u64, sk, pub_keys.clone(), threshold);
|
|
||||||
nodes.push(sync_key_gen);
|
nodes.push(sync_key_gen);
|
||||||
proposal
|
proposal
|
||||||
})
|
})
|
||||||
|
@ -32,23 +35,23 @@ fn test_sync_key_gen_with(threshold: usize, node_num: usize) {
|
||||||
|
|
||||||
// Handle the first `threshold + 1` proposals. Those should suffice for key generation.
|
// Handle the first `threshold + 1` proposals. Those should suffice for key generation.
|
||||||
let mut accepts = Vec::new();
|
let mut accepts = Vec::new();
|
||||||
for (sender_idx, proposal) in proposals[..=threshold].iter().enumerate() {
|
for (sender_id, proposal) in proposals[..=threshold].iter().enumerate() {
|
||||||
for (node_idx, node) in nodes.iter_mut().enumerate() {
|
for (node_id, node) in nodes.iter_mut().enumerate() {
|
||||||
let accept = node
|
let accept = node
|
||||||
.handle_propose(sender_idx as u64, proposal.clone())
|
.handle_propose(&sender_id, proposal.clone())
|
||||||
.expect("valid proposal");
|
.expect("valid proposal");
|
||||||
// Only the first `threshold + 1` manage to commit their `Accept`s.
|
// Only the first `threshold + 1` manage to commit their `Accept`s.
|
||||||
if node_idx <= 2 * threshold {
|
if node_id <= 2 * threshold {
|
||||||
accepts.push((node_idx, accept));
|
accepts.push((node_id, accept));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the `Accept`s from `2 * threshold + 1` nodes.
|
// Handle the `Accept`s from `2 * threshold + 1` nodes.
|
||||||
for (sender_idx, accept) in accepts {
|
for (sender_id, accept) in accepts {
|
||||||
for node in &mut nodes {
|
for node in &mut nodes {
|
||||||
assert!(!node.is_ready()); // Not enough `Accept`s yet.
|
assert!(!node.is_ready()); // Not enough `Accept`s yet.
|
||||||
node.handle_accept(sender_idx as u64, accept.clone());
|
node.handle_accept(&sender_id, accept.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue