Dedicated Commit object

Restores sig aggregation API.
This commit is contained in:
Luke Parker 2022-10-17 03:15:13 -04:00
parent b993ff1cc8
commit 6155d12160
No known key found for this signature in database
GPG key ID: F9F1386DB1E119B6
3 changed files with 63 additions and 20 deletions

View file

@ -31,6 +31,21 @@ pub trait SignatureScheme: Send + Sync {
fn sign(&self, msg: &[u8]) -> Self::Signature;
#[must_use]
fn verify(&self, validator: Self::ValidatorId, msg: &[u8], sig: Self::Signature) -> bool;
fn aggregate(sigs: &[Self::Signature]) -> Self::AggregateSignature;
#[must_use]
fn verify_aggregate(
&self,
msg: &[u8],
signers: &[Self::ValidatorId],
sig: Self::AggregateSignature,
) -> bool;
}
#[derive(Clone, PartialEq, Debug, Encode, Decode)]
pub struct Commit<S: SignatureScheme> {
pub validators: Vec<S::ValidatorId>,
pub signature: S::AggregateSignature,
}
pub trait Weights: Send + Sync {
@ -76,6 +91,21 @@ pub trait Network: Send + Sync {
fn signature_scheme(&self) -> Arc<Self::SignatureScheme>;
fn weights(&self) -> Arc<Self::Weights>;
#[must_use]
fn verify_commit(
&self,
id: <Self::Block as Block>::Id,
commit: Commit<Self::SignatureScheme>,
) -> bool {
if !self.signature_scheme().verify_aggregate(&id.encode(), &commit.validators, commit.signature)
{
return false;
}
let weights = self.weights();
commit.validators.iter().map(|v| weights.weight(*v)).sum::<u64>() >= weights.threshold()
}
async fn broadcast(
&mut self,
msg: SignedMessage<
@ -90,9 +120,6 @@ pub trait Network: Send + Sync {
fn validate(&mut self, block: &Self::Block) -> Result<(), BlockError>;
// Add a block and return the proposal for the next one
fn add_block(
&mut self,
block: Self::Block,
sigs: Vec<(Self::ValidatorId, <Self::SignatureScheme as SignatureScheme>::Signature)>,
) -> Self::Block;
fn add_block(&mut self, block: Self::Block, commit: Commit<Self::SignatureScheme>)
-> Self::Block;
}

View file

@ -253,15 +253,19 @@ impl<N: Network + 'static> TendermintMachine<N> {
match machine.message(msg.msg).await {
Ok(None) => (),
Ok(Some(block)) => {
let sigs = machine
.log
.precommitted
.iter()
.filter_map(|(k, (id, sig))| {
Some((*k, sig.clone())).filter(|_| id == &block.id())
})
.collect();
let proposal = machine.network.write().await.add_block(block, sigs);
let mut validators = vec![];
let mut sigs = vec![];
for (v, sig) in machine.log.precommitted.iter().filter_map(|(k, (id, sig))| {
Some((*k, sig.clone())).filter(|_| id == &block.id())
}) {
validators.push(v);
sigs.push(sig);
}
let proposal = machine.network.write().await.add_block(
block,
Commit { validators, signature: N::SignatureScheme::aggregate(&sigs) },
);
machine.reset(proposal).await
}
Err(TendermintError::Malicious(validator)) => {
@ -400,13 +404,13 @@ impl<N: Network + 'static> TendermintMachine<N> {
if self.step == Step::Prevote {
let (participation, weight) = self.log.message_instances(self.round, Data::Prevote(None));
// 34-35
if participation > self.weights.threshold() {
if participation >= self.weights.threshold() {
let timeout = self.timeout(Step::Prevote);
self.timeouts.entry(Step::Prevote).or_insert(timeout);
}
// 44-46
if weight > self.weights.threshold() {
if weight >= self.weights.threshold() {
debug_assert!(self.broadcast(Data::Precommit(None)).await.is_none());
}
}

View file

@ -22,9 +22,23 @@ impl SignatureScheme for TestSignatureScheme {
sig
}
#[must_use]
fn verify(&self, validator: u16, msg: &[u8], sig: [u8; 32]) -> bool {
(sig[.. 2] == validator.to_le_bytes()) && (&sig[2 ..] == &[msg, &[0; 30]].concat()[.. 30])
}
fn aggregate(sigs: &[[u8; 32]]) -> Vec<[u8; 32]> {
sigs.to_vec()
}
#[must_use]
fn verify_aggregate(&self, msg: &[u8], signers: &[TestValidatorId], sigs: Vec<[u8; 32]>) -> bool {
assert_eq!(signers.len(), sigs.len());
for sig in signers.iter().zip(sigs.iter()) {
assert!(self.verify(*sig.0, msg, *sig.1));
}
true
}
}
struct TestWeights;
@ -91,12 +105,10 @@ impl Network for TestNetwork {
block.valid
}
fn add_block(&mut self, block: TestBlock, sigs: Vec<(u16, [u8; 32])>) -> TestBlock {
fn add_block(&mut self, block: TestBlock, commit: Commit<TestSignatureScheme>) -> TestBlock {
dbg!("Adding ", &block);
assert!(block.valid.is_ok());
for sig in sigs {
assert!(TestSignatureScheme(u16::MAX).verify(sig.0, &block.id().encode(), sig.1));
}
assert!(self.verify_commit(block.id(), commit));
TestBlock { id: block.id + 1, valid: Ok(()) }
}
}