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

BLS Signature Aggregation and Verification #117

Merged
merged 6 commits into from
Dec 3, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

- Blockchain Protocol
- [consensus] [\#101](https://github.com/line/tendermint/pull/101) Introduce composite key to delegate features to each function key
- [consensus] [\#117](https://github.com/line/tendermint/pull/117) BLS Signature Aggregation and Verification

### FEATURES:
- [init command] [\#125](https://github.com/line/tendermint/pull/125) Add an option selecting private key type to init, testnet commands
Expand Down
4 changes: 2 additions & 2 deletions blockchain/v1/reactor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,9 @@ func TestFastSyncNoBlockResponse(t *testing.T) {
for _, tt := range tests {
block := reactorPairs[1].bcR.store.LoadBlock(tt.height)
if tt.existent {
assert.True(t, block != nil)
assert.True(t, block != nil, "height=%d, existent=%t", tt.height, tt.existent)
} else {
assert.True(t, block == nil)
assert.True(t, block == nil, "height=%d, existent=%t", tt.height, tt.existent)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/pkg/errors"

"github.com/tendermint/tendermint/privval"
)

Expand Down
1 change: 1 addition & 0 deletions consensus/byzantine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/stretchr/testify/require"

config2 "github.com/tendermint/tendermint/config"

"github.com/tendermint/tendermint/libs/service"
Expand Down
4 changes: 3 additions & 1 deletion consensus/invalid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ func invalidDoPrevoteFunc(t *testing.T, height int64, round int, cs *State, sw *
Hash: blockHash,
PartsHeader: types.PartSetHeader{Total: 1, Hash: tmrand.Bytes(32)}},
}
cs.privValidator.SignVote(cs.state.ChainID, precommit)
if err = cs.privValidator.SignVote(cs.state.ChainID, precommit); err != nil {
panic(err)
}
cs.privValidator = nil // disable priv val so we don't do normal votes
cs.mtx.Unlock()

Expand Down
6 changes: 4 additions & 2 deletions consensus/reactor.go
Original file line number Diff line number Diff line change
Expand Up @@ -652,9 +652,11 @@ OUTER_LOOP:
// Catchup logic
// If peer is lagging by more than 1, send Commit.
if prs.Height != 0 && rs.Height >= prs.Height+2 {
// Load the block commit for prs.Height,
// Load the seen commit for prs.Height,
// which contains precommit signatures for prs.Height.
commit := conR.conS.blockStore.LoadBlockCommit(prs.Height)
// Originally the block commit was used, but with the addition of the BLS signature-aggregation,
// we use seen commit instead of the block commit because block commit has no no individual signature.
Copy link

Choose a reason for hiding this comment

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

no no individual signature is it typo?

Copy link
Contributor Author

@torao torao Dec 3, 2020

Choose a reason for hiding this comment

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

I fixed it. thanks!

commit := conR.conS.blockStore.LoadSeenCommit(prs.Height)
if ps.PickSendVote(commit) {
logger.Debug("Picked Catchup commit to send", "height", prs.Height)
continue OUTER_LOOP
Expand Down
2 changes: 2 additions & 0 deletions consensus/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

"github.com/pkg/errors"

"github.com/tendermint/tendermint/libs/fail"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
Expand Down Expand Up @@ -1086,6 +1087,7 @@ func (cs *State) createProposalBlock(round int) (block *types.Block, blockParts
case cs.LastCommit.HasTwoThirdsMajority():
// Make the commit from LastCommit
commit = cs.LastCommit.MakeCommit()
commit.AggregateSignatures()
default: // This shouldn't happen.
cs.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block")
return
Expand Down
72 changes: 70 additions & 2 deletions crypto/bls/bls.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bls

import (
"bytes"
"crypto/sha512"
"crypto/subtle"
"fmt"

Expand Down Expand Up @@ -46,6 +47,71 @@ func init() {
// PrivKeyBLS12 implements crypto.PrivKey.
type PrivKeyBLS12 [PrivKeyBLS12Size]byte

// AddSignature adds a BLS signature to the init. When the init is nil, then a new aggregate signature is built
// from specified signature.
func AddSignature(init []byte, signature []byte) (aggrSign []byte, err error) {
if init == nil {
blsSign := bls.Sign{}
init = blsSign.Serialize()
} else if len(init) != SignatureSize {
err = fmt.Errorf("invalid BLS signature: aggregated signature size %d is not valid size %d",
len(init), SignatureSize)
return
}
if len(signature) != SignatureSize {
err = fmt.Errorf("invalid BLS signature: signature size %d is not valid size %d",
len(signature), SignatureSize)
return
}
blsSign := bls.Sign{}
err = blsSign.Deserialize(signature)
if err != nil {
return
}
aggrBLSSign := bls.Sign{}
err = aggrBLSSign.Deserialize(init)
if err != nil {
return
}
aggrBLSSign.Add(&blsSign)
aggrSign = aggrBLSSign.Serialize()
return
}

func VerifyAggregatedSignature(aggregatedSignature []byte, pubKeys []PubKeyBLS12, msgs [][]byte) error {
if len(pubKeys) != len(msgs) {
return fmt.Errorf("the number of public keys %d doesn't match the one of messages %d",
len(pubKeys), len(msgs))
}
if aggregatedSignature == nil {
if len(pubKeys) == 0 {
return nil
}
return fmt.Errorf(
"the aggregate signature was omitted, even though %d public keys were specified", len(pubKeys))
}
aggrSign := bls.Sign{}
err := aggrSign.Deserialize(aggregatedSignature)
if err != nil {
return err
}
blsPubKeys := make([]bls.PublicKey, len(pubKeys))
hashes := make([][]byte, len(msgs))
for i := 0; i < len(pubKeys); i++ {
blsPubKeys[i] = bls.PublicKey{}
err = blsPubKeys[i].Deserialize(pubKeys[i][:])
if err != nil {
return err
}
hash := sha512.Sum512_256(msgs[i])
hashes[i] = hash[:]
}
if !aggrSign.VerifyAggregateHashes(blsPubKeys, hashes) {
return fmt.Errorf("failed to verify the aggregated hashes by %d public keys", len(blsPubKeys))
}
return nil
}

// GenPrivKey generates a new BLS12-381 private key.
func GenPrivKey() PrivKeyBLS12 {
sigKey := bls.SecretKey{}
Expand Down Expand Up @@ -74,7 +140,8 @@ func (privKey PrivKeyBLS12) Sign(msg []byte) ([]byte, error) {
if err != nil {
panic(fmt.Sprintf("Failed to copy the private key: %s", err))
}
sign := blsKey.SignByte(msg)
hash := sha512.Sum512_256(msg)
sign := blsKey.SignHash(hash[:])
return sign.Serialize(), nil
}

Expand Down Expand Up @@ -143,7 +210,8 @@ func (pubKey PubKeyBLS12) VerifyBytes(msg []byte, sig []byte) bool {
if err != nil {
return false
}
return blsSign.VerifyByte(&blsPubKey, msg)
hash := sha512.Sum512_256(msg)
return blsSign.VerifyHash(&blsPubKey, hash[:])
}

// VRFVerify is not supported in BLS12.
Expand Down
Loading