Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(crypto/bls12381): signature aggregation #11

Open
wants to merge 125 commits into
base: bera-v1.x
Choose a base branch
from

Conversation

melekes
Copy link

@melekes melekes commented Jan 7, 2025

Aggregating signatures in the LastCommit before including it in the next block (proposal block). Note we don't aggregate prevotes, nor precommits when accumulating them - only after we've received 2/3+ of them and are ready to go to the next height.

Proto changes

BlockIDFlag

This PR adds 4 new enum options to BlockIDFlag:

  • BlockIDFlagAggCommit
  • BlockIDFlagAggCommitAbsent
  • BlockIDFlagAggNil
  • BlockIDFlagAggNilAbsent

The structure of the commit becomes like this:

0: BlockIDFlagAggCommit {aggregated signature}
1: BlockIDFlagAggCommitAbsent {empty signature}
2: BlockIDFlagAggCommitAbsent {empty signature}
3: BlockIDFlagAggCommitAbsent {empty signature}

4 validators, 1 aggregated signature

When there are precommits for nil:

0: BlockIDFlagAggCommit {aggregated signature}
1: BlockIDFlagAggCommitAbsent {empty signature}
2: BlockIDFlagAggCommitAbsent {empty signature}
3: BlockIDFlagAggNil {aggregated signature}

4 validators, 1 aggregated signature for block, 1 aggregated signature for nil (2 signatures in total).

CanonicalVote

Removes Timestamp

Vote

Sets Timestamp always to zero

Breaking changes

Removes BFT time in favor of PBTS, which becomes required from height 1 (from the start). If PBTS is not enabled from height 1, the code will panic!

Removes support for all curves other than BLS12-381. CometBFT will return an error if the validator update contains ed25519 or a different curve.

@melekes melekes marked this pull request as ready for review January 7, 2025 09:18
BlockID: CanonicalizeBlockID(vote.BlockID),
// Timestamp is not included in the canonical vote
// because we won't be able to aggregate votes with different timestamps.
// Timestamp: vote.Timestamp,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is probably the biggest breaking change - removing Timestamp from vote sign bytes

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am double checking, I think it is ok because this is only for the canonical vote. Because vote timestamps are used to compute the block time when using BFT time.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also remove the timestamp field from both vote structures: the one internal to comet, and the protobuf-generated one. Leaving that field there only adds confusion IMO (let me know if you want to discuss)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also remove the timestamp field from both vote structures: the one internal to comet, and the protobuf-generated one. Leaving that field there only adds confusion IMO (let me know if you want to discuss)

Should it go hand in hand with making the PBTS the default choice + ripping off median time?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The decision here was to add preemptive panics so we fail early in case CometBFT is misconfigured.

for i, v := range voteSet.votes {
cSig := v.CommitSig()
if cSig.BlockIDFlag != BlockIDFlagAbsent {
cSig.Signature = []byte{0x00} // clear the signature
Copy link
Author

@melekes melekes Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ugly. CometBFT requires signatures to be present (not empty), but with BLS we only have 2 signatures present at max (1 for block, 1 for nil)! We can disable the check for empty sig in ValidateBasic though ... What do people think?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can have two new flags BlockIDFlagAggCommit (to store the aggregated signature), BlockIDFlagAggAbsent (to denote the signature is missing because it's aggregated in another slot). And maybe BlockIDFlagAggNil (to store the aggregated signature for nil). Although I still think aggregating nil votes is not worth the extra complexity (nil votes in a commit is extremely rare in practice)

assert.Equal(t, sig, v.Signature)
assert.Equal(t, extSig, v.ExtensionSignature)
}
// {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we delete this or modify it so it works with the new scheme?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will remove

internal/consensus/state.go Outdated Show resolved Hide resolved
test/e2e/Makefile Show resolved Hide resolved
BlockID: CanonicalizeBlockID(vote.BlockID),
// Timestamp is not included in the canonical vote
// because we won't be able to aggregate votes with different timestamps.
// Timestamp: vote.Timestamp,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am double checking, I think it is ok because this is only for the canonical vote. Because vote timestamps are used to compute the block time when using BFT time.

@jmalicevic
Copy link

BLS at the moment has a SignatureLength which is checked on vote veriification. Does that need special handling now?

Comment on lines 1316 to 1317
// Note we can't aggregate a commit when vote extensions are enabled
// because votes are different.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I might be wrong, but I don't agree with this.
When vote extensions are enabled, there is one signature for the vote and another signature for the vote extension.
I agree the extension signatures cannot be aggregated, as the extensions can be different.
But the vote themselves can still be aggregated (assuming you remove the timestamp field, or set it always to 0-time).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. But then again, who is going to verify vote extensions? There's no point in aggregating votes if you need to verify vote extensions using individual verification (signature.Verify).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the 2nd thought, we don't verify vote extensions in VerifyCommit, so I think using them while aggregating vote signatures is okay. 6b0b06e (#11)

types/validation.go Outdated Show resolved Hide resolved
types/validation.go Outdated Show resolved Hide resolved
types/validation.go Outdated Show resolved Hide resolved
types/validation.go Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants