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
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; fn sign(&self, msg: &[u8]) -> Self::Signature;
#[must_use] #[must_use]
fn verify(&self, validator: Self::ValidatorId, msg: &[u8], sig: Self::Signature) -> bool; 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 { pub trait Weights: Send + Sync {
@@ -76,6 +91,21 @@ pub trait Network: Send + Sync {
fn signature_scheme(&self) -> Arc<Self::SignatureScheme>; fn signature_scheme(&self) -> Arc<Self::SignatureScheme>;
fn weights(&self) -> Arc<Self::Weights>; 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( async fn broadcast(
&mut self, &mut self,
msg: SignedMessage< msg: SignedMessage<
@@ -90,9 +120,6 @@ pub trait Network: Send + Sync {
fn validate(&mut self, block: &Self::Block) -> Result<(), BlockError>; fn validate(&mut self, block: &Self::Block) -> Result<(), BlockError>;
// Add a block and return the proposal for the next one // Add a block and return the proposal for the next one
fn add_block( fn add_block(&mut self, block: Self::Block, commit: Commit<Self::SignatureScheme>)
&mut self, -> Self::Block;
block: Self::Block,
sigs: Vec<(Self::ValidatorId, <Self::SignatureScheme as SignatureScheme>::Signature)>,
) -> Self::Block;
} }

View File

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

View File

@@ -22,9 +22,23 @@ impl SignatureScheme for TestSignatureScheme {
sig sig
} }
#[must_use]
fn verify(&self, validator: u16, msg: &[u8], sig: [u8; 32]) -> bool { fn verify(&self, validator: u16, msg: &[u8], sig: [u8; 32]) -> bool {
(sig[.. 2] == validator.to_le_bytes()) && (&sig[2 ..] == &[msg, &[0; 30]].concat()[.. 30]) (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; struct TestWeights;
@@ -91,12 +105,10 @@ impl Network for TestNetwork {
block.valid 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); dbg!("Adding ", &block);
assert!(block.valid.is_ok()); assert!(block.valid.is_ok());
for sig in sigs { assert!(self.verify_commit(block.id(), commit));
assert!(TestSignatureScheme(u16::MAX).verify(sig.0, &block.id().encode(), sig.1));
}
TestBlock { id: block.id + 1, valid: Ok(()) } TestBlock { id: block.id + 1, valid: Ok(()) }
} }
} }