Skip to content

Commit

Permalink
Merge pull request #73 from anoma/bat/announcement-refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
joebebel committed Dec 15, 2021
2 parents 2d8026b + d3fb002 commit 9786ac0
Show file tree
Hide file tree
Showing 7 changed files with 455 additions and 658 deletions.
124 changes: 76 additions & 48 deletions ferveo-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,73 +1,101 @@
use anyhow::{anyhow, Result};
use anyhow::Result;
use ark_ec::PairingEngine;
use ark_serialize::{
CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write,
};

pub mod keypair;
pub use keypair::*;
use std::cmp::Ordering;

#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)]
/// Represents a tendermint validator
pub struct TendermintValidator<E: PairingEngine> {
/// Total voting power in tendermint consensus
pub power: u64,
/// The established address of the validator
pub address: String,
/// The Public key
pub public_key: PublicKey<E>,
}

impl<E: PairingEngine> PartialEq for TendermintValidator<E> {
fn eq(&self, other: &Self) -> bool {
(self.power, &self.address) == (other.power, &other.address)
}
}

impl<E: PairingEngine> Eq for TendermintValidator<E> {}

impl<E: PairingEngine> PartialOrd for TendermintValidator<E> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some((self.power, &self.address).cmp(&(other.power, &other.address)))
}
}

impl<E: PairingEngine> Ord for TendermintValidator<E> {
fn cmp(&self, other: &Self) -> Ordering {
(self.power, &self.address).cmp(&(other.power, &other.address))
}
}

#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)]
/// The set of tendermint validators for a dkg instance
pub struct ValidatorSet<E: PairingEngine> {
pub validators: Vec<TendermintValidator<E>>,
}

impl<E: PairingEngine> ValidatorSet<E> {
/// Sorts the validators from highest to lowest. This ordering
/// first considers staking weight and breaks ties on established
/// address
pub fn new(mut validators: Vec<TendermintValidator<E>>) -> Self {
// reverse the ordering here
validators.sort_by(|a, b| b.cmp(a));
Self { validators }
}

/// Get the total voting power of the validator set
pub fn total_voting_power(&self) -> u64 {
self.validators.iter().map(|v| v.power).sum()
}
}

#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)]
pub struct Validator<E: PairingEngine> {
pub key: ValidatorPublicKey<E>,
pub validator: TendermintValidator<E>,
pub weight: u32,
pub share_start: usize,
pub share_end: usize,
}

impl<E: PairingEngine> Validator<E> {
pub fn encryption_key(&self) -> Result<E::G2Affine> {
match self.key {
ValidatorPublicKey::Announced(key) => Ok(key.encryption_key),
ValidatorPublicKey::Unannounced => Err(anyhow!(
"The encryption key for this validator was not announced"
)),
}
impl<E: PairingEngine> PartialEq for Validator<E> {
fn eq(&self, other: &Self) -> bool {
(
&self.validator,
self.weight,
self.share_start,
self.share_end,
) == (
&other.validator,
other.weight,
other.share_start,
other.share_end,
)
}
}

/// Initially we do not know the ephemeral public keys
/// of participating validators. We only learn these
/// as they are announced.
#[derive(Clone, Debug)]
pub enum ValidatorPublicKey<E: PairingEngine> {
Announced(PublicKey<E>),
Unannounced,
}

impl<E: PairingEngine> CanonicalSerialize for ValidatorPublicKey<E> {
#[inline]
fn serialize<W: Write>(
&self,
mut writer: W,
) -> Result<(), SerializationError> {
match self {
Self::Announced(key) => Some(*key),
Self::Unannounced => None,
}
.serialize(&mut writer)
}
impl<E: PairingEngine> Eq for Validator<E> {}

#[inline]
fn serialized_size(&self) -> usize {
match self {
Self::Announced(key) => Some(*key),
Self::Unannounced => None,
}
.serialized_size()
impl<E: PairingEngine> PartialOrd for Validator<E> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.validator.cmp(&other.validator))
}
}

impl<E: PairingEngine> CanonicalDeserialize for ValidatorPublicKey<E> {
#[inline]
fn deserialize<R: Read>(mut reader: R) -> Result<Self, SerializationError> {
let is_some = bool::deserialize(&mut reader)?;
let data = if is_some {
Self::Announced(PublicKey::<E>::deserialize(&mut reader)?)
} else {
Self::Unannounced
};
Ok(data)
impl<E: PairingEngine> Ord for Validator<E> {
fn cmp(&self, other: &Self) -> Ordering {
self.validator.cmp(&other.validator)
}
}

Expand Down
57 changes: 22 additions & 35 deletions ferveo/benches/benchmarks/pvdkg.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
pub use ark_bls12_381::Bls12_381 as EllipticCurve;
use criterion::{criterion_group, criterion_main, Criterion};
use ferveo_common::{ValidatorSet, TendermintValidator};
use pprof::criterion::{Output, PProfProfiler};

use ferveo::*;

pub fn dkgs(c: &mut Criterion) {
Expand All @@ -26,8 +29,6 @@ pub fn dkgs(c: &mut Criterion) {
group.bench_function("PVDKG BLS12-381", |b| b.iter(|| setup_dealt_dkg(10)));
}

use pprof::criterion::{Output, PProfProfiler};

criterion_group! {
name = pvdkg_bls;
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
Expand All @@ -36,13 +37,22 @@ criterion_group! {

criterion_main!(pvdkg_bls);

/// Generate a set of keypairs for each validator
pub fn gen_keypairs(num: u64) -> Vec<ferveo_common::Keypair<EllipticCurve>> {
let rng = &mut ark_std::test_rng();
(0..num)
.map(|_| ferveo_common::Keypair::<EllipticCurve>::new(rng))
.collect()
}

/// Generate a few validators
pub fn gen_validators(num: u64) -> ValidatorSet {
pub fn gen_validators(keypairs: &[ferveo_common::Keypair<EllipticCurve>]) -> ValidatorSet<EllipticCurve> {
ValidatorSet::new(
(0..num)
(0..keypairs.len())
.map(|i| TendermintValidator {
power: i,
power: i as u64,
address: format!("validator_{}", i),
public_key: keypairs[i as usize].public(),
})
.collect(),
)
Expand All @@ -53,61 +63,38 @@ pub fn setup_dkg(
validator: usize,
num: u64,
) -> PubliclyVerifiableDkg<EllipticCurve> {
let rng = &mut ark_std::test_rng();
let validators = gen_validators(num);
let keypairs = gen_keypairs(num);
let validators = gen_validators(&keypairs);
let me = validators.validators[validator].clone();
PubliclyVerifiableDkg::new(
validators,
Params {
tau: 0,
security_threshold: 300 / 3,
total_weight: 300,
retry_after: 2,
},
me,
rng,
keypairs[validator].clone(),
)
.expect("Setup failed")
}

/// Setup a dkg instance with all announcements received
pub fn setup_shared_dkg(
validator: usize,
num: u64,
) -> PubliclyVerifiableDkg<EllipticCurve> {
let rng = &mut ark_std::test_rng();
let mut dkg = setup_dkg(validator, num);

// generated the announcements for all other validators
for i in 0..num {
if i as usize == validator {
continue;
}
let announce = Message::Announce(
ferveo_common::Keypair::<EllipticCurve>::new(rng).public(),
);
let sender = dkg.validator_set.validators[i as usize].clone();
dkg.verify_message(&sender, &announce, rng)
.expect("Setup failed");
dkg.apply_message(sender, announce).expect("Setup failed");
}
dkg
}

/// Set up a dkg with enough pvss transcripts to meet the threshold
pub fn setup_dealt_dkg(num: u64) {
let rng = &mut ark_std::test_rng();
// gather everyone's transcripts
let mut transcripts = vec![];
for i in 0..num {
let mut dkg = setup_shared_dkg(i as usize, num);
let mut dkg = setup_dkg(i as usize, num);
transcripts.push(dkg.share(rng).expect("Test failed"));
}
// our test dkg
let mut dkg = setup_shared_dkg(0, num);
let mut dkg = setup_dkg(0, num);
// iterate over transcripts from lowest weight to highest
for (sender, pvss) in transcripts.into_iter().rev().enumerate() {
dkg.apply_message(
dkg.validator_set.validators[num as usize - 1 - sender].clone(),
dkg.validators[num as usize - 1 - sender].validator.clone(),
pvss,
)
.expect("Setup failed");
Expand Down
56 changes: 22 additions & 34 deletions ferveo/examples/pvdkg.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub use ark_bls12_381::Bls12_381 as EllipticCurve;
use ferveo::*;
use ferveo_common::{TendermintValidator, ValidatorSet};
use measure_time::print_time;

pub fn main() {
Expand All @@ -9,13 +10,24 @@ pub fn main() {
setup_dealt_dkg(10, 8192);
}

/// Generate a set of keypairs for each validator
pub fn gen_keypairs(num: u64) -> Vec<ferveo_common::Keypair<EllipticCurve>> {
let rng = &mut ark_std::test_rng();
(0..num)
.map(|_| ferveo_common::Keypair::<EllipticCurve>::new(rng))
.collect()
}

/// Generate a few validators
pub fn gen_validators(num: u64) -> ValidatorSet {
pub fn gen_validators(
keypairs: &[ferveo_common::Keypair<EllipticCurve>],
) -> ValidatorSet<EllipticCurve> {
ValidatorSet::new(
(0..num)
(0..keypairs.len())
.map(|i| TendermintValidator {
power: i,
power: i as u64,
address: format!("validator_{}", i),
public_key: keypairs[i as usize].public(),
})
.collect(),
)
Expand All @@ -27,66 +39,42 @@ pub fn setup_dkg(
num: u64,
shares: u32,
) -> PubliclyVerifiableDkg<EllipticCurve> {
let rng = &mut ark_std::test_rng();
let validators = gen_validators(num);
let keypairs = gen_keypairs(num);
let validators = gen_validators(&keypairs);
let me = validators.validators[validator].clone();
PubliclyVerifiableDkg::new(
validators,
Params {
tau: 0,
security_threshold: shares / 3,
total_weight: shares,
retry_after: 1,
},
me,
rng,
keypairs[validator].clone(),
)
.expect("Setup failed")
}

/// Setup a dkg instance with all announcements received
pub fn setup_shared_dkg(
validator: usize,
num: u64,
shares: u32,
) -> PubliclyVerifiableDkg<EllipticCurve> {
let rng = &mut ark_std::test_rng();
let mut dkg = setup_dkg(validator, num, shares);

// generated the announcements for all other validators
for i in 0..num {
if i as usize == validator {
continue;
}
let announce = Message::Announce(
ferveo_common::Keypair::<EllipticCurve>::new(rng).public(),
);
let sender = dkg.validator_set.validators[i as usize].clone();
dkg.verify_message(&sender, &announce, rng)
.expect("Setup failed");
dkg.apply_message(sender, announce).expect("Setup failed");
}
dkg
}

/// Set up a dkg with enough pvss transcripts to meet the threshold
pub fn setup_dealt_dkg(num: u64, shares: u32) {
let rng = &mut ark_std::test_rng();
// gather everyone's transcripts
let mut transcripts = vec![];
for i in 0..num {
let mut dkg = setup_shared_dkg(i as usize, num, shares);
let mut dkg = setup_dkg(i as usize, num, shares);
transcripts.push(dkg.share(rng).expect("Test failed"));
}
// our test dkg
let mut dkg = setup_shared_dkg(0, num, shares);
let mut dkg = setup_dkg(0, num, shares);
// iterate over transcripts from lowest weight to highest
for (sender, pvss) in transcripts.into_iter().rev().enumerate() {
if let Message::Deal(ss) = pvss.clone() {
print_time!("PVSS verify pvdkg");
ss.verify_full(&dkg, rng);
}
dkg.apply_message(
dkg.validator_set.validators[num as usize - 1 - sender].clone(),
dkg.validators[num as usize - 1 - sender].validator.clone(),
pvss,
)
.expect("Setup failed");
Expand Down
Loading

0 comments on commit 9786ac0

Please sign in to comment.