diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2019-04-11 16:45:38 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-11 16:45:38 +0800 |
commit | 5b0aad05d7ccc1dabedfd1f3bfc0d584db849e63 (patch) | |
tree | bdbecd8695ed5225aa24f56b6a3c0acc7244f68f | |
parent | 269fed574986331e07bf931b2c9b1a495c40f8ac (diff) | |
download | dexon-consensus-5b0aad05d7ccc1dabedfd1f3bfc0d584db849e63.tar dexon-consensus-5b0aad05d7ccc1dabedfd1f3bfc0d584db849e63.tar.gz dexon-consensus-5b0aad05d7ccc1dabedfd1f3bfc0d584db849e63.tar.bz2 dexon-consensus-5b0aad05d7ccc1dabedfd1f3bfc0d584db849e63.tar.lz dexon-consensus-5b0aad05d7ccc1dabedfd1f3bfc0d584db849e63.tar.xz dexon-consensus-5b0aad05d7ccc1dabedfd1f3bfc0d584db849e63.tar.zst dexon-consensus-5b0aad05d7ccc1dabedfd1f3bfc0d584db849e63.zip |
core: change CRSSignature with bls (#563)
-rw-r--r-- | core/agreement-mgr.go | 20 | ||||
-rw-r--r-- | core/agreement-state_test.go | 2 | ||||
-rw-r--r-- | core/agreement.go | 2 | ||||
-rw-r--r-- | core/agreement_test.go | 72 | ||||
-rw-r--r-- | core/consensus.go | 8 | ||||
-rw-r--r-- | core/leader-selector.go | 20 | ||||
-rw-r--r-- | core/leader-selector_test.go | 2 | ||||
-rw-r--r-- | core/utils/crypto.go | 23 | ||||
-rw-r--r-- | core/utils/crypto_test.go | 11 | ||||
-rw-r--r-- | core/utils/signer.go | 23 | ||||
-rw-r--r-- | core/utils/signer_test.go | 6 |
11 files changed, 104 insertions, 85 deletions
diff --git a/core/agreement-mgr.go b/core/agreement-mgr.go index af0adf2..ac28955 100644 --- a/core/agreement-mgr.go +++ b/core/agreement-mgr.go @@ -36,17 +36,33 @@ var ( ErrRoundOutOfRange = errors.New("round out of range") ErrInvalidBlock = errors.New("invalid block") ErrNoValidLeader = errors.New("no valid leader") + ErrIncorrectCRSSignature = errors.New("incorrect CRS signature") + ErrBlockTooOld = errors.New("block too old") ) const maxResultCache = 100 // genValidLeader generate a validLeader function for agreement modules. func genValidLeader( - mgr *agreementMgr) func(*types.Block) (bool, error) { - return func(block *types.Block) (bool, error) { + mgr *agreementMgr) validLeaderFn { + return func(block *types.Block, crs common.Hash) (bool, error) { if block.Timestamp.After(time.Now()) { return false, nil } + if block.Position.Round >= DKGDelayRound { + if mgr.recv.npks == nil { + return false, nil + } + if block.Position.Round > mgr.recv.npks.Round { + return false, nil + } + if block.Position.Round < mgr.recv.npks.Round { + return false, ErrBlockTooOld + } + } + if !utils.VerifyCRSSignature(block, crs, mgr.recv.npks) { + return false, ErrIncorrectCRSSignature + } if err := mgr.bcModule.sanityCheck(block); err != nil { if err == ErrRetrySanityCheckLater { return false, nil diff --git a/core/agreement-state_test.go b/core/agreement-state_test.go index cbcbc63..43631ea 100644 --- a/core/agreement-state_test.go +++ b/core/agreement-state_test.go @@ -103,7 +103,7 @@ func (s *AgreementStateTestSuite) SetupTest() { func (s *AgreementStateTestSuite) newAgreement(numNode int) *agreement { logger := &common.NullLogger{} - leader := newLeaderSelector(func(*types.Block) (bool, error) { + leader := newLeaderSelector(func(*types.Block, common.Hash) (bool, error) { return true, nil }, logger) notarySet := make(map[types.NodeID]struct{}) diff --git a/core/agreement.go b/core/agreement.go index b122a4d..a6fb074 100644 --- a/core/agreement.go +++ b/core/agreement.go @@ -690,7 +690,7 @@ func (a *agreement) processBlock(block *types.Block) error { if !exist { return true } - ok, err := a.data.leader.validLeader(block) + ok, err := a.data.leader.validLeader(block, a.data.leader.hashCRS) if err != nil { fmt.Println("Error checking validLeader for Fast BA", "error", err, "block", block) diff --git a/core/agreement_test.go b/core/agreement_test.go index 9afc0f2..0854c7e 100644 --- a/core/agreement_test.go +++ b/core/agreement_test.go @@ -95,17 +95,18 @@ func (s *AgreementTestSuite) proposeBlock( type AgreementTestSuite struct { suite.Suite - ID types.NodeID - signers map[types.NodeID]*utils.Signer - voteChan chan *types.Vote - blockChan chan common.Hash - confirmChan chan common.Hash - forkVoteChan chan common.Hash - forkBlockChan chan common.Hash - block map[common.Hash]*types.Block - pulledBlocks map[common.Hash]struct{} - agreement []*agreement - agreementID types.Position + ID types.NodeID + signers map[types.NodeID]*utils.Signer + voteChan chan *types.Vote + blockChan chan common.Hash + confirmChan chan common.Hash + forkVoteChan chan common.Hash + forkBlockChan chan common.Hash + block map[common.Hash]*types.Block + pulledBlocks map[common.Hash]struct{} + agreement []*agreement + agreementID types.Position + defaultValidLeader validLeaderFn } func (s *AgreementTestSuite) SetupTest() { @@ -123,6 +124,9 @@ func (s *AgreementTestSuite) SetupTest() { s.block = make(map[common.Hash]*types.Block) s.pulledBlocks = make(map[common.Hash]struct{}) s.agreementID = types.Position{Height: types.GenesisHeight} + s.defaultValidLeader = func(*types.Block, common.Hash) (bool, error) { + return true, nil + } } func (s *AgreementTestSuite) newAgreement( @@ -183,9 +187,7 @@ func (s *AgreementTestSuite) prepareVote( } func (s *AgreementTestSuite) TestSimpleConfirm() { - a, leaderNode := s.newAgreement(4, 0, func(*types.Block) (bool, error) { - return true, nil - }) + a, leaderNode := s.newAgreement(4, 0, s.defaultValidLeader) s.Require().Equal(s.ID, leaderNode) // FastState a.nextState() @@ -243,9 +245,7 @@ func (s *AgreementTestSuite) TestSimpleConfirm() { } func (s *AgreementTestSuite) TestPartitionOnCommitVote() { - a, _ := s.newAgreement(4, -1, func(*types.Block) (bool, error) { - return true, nil - }) + a, _ := s.newAgreement(4, -1, s.defaultValidLeader) // FastState a.nextState() // FastVoteState @@ -287,9 +287,7 @@ func (s *AgreementTestSuite) TestPartitionOnCommitVote() { } func (s *AgreementTestSuite) TestFastConfirmLeader() { - a, leaderNode := s.newAgreement(4, 0, func(*types.Block) (bool, error) { - return true, nil - }) + a, leaderNode := s.newAgreement(4, 0, s.defaultValidLeader) s.Require().Equal(s.ID, leaderNode) // FastState a.nextState() @@ -327,9 +325,7 @@ func (s *AgreementTestSuite) TestFastConfirmLeader() { } func (s *AgreementTestSuite) TestFastConfirmNonLeader() { - a, leaderNode := s.newAgreement(4, 1, func(*types.Block) (bool, error) { - return true, nil - }) + a, leaderNode := s.newAgreement(4, 1, s.defaultValidLeader) s.Require().NotEqual(s.ID, leaderNode) // FastState a.nextState() @@ -367,9 +363,7 @@ func (s *AgreementTestSuite) TestFastConfirmNonLeader() { func (s *AgreementTestSuite) TestFastForwardCond1() { votes := 0 - a, _ := s.newAgreement(4, -1, func(*types.Block) (bool, error) { - return true, nil - }) + a, _ := s.newAgreement(4, -1, s.defaultValidLeader) a.data.lockIter = 1 a.data.period = 3 hash := common.NewRandomHash() @@ -423,9 +417,7 @@ func (s *AgreementTestSuite) TestFastForwardCond1() { func (s *AgreementTestSuite) TestFastForwardCond2() { votes := 0 - a, _ := s.newAgreement(4, -1, func(*types.Block) (bool, error) { - return true, nil - }) + a, _ := s.newAgreement(4, -1, s.defaultValidLeader) a.data.period = 1 done := a.done() hash := common.NewRandomHash() @@ -468,9 +460,7 @@ func (s *AgreementTestSuite) TestFastForwardCond2() { func (s *AgreementTestSuite) TestFastForwardCond3() { numVotes := 0 votes := []*types.Vote{} - a, _ := s.newAgreement(4, -1, func(*types.Block) (bool, error) { - return true, nil - }) + a, _ := s.newAgreement(4, -1, s.defaultValidLeader) a.data.period = 1 done := a.done() for nID := range a.notarySet { @@ -503,9 +493,7 @@ func (s *AgreementTestSuite) TestFastForwardCond3() { func (s *AgreementTestSuite) TestDecide() { votes := 0 - a, _ := s.newAgreement(4, -1, func(*types.Block) (bool, error) { - return true, nil - }) + a, _ := s.newAgreement(4, -1, s.defaultValidLeader) a.data.period = 5 // No decide if com-vote on SKIP. @@ -533,9 +521,7 @@ func (s *AgreementTestSuite) TestDecide() { } func (s *AgreementTestSuite) TestForkVote() { - a, _ := s.newAgreement(4, -1, func(*types.Block) (bool, error) { - return true, nil - }) + a, _ := s.newAgreement(4, -1, s.defaultValidLeader) a.data.period = 2 for nID := range a.notarySet { v01 := s.prepareVote(nID, types.VotePreCom, common.NewRandomHash(), 2) @@ -549,9 +535,7 @@ func (s *AgreementTestSuite) TestForkVote() { } func (s *AgreementTestSuite) TestForkBlock() { - a, _ := s.newAgreement(4, -1, func(*types.Block) (bool, error) { - return true, nil - }) + a, _ := s.newAgreement(4, -1, s.defaultValidLeader) for nID := range a.notarySet { b01 := s.proposeBlock(nID, a.data.leader.hashCRS) b02 := s.proposeBlock(nID, a.data.leader.hashCRS) @@ -563,7 +547,7 @@ func (s *AgreementTestSuite) TestForkBlock() { } func (s *AgreementTestSuite) TestFindBlockInPendingSet() { - a, leaderNode := s.newAgreement(4, 0, func(*types.Block) (bool, error) { + a, leaderNode := s.newAgreement(4, 0, func(*types.Block, common.Hash) (bool, error) { return false, nil }) block := s.proposeBlock(leaderNode, a.data.leader.hashCRS) @@ -579,9 +563,7 @@ func (s *AgreementTestSuite) TestFindBlockInPendingSet() { } func (s *AgreementTestSuite) TestConfirmWithBlock() { - a, _ := s.newAgreement(4, -1, func(*types.Block) (bool, error) { - return true, nil - }) + a, _ := s.newAgreement(4, -1, s.defaultValidLeader) block := &types.Block{ Hash: common.NewRandomHash(), Position: a.agreementID(), diff --git a/core/consensus.go b/core/consensus.go index 966c70a..49f2db1 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -656,6 +656,14 @@ func newConsensusForRound( } cfgModule := newConfigurationChain(ID, recv, gov, nodeSetCache, db, logger) recv.cfgModule = cfgModule + signer.SetBLSSigner( + func(round uint64, hash common.Hash) (crypto.Signature, error) { + _, signer, err := cfgModule.getDKGInfo(round, false) + if err != nil { + return crypto.Signature{}, err + } + return crypto.Signature(signer.sign(hash)), nil + }) appModule := app if usingNonBlocking { appModule = newNonBlocking(app, debugApp) diff --git a/core/leader-selector.go b/core/leader-selector.go index 8c06328..91b2e99 100644 --- a/core/leader-selector.go +++ b/core/leader-selector.go @@ -18,22 +18,15 @@ package core import ( - "fmt" "math/big" "sync" "github.com/dexon-foundation/dexon-consensus/common" "github.com/dexon-foundation/dexon-consensus/core/crypto" "github.com/dexon-foundation/dexon-consensus/core/types" - "github.com/dexon-foundation/dexon-consensus/core/utils" ) -// Errors for leader module. -var ( - ErrIncorrectCRSSignature = fmt.Errorf("incorrect CRS signature") -) - -type validLeaderFn func(*types.Block) (bool, error) +type validLeaderFn func(block *types.Block, crs common.Hash) (bool, error) // Some constant value. var ( @@ -105,7 +98,7 @@ func (l *leaderSelector) leaderBlockHash() common.Hash { if !ok { continue } - ok, err := l.validLeader(b) + ok, err := l.validLeader(b, l.hashCRS) if err != nil { l.logger.Error("Error checking validLeader", "error", err, "block", b) delete(l.pendingBlocks, b.Hash) @@ -120,20 +113,13 @@ func (l *leaderSelector) leaderBlockHash() common.Hash { } func (l *leaderSelector) processBlock(block *types.Block) error { - ok, err := utils.VerifyCRSSignature(block, l.hashCRS) - if err != nil { - return err - } - if !ok { - return ErrIncorrectCRSSignature - } l.lock.Lock() defer l.lock.Unlock() ok, dist := l.potentialLeader(block) if !ok { return nil } - ok, err = l.validLeader(block) + ok, err := l.validLeader(block, l.hashCRS) if err != nil { return err } diff --git a/core/leader-selector_test.go b/core/leader-selector_test.go index 9e09279..4738663 100644 --- a/core/leader-selector_test.go +++ b/core/leader-selector_test.go @@ -38,7 +38,7 @@ type LeaderSelectorTestSuite struct { func (s *LeaderSelectorTestSuite) SetupTest() { s.mockValidLeaderDefault = true s.mockValidLeaderDB = make(map[common.Hash]bool) - s.mockValidLeader = func(b *types.Block) (bool, error) { + s.mockValidLeader = func(b *types.Block, _ common.Hash) (bool, error) { if ret, exist := s.mockValidLeaderDB[b.Hash]; exist { return ret, nil } diff --git a/core/utils/crypto.go b/core/utils/crypto.go index 7fd3a77..496944d 100644 --- a/core/utils/crypto.go +++ b/core/utils/crypto.go @@ -18,6 +18,7 @@ package utils import ( + "bytes" "encoding/binary" "github.com/dexon-foundation/dexon-consensus/common" @@ -122,21 +123,27 @@ func VerifyVoteSignature(vote *types.Vote) (bool, error) { func hashCRS(block *types.Block, crs common.Hash) common.Hash { hashPos := HashPosition(block.Position) + if block.Position.Round < dkgDelayRound { + return crypto.Keccak256Hash(crs[:], hashPos[:], block.ProposerID.Hash[:]) + } return crypto.Keccak256Hash(crs[:], hashPos[:]) } // VerifyCRSSignature verifies the CRS signature of types.Block. -func VerifyCRSSignature(block *types.Block, crs common.Hash) ( - bool, error) { +func VerifyCRSSignature( + block *types.Block, crs common.Hash, npks *typesDKG.NodePublicKeys) bool { hash := hashCRS(block, crs) - pubKey, err := crypto.SigToPub(hash, block.CRSSignature) - if err != nil { - return false, err + if block.Position.Round < dkgDelayRound { + return bytes.Compare(block.CRSSignature.Signature[:], hash[:]) == 0 } - if block.ProposerID != types.NewNodeID(pubKey) { - return false, nil + if npks == nil { + return false } - return true, nil + pubKey, exist := npks.PublicKeys[block.ProposerID] + if !exist { + return false + } + return pubKey.VerifySignature(hash, block.CRSSignature) } // HashPosition generates hash of a types.Position. diff --git a/core/utils/crypto_test.go b/core/utils/crypto_test.go index 5dfd82b..24ea68e 100644 --- a/core/utils/crypto_test.go +++ b/core/utils/crypto_test.go @@ -127,6 +127,7 @@ func (s *CryptoTestSuite) TestVoteSignature() { } func (s *CryptoTestSuite) TestCRSSignature() { + dkgDelayRound = 1 crs := common.NewRandomHash() prv, err := ecdsa.NewPrivateKey() s.Require().NoError(err) @@ -135,14 +136,12 @@ func (s *CryptoTestSuite) TestCRSSignature() { block := &types.Block{ ProposerID: nID, } - block.CRSSignature, err = prv.Sign(hashCRS(block, crs)) - s.Require().NoError(err) - ok, err := VerifyCRSSignature(block, crs) - s.Require().NoError(err) + hash := hashCRS(block, crs) + block.CRSSignature.Signature = hash[:] + ok := VerifyCRSSignature(block, crs, nil) s.True(ok) block.Position.Height++ - ok, err = VerifyCRSSignature(block, crs) - s.Require().NoError(err) + ok = VerifyCRSSignature(block, crs, nil) s.False(ok) } diff --git a/core/utils/signer.go b/core/utils/signer.go index 7694dab..9904410 100644 --- a/core/utils/signer.go +++ b/core/utils/signer.go @@ -31,13 +31,17 @@ var ( ErrInvalidProposerID = errors.New("invalid proposer id") ErrIncorrectHash = errors.New("hash of block is incorrect") ErrIncorrectSignature = errors.New("signature of block is incorrect") + ErrNoBLSSigner = errors.New("bls signer not set") ) +type blsSigner func(round uint64, hash common.Hash) (crypto.Signature, error) + // Signer signs a segment of data. type Signer struct { prvKey crypto.PrivateKey pubKey crypto.PublicKey proposerID types.NodeID + blsSign blsSigner } // NewSigner constructs an Signer instance. @@ -50,6 +54,11 @@ func NewSigner(prvKey crypto.PrivateKey) (s *Signer) { return } +// SetBLSSigner for signing CRSSignature +func (s *Signer) SetBLSSigner(signer blsSigner) { + s.blsSign = signer +} + // SignBlock signs a types.Block. func (s *Signer) SignBlock(b *types.Block) (err error) { b.ProposerID = s.proposerID @@ -76,7 +85,19 @@ func (s *Signer) SignCRS(b *types.Block, crs common.Hash) (err error) { err = ErrInvalidProposerID return } - b.CRSSignature, err = s.prvKey.Sign(hashCRS(b, crs)) + if b.Position.Round < dkgDelayRound { + hash := hashCRS(b, crs) + b.CRSSignature = crypto.Signature{ + Type: "bls", + Signature: hash[:], + } + return + } + if s.blsSign == nil { + err = ErrNoBLSSigner + return + } + b.CRSSignature, err = s.blsSign(b.Position.Round, hashCRS(b, crs)) return } diff --git a/core/utils/signer_test.go b/core/utils/signer_test.go index 3905352..0ee1c30 100644 --- a/core/utils/signer_test.go +++ b/core/utils/signer_test.go @@ -66,11 +66,12 @@ func (s *SignerTestSuite) TestVote() { } func (s *SignerTestSuite) TestCRS() { + dkgDelayRound = 1 k := s.setupSigner() b := &types.Block{ ParentHash: common.NewRandomHash(), Position: types.Position{ - Round: 8, + Round: 0, Height: 9, }, Timestamp: time.Now().UTC(), @@ -80,9 +81,8 @@ func (s *SignerTestSuite) TestCRS() { // Hash block before hash CRS. s.NoError(k.SignBlock(b)) s.NoError(k.SignCRS(b, crs)) - ok, err := VerifyCRSSignature(b, crs) + ok := VerifyCRSSignature(b, crs, nil) s.True(ok) - s.NoError(err) } func TestSigner(t *testing.T) { |