Skip to content

Commit

Permalink
Merge branch 'aggregate-sigs' of github.com:akildemir/serai into aggr…
Browse files Browse the repository at this point in the history
…egate-sigs
  • Loading branch information
kayabaNerve committed Aug 21, 2023
2 parents 39ce819 + da4ba5d commit 0087605
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 16 deletions.
55 changes: 45 additions & 10 deletions coordinator/tributary/src/tendermint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ use ciphersuite::{
},
Ciphersuite, Ristretto,
};
use schnorr::SchnorrSignature;
use schnorr::{
SchnorrSignature,
aggregate::{SchnorrAggregator, SchnorrAggregate},
};

use serai_db::Db;

Expand Down Expand Up @@ -46,6 +49,8 @@ use crate::{
pub mod tx;
use tx::{TendermintTx, VoteSignature};

const DST: &[u8] = b"Tributary Tendermint Commit Aggregator";

fn challenge(
genesis: [u8; 32],
key: [u8; 32],
Expand Down Expand Up @@ -159,8 +164,7 @@ impl Validators {
impl SignatureScheme for Validators {
type ValidatorId = [u8; 32];
type Signature = [u8; 64];
// TODO: Use half-aggregation.
type AggregateSignature = Vec<[u8; 64]>;
type AggregateSignature = Vec<u8>;
type Signer = Arc<Signer>;

#[must_use]
Expand All @@ -177,8 +181,23 @@ impl SignatureScheme for Validators {
actual_sig.verify(validator_point, challenge(self.genesis, validator, &sig[.. 32], msg))
}

fn aggregate(sigs: &[Self::Signature]) -> Self::AggregateSignature {
sigs.to_vec()
fn aggregate(
&self,
validators: &[Self::ValidatorId],
msg: &[u8],
sigs: &[Self::Signature],
) -> Self::AggregateSignature {
assert_eq!(validators.len(), sigs.len());

let mut aggregator = SchnorrAggregator::<Ristretto>::new(DST);
for (key, sig) in validators.iter().zip(sigs) {
let actual_sig = SchnorrSignature::<Ristretto>::read::<&[u8]>(&mut sig.as_ref()).unwrap();
let challenge = challenge(self.genesis, *key, actual_sig.R.to_bytes().as_ref(), msg);
aggregator.aggregate(challenge, actual_sig);
}

let aggregate = aggregator.complete().unwrap();
aggregate.serialize()
}

#[must_use]
Expand All @@ -188,12 +207,28 @@ impl SignatureScheme for Validators {
msg: &[u8],
sig: &Self::AggregateSignature,
) -> bool {
for (signer, sig) in signers.iter().zip(sig.iter()) {
if !self.verify(*signer, msg, sig) {
return false;
}
let Ok(aggregate) = SchnorrAggregate::<Ristretto>::read::<&[u8]>(&mut sig.as_slice()) else {
return false;
};

if signers.len() != aggregate.Rs().len() {
return false;
}
true

let mut challenges = vec![];
for (key, nonce) in signers.iter().zip(aggregate.Rs()) {
challenges.push(challenge(self.genesis, *key, nonce.to_bytes().as_ref(), msg));
}

aggregate.verify(
DST,
signers
.iter()
.zip(challenges)
.map(|(s, c)| (<Ristretto as Ciphersuite>::read_G(&mut s.as_slice()).unwrap(), c))
.collect::<Vec<_>>()
.as_slice(),
)
}
}

Expand Down
17 changes: 14 additions & 3 deletions coordinator/tributary/tendermint/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,13 @@ pub trait SignatureScheme: Send + Sync + Clone {
fn verify(&self, validator: Self::ValidatorId, msg: &[u8], sig: &Self::Signature) -> bool;

/// Aggregate signatures.
fn aggregate(sigs: &[Self::Signature]) -> Self::AggregateSignature;
/// It may panic if corrupted data passed in.
fn aggregate(
&self,
validators: &[Self::ValidatorId],
msg: &[u8],
sigs: &[Self::Signature],
) -> Self::AggregateSignature;
/// Verify an aggregate signature for the list of signers.
#[must_use]
fn verify_aggregate(
Expand All @@ -102,8 +108,13 @@ impl<S: SignatureScheme> SignatureScheme for Arc<S> {
self.as_ref().verify(validator, msg, sig)
}

fn aggregate(sigs: &[Self::Signature]) -> Self::AggregateSignature {
S::aggregate(sigs)
fn aggregate(
&self,
validators: &[Self::ValidatorId],
msg: &[u8],
sigs: &[Self::Signature],
) -> Self::AggregateSignature {
self.as_ref().aggregate(validators, msg, sigs)
}

#[must_use]
Expand Down
8 changes: 6 additions & 2 deletions coordinator/tributary/tendermint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,10 +469,14 @@ impl<N: Network + 'static> TendermintMachine<N> {
}
}

let commit_msg = commit_msg(
self.block.end_time[&self.block.round().number].canonical(),
block.id().as_ref(),
);
let commit = Commit {
end_time: self.block.end_time[&msg.round].canonical(),
validators,
signature: N::SignatureScheme::aggregate(&sigs),
validators: validators.clone(),
signature: self.network.signature_scheme().aggregate(&validators, &commit_msg, &sigs),
};
debug_assert!(self.network.verify_commit(block.id(), &commit));

Expand Down
7 changes: 6 additions & 1 deletion coordinator/tributary/tendermint/tests/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ impl SignatureScheme for TestSignatureScheme {
(sig[.. 2] == validator.to_le_bytes()) && (sig[2 ..] == [msg, &[0; 30]].concat()[.. 30])
}

fn aggregate(sigs: &[[u8; 32]]) -> Vec<[u8; 32]> {
fn aggregate(
&self,
_: &[Self::ValidatorId],
_: &[u8],
sigs: &[Self::Signature],
) -> Self::AggregateSignature {
sigs.to_vec()
}

Expand Down
5 changes: 5 additions & 0 deletions crypto/schnorr/src/aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ impl<C: Ciphersuite> SchnorrAggregate<C> {
buf
}

#[allow(non_snake_case)]
pub fn Rs(&self) -> &[C::G] {
self.Rs.as_slice()
}

/// Perform signature verification.
///
/// Challenges must be properly crafted, which means being binding to the public key, nonce, and
Expand Down

0 comments on commit 0087605

Please sign in to comment.