diff options
author | Mission Liao <mission.liao@dexon.org> | 2019-03-17 09:56:23 +0800 |
---|---|---|
committer | Jimmy Hu <jimmy.hu@dexon.org> | 2019-03-17 09:56:23 +0800 |
commit | 4b40c1b8990d2a371a77018feea32d038163f2ec (patch) | |
tree | b482aee945e1f60c6c9c9efd86c39abe812a353b /core | |
parent | b636901c60aa666c6c6b532d06e78b529537d315 (diff) | |
download | dexon-consensus-4b40c1b8990d2a371a77018feea32d038163f2ec.tar dexon-consensus-4b40c1b8990d2a371a77018feea32d038163f2ec.tar.gz dexon-consensus-4b40c1b8990d2a371a77018feea32d038163f2ec.tar.bz2 dexon-consensus-4b40c1b8990d2a371a77018feea32d038163f2ec.tar.lz dexon-consensus-4b40c1b8990d2a371a77018feea32d038163f2ec.tar.xz dexon-consensus-4b40c1b8990d2a371a77018feea32d038163f2ec.tar.zst dexon-consensus-4b40c1b8990d2a371a77018feea32d038163f2ec.zip |
dkg: add reset field (#492)
* Add Reset fields to DKG types
* Fix crypto part after adding Reset field
* Prohibit DKG messages with different resetCount
* Add TODO
* Add reset parameter to dkgProtocol constructor
* Add TODO
* Fix inconsist hash to prepare CRS
* Add reset parameter when runnning DKG
* Fix test for utils.RoundEvent
* Add dummy test to prohibit DKG messages with unexpected reset count
* Fix test.App
Diffstat (limited to 'core')
-rw-r--r-- | core/configuration-chain.go | 41 | ||||
-rw-r--r-- | core/configuration-chain_test.go | 30 | ||||
-rw-r--r-- | core/consensus.go | 11 | ||||
-rw-r--r-- | core/consensus_test.go | 4 | ||||
-rw-r--r-- | core/dkg-tsig-protocol.go | 73 | ||||
-rw-r--r-- | core/dkg-tsig-protocol_test.go | 152 | ||||
-rw-r--r-- | core/test/app_test.go | 23 | ||||
-rw-r--r-- | core/test/state.go | 30 | ||||
-rw-r--r-- | core/test/state_test.go | 118 | ||||
-rw-r--r-- | core/types/dkg/dkg.go | 41 | ||||
-rw-r--r-- | core/types/dkg/dkg_test.go | 35 | ||||
-rw-r--r-- | core/utils/crypto.go | 18 | ||||
-rw-r--r-- | core/utils/crypto_test.go | 47 |
13 files changed, 483 insertions, 140 deletions
diff --git a/core/configuration-chain.go b/core/configuration-chain.go index 9214cd9..5c32260 100644 --- a/core/configuration-chain.go +++ b/core/configuration-chain.go @@ -86,7 +86,7 @@ func newConfigurationChain( } } -func (cc *configurationChain) registerDKG(round uint64, threshold int) { +func (cc *configurationChain) registerDKG(round, reset uint64, threshold int) { cc.dkgLock.Lock() defer cc.dkgLock.Unlock() if cc.dkg != nil { @@ -105,7 +105,9 @@ func (cc *configurationChain) registerDKG(round uint64, threshold int) { cc.ID, cc.recv, round, + reset, threshold) + // TODO(mission): should keep DKG resetCount along with DKG private share. err = cc.db.PutOrUpdateDKGMasterPrivateShares(round, *cc.dkg.prvShares) if err != nil { cc.logger.Error("Error put or update DKG master private shares", "error", @@ -122,20 +124,22 @@ func (cc *configurationChain) registerDKG(round uint64, threshold int) { }() } -func (cc *configurationChain) runDKG(round uint64) error { +func (cc *configurationChain) runDKG(round, reset uint64) error { // Check if corresponding DKG signer is ready. if _, _, err := cc.getDKGInfo(round); err == nil { return nil } cc.dkgLock.Lock() defer cc.dkgLock.Unlock() - if cc.dkg == nil || cc.dkg.round != round { - if cc.dkg != nil && cc.dkg.round > round { - cc.logger.Warn("DKG canceled", "round", round) - return nil - } + if cc.dkg == nil || + cc.dkg.round < round || + (cc.dkg.round == round && cc.dkg.reset < reset) { return ErrDKGNotRegistered } + if cc.dkg.round != round || cc.dkg.reset != reset { + cc.logger.Warn("DKG canceled", "round", round, "reset", reset) + return nil + } cc.logger.Debug("Calling Governance.IsDKGFinal", "round", round) if cc.gov.IsDKGFinal(round) { cc.logger.Warn("DKG already final", "round", round) @@ -144,7 +148,9 @@ func (cc *configurationChain) runDKG(round uint64) error { cc.logger.Debug("Calling Governance.IsDKGMPKReady", "round", round) for !cc.gov.IsDKGMPKReady(round) { cc.logger.Debug("DKG MPKs are not ready yet. Try again later...", - "nodeID", cc.ID) + "nodeID", cc.ID.String()[:6], + "round", round, + "reset", reset) cc.dkgLock.Unlock() time.Sleep(500 * time.Millisecond) cc.dkgLock.Lock() @@ -165,18 +171,24 @@ func (cc *configurationChain) runDKG(round uint64) error { } } if !inProtocol { - cc.logger.Warn("Failed to join DKG protocol", "round", round) + cc.logger.Warn("Failed to join DKG protocol", + "round", round, + "reset", reset) return nil } // Phase 2(T = 0): Exchange DKG secret key share. if err := cc.dkg.processMasterPublicKeys(mpks); err != nil { cc.logger.Error("Failed to process master public key", + "round", round, + "reset", reset, "error", err) } cc.mpkReady = true for _, prvShare := range cc.pendingPrvShare { if err := cc.dkg.processPrivateShare(prvShare); err != nil { cc.logger.Error("Failed to process private share", + "round", round, + "reset", reset, "error", err) } } @@ -195,6 +207,8 @@ func (cc *configurationChain) runDKG(round uint64) error { complaints := cc.gov.DKGComplaints(round) if err := cc.dkg.processNackComplaints(complaints); err != nil { cc.logger.Error("Failed to process NackComplaint", + "round", round, + "reset", reset, "error", err) } cc.dkgLock.Unlock() @@ -222,7 +236,9 @@ func (cc *configurationChain) runDKG(round uint64) error { cc.logger.Debug("Calling Governance.IsDKGFinal", "round", round) for !cc.gov.IsDKGFinal(round) { cc.logger.Debug("DKG is not ready yet. Try again later...", - "nodeID", cc.ID) + "nodeID", cc.ID.String()[:6], + "round", round, + "reset", reset) time.Sleep(500 * time.Millisecond) } cc.logger.Debug("Calling Governance.DKGMasterPublicKeys", "round", round) @@ -241,10 +257,13 @@ func (cc *configurationChain) runDKG(round uint64) error { cc.logger.Info("Qualify Nodes", "nodeID", cc.ID, "round", round, + "reset", reset, "count", len(npks.QualifyIDs), "qualifies", qualifies) if _, exist := npks.QualifyNodeIDs[cc.ID]; !exist { - cc.logger.Warn("Self is not in Qualify Nodes") + cc.logger.Warn("Self is not in Qualify Nodes", + "round", round, + "reset", reset) return nil } signer, err := cc.dkg.recoverShareSecret(npks.QualifyIDs) diff --git a/core/configuration-chain_test.go b/core/configuration-chain_test.go index fd7e6a3..2edcade 100644 --- a/core/configuration-chain_test.go +++ b/core/configuration-chain_test.go @@ -195,7 +195,7 @@ func (s *ConfigurationChainTestSuite) setupNodes(n int) { } func (s *ConfigurationChainTestSuite) runDKG( - k, n int, round uint64) map[types.NodeID]*configurationChain { + k, n int, round, reset uint64) map[types.NodeID]*configurationChain { s.setupNodes(n) cfgChains := make(map[types.NodeID]*configurationChain) @@ -217,7 +217,7 @@ func (s *ConfigurationChainTestSuite) runDKG( } for _, cc := range cfgChains { - cc.registerDKG(round, k) + cc.registerDKG(round, reset, k) } for _, gov := range recv.govs { @@ -230,7 +230,7 @@ func (s *ConfigurationChainTestSuite) runDKG( for _, cc := range cfgChains { go func(cc *configurationChain) { defer wg.Done() - errs <- cc.runDKG(round) + errs <- cc.runDKG(round, reset) }(cc) } wg.Wait() @@ -272,7 +272,8 @@ func (s *ConfigurationChainTestSuite) TestConfigurationChain() { k := 4 n := 10 round := DKGDelayRound - cfgChains := s.runDKG(k, n, round) + reset := uint64(0) + cfgChains := s.runDKG(k, n, round, reset) hash := crypto.Keccak256Hash([]byte("🌚🌝")) psigs := s.preparePartialSignature(hash, round, cfgChains) @@ -317,6 +318,7 @@ func (s *ConfigurationChainTestSuite) TestDKGMasterPublicKeyDelayAdd() { k := 4 n := 10 round := DKGDelayRound + reset := uint64(0) lambdaDKG := 1000 * time.Millisecond s.setupNodes(n) @@ -345,10 +347,10 @@ func (s *ConfigurationChainTestSuite) TestDKGMasterPublicKeyDelayAdd() { if nID == delayNode { continue } - cc.registerDKG(round, k) + cc.registerDKG(round, reset, k) } time.Sleep(lambdaDKG) - cfgChains[delayNode].registerDKG(round, k) + cfgChains[delayNode].registerDKG(round, reset, k) for _, gov := range recv.govs { s.Require().Len(gov.DKGMasterPublicKeys(round), n-1) @@ -360,7 +362,7 @@ func (s *ConfigurationChainTestSuite) TestDKGMasterPublicKeyDelayAdd() { for _, cc := range cfgChains { go func(cc *configurationChain) { defer wg.Done() - errs <- cc.runDKG(round) + errs <- cc.runDKG(round, reset) }(cc) } wg.Wait() @@ -383,6 +385,7 @@ func (s *ConfigurationChainTestSuite) TestDKGComplaintDelayAdd() { k := 4 n := 10 round := DKGDelayRound + reset := uint64(0) lambdaDKG := 1000 * time.Millisecond s.setupNodes(n) @@ -407,7 +410,7 @@ func (s *ConfigurationChainTestSuite) TestDKGComplaintDelayAdd() { } for _, cc := range cfgChains { - cc.registerDKG(round, k) + cc.registerDKG(round, reset, k) } for _, gov := range recv.govs { @@ -420,7 +423,7 @@ func (s *ConfigurationChainTestSuite) TestDKGComplaintDelayAdd() { for _, cc := range cfgChains { go func(cc *configurationChain) { defer wg.Done() - errs <- cc.runDKG(round) + errs <- cc.runDKG(round, reset) }(cc) } go func() { @@ -459,7 +462,8 @@ func (s *ConfigurationChainTestSuite) TestMultipleTSig() { k := 2 n := 7 round := DKGDelayRound - cfgChains := s.runDKG(k, n, round) + reset := uint64(0) + cfgChains := s.runDKG(k, n, round, reset) hash1 := crypto.Keccak256Hash([]byte("Hash1")) hash2 := crypto.Keccak256Hash([]byte("Hash2")) @@ -519,7 +523,8 @@ func (s *ConfigurationChainTestSuite) TestTSigTimeout() { k := 2 n := 7 round := DKGDelayRound - cfgChains := s.runDKG(k, n, round) + reset := uint64(0) + cfgChains := s.runDKG(k, n, round, reset) timeout := 6 * time.Second hash := crypto.Keccak256Hash([]byte("🍯🍋")) @@ -556,7 +561,8 @@ func (s *ConfigurationChainTestSuite) TestDKGSignerRecoverFromDB() { k := 2 n := 7 round := DKGDelayRound - cfgChains := s.runDKG(k, n, round) + reset := uint64(0) + cfgChains := s.runDKG(k, n, round, reset) hash := crypto.Keccak256Hash([]byte("Hash1")) // Make sure we have more than one configurationChain instance. s.Require().True(len(cfgChains) > 0) diff --git a/core/consensus.go b/core/consensus.go index 8529e40..e0a6753 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -740,7 +740,7 @@ func (con *Consensus) prepare( con.logger.Info("Selected as DKG set", "round", nextRound) nextConfig := utils.GetConfigWithPanic(con.gov, nextRound, con.logger) - con.cfgModule.registerDKG(nextRound, utils.GetDKGThreshold( + con.cfgModule.registerDKG(nextRound, e.Reset, utils.GetDKGThreshold( nextConfig)) con.event.RegisterHeight(e.NextDKGPreparationHeight(), func(uint64) { @@ -749,7 +749,7 @@ func (con *Consensus) prepare( defer con.dkgReady.L.Unlock() con.dkgRunning = 0 }() - con.runDKG(nextRound, nextConfig) + con.runDKG(nextRound, e.Reset, nextConfig) }) }) }) @@ -805,7 +805,7 @@ func (con *Consensus) Run() { } // runDKG starts running DKG protocol. -func (con *Consensus) runDKG(round uint64, config *types.Config) { +func (con *Consensus) runDKG(round, reset uint64, config *types.Config) { con.dkgReady.L.Lock() defer con.dkgReady.L.Unlock() if con.dkgRunning != 0 { @@ -819,7 +819,7 @@ func (con *Consensus) runDKG(round uint64, config *types.Config) { con.dkgReady.Broadcast() con.dkgRunning = 2 }() - if err := con.cfgModule.runDKG(round); err != nil { + if err := con.cfgModule.runDKG(round, reset); err != nil { con.logger.Error("Failed to runDKG", "error", err) } }() @@ -841,8 +841,7 @@ func (con *Consensus) runCRS(round uint64, hash common.Hash) { "hash", psig.Hash) con.network.BroadcastDKGPartialSignature(psig) con.logger.Debug("Calling Governance.CRS", "round", round) - crs, err := con.cfgModule.runCRSTSig( - round, utils.GetCRSWithPanic(con.gov, round, con.logger)) + crs, err := con.cfgModule.runCRSTSig(round, hash) if err != nil { con.logger.Error("Failed to run CRS Tsig", "error", err) } else { diff --git a/core/consensus_test.go b/core/consensus_test.go index 75f5422..a7ac8c4 100644 --- a/core/consensus_test.go +++ b/core/consensus_test.go @@ -235,7 +235,7 @@ func (s *ConsensusTestSuite) TestRegisteredDKGRecover() { s.Require().Nil(con.cfgModule.dkg) - con.cfgModule.registerDKG(0, 10) + con.cfgModule.registerDKG(0, 0, 10) _, newCon := s.prepareConsensusWithDB(dMoment, gov, prvKeys[0], conn, dbInst) @@ -269,7 +269,7 @@ func (s *ConsensusTestSuite) TestDKGCRS() { } time.Sleep(gov.Configuration(0).MinBlockInterval * 4) for _, con := range cons { - go con.runDKG(0, gov.Configuration(0)) + go con.runDKG(0, 0, gov.Configuration(0)) } for _, con := range cons { func() { diff --git a/core/dkg-tsig-protocol.go b/core/dkg-tsig-protocol.go index 259d07a..82da6dc 100644 --- a/core/dkg-tsig-protocol.go +++ b/core/dkg-tsig-protocol.go @@ -60,6 +60,30 @@ var ( "self privateShare does not match mpk registered") ) +// ErrUnexpectedDKGResetCount represents receiving a DKG message with unexpected +// DKG reset count. +type ErrUnexpectedDKGResetCount struct { + expect, actual uint64 + proposerID types.NodeID +} + +func (e ErrUnexpectedDKGResetCount) Error() string { + return fmt.Sprintf( + "unexpected DKG reset count, from:%s expect:%d actual:%d", + e.proposerID.String()[:6], e.expect, e.actual) +} + +// ErrUnexpectedRound represents receiving a DKG message with unexpected round. +type ErrUnexpectedRound struct { + expect, actual uint64 + proposerID types.NodeID +} + +func (e ErrUnexpectedRound) Error() string { + return fmt.Sprintf("unexpected round, from:%s expect:%d actual:%d", + e.proposerID.String()[:6], e.expect, e.actual) +} + type dkgReceiver interface { // ProposeDKGComplaint proposes a DKGComplaint. ProposeDKGComplaint(complaint *typesDKG.Complaint) @@ -84,6 +108,7 @@ type dkgProtocol struct { ID types.NodeID recv dkgReceiver round uint64 + reset uint64 threshold int idMap map[types.NodeID]dkg.ID mpkMap map[types.NodeID]*dkg.PublicKeyShares @@ -140,12 +165,14 @@ func newDKGProtocol( ID types.NodeID, recv dkgReceiver, round uint64, + reset uint64, threshold int) *dkgProtocol { prvShare, pubShare := dkg.NewPrivateKeyShares(threshold) recv.ProposeDKGMasterPublicKey(&typesDKG.MasterPublicKey{ Round: round, + Reset: reset, DKGID: typesDKG.NewID(ID), PublicKeyShares: *pubShare, }) @@ -154,6 +181,7 @@ func newDKGProtocol( ID: ID, recv: recv, round: round, + reset: reset, threshold: threshold, idMap: make(map[types.NodeID]dkg.ID), mpkMap: make(map[types.NodeID]*dkg.PublicKeyShares), @@ -176,13 +204,17 @@ func recoverDKGProtocol( if err == db.ErrDKGMasterPrivateSharesDoesNotExist { return nil, nil } - return nil, err } + // TODO(mission): taken resetCount into consideration, we should keep + // reset count of private shares from DB, and use it to init + // DKG protocol instance. + reset := uint64(0) return &dkgProtocol{ ID: ID, recv: recv, round: round, + reset: reset, threshold: threshold, idMap: make(map[types.NodeID]dkg.ID), mpkMap: make(map[types.NodeID]*dkg.PublicKeyShares), @@ -201,6 +233,13 @@ func (d *dkgProtocol) processMasterPublicKeys( d.prvSharesReceived = make(map[types.NodeID]struct{}, len(mpks)) ids := make(dkg.IDs, len(mpks)) for i := range mpks { + if mpks[i].Reset != d.reset { + return ErrUnexpectedDKGResetCount{ + expect: d.reset, + actual: mpks[i].Reset, + proposerID: mpks[i].ProposerID, + } + } nID := mpks[i].ProposerID d.idMap[nID] = mpks[i].DKGID d.mpkMap[nID] = &mpks[i].PublicKeyShares @@ -219,6 +258,7 @@ func (d *dkgProtocol) processMasterPublicKeys( d.recv.ProposeDKGPrivateShare(&typesDKG.PrivateShare{ ReceiverID: mpk.ProposerID, Round: d.round, + Reset: d.reset, PrivateShare: *share, }) } @@ -252,9 +292,11 @@ func (d *dkgProtocol) proposeNackComplaints() { } d.recv.ProposeDKGComplaint(&typesDKG.Complaint{ Round: d.round, + Reset: d.reset, PrivateShare: typesDKG.PrivateShare{ ProposerID: nID, Round: d.round, + Reset: d.reset, }, }) } @@ -269,6 +311,9 @@ func (d *dkgProtocol) processNackComplaints(complaints []*typesDKG.Complaint) ( if !complaint.IsNack() { continue } + if complaint.Reset != d.reset { + continue + } if complaint.PrivateShare.ProposerID != d.ID { continue } @@ -286,6 +331,7 @@ func (d *dkgProtocol) processNackComplaints(complaints []*typesDKG.Complaint) ( ProposerID: d.ID, ReceiverID: complaint.ProposerID, Round: d.round, + Reset: d.reset, PrivateShare: *share, }) } @@ -297,6 +343,9 @@ func (d *dkgProtocol) enforceNackComplaints(complaints []*typesDKG.Complaint) { if !complaint.IsNack() { continue } + if complaint.Reset != d.reset { + continue + } to := complaint.PrivateShare.ProposerID // Do not propose nack complaint to itself. if to == d.ID { @@ -311,9 +360,11 @@ func (d *dkgProtocol) enforceNackComplaints(complaints []*typesDKG.Complaint) { d.antiComplaintReceived[from][to]; !exist { d.recv.ProposeDKGComplaint(&typesDKG.Complaint{ Round: d.round, + Reset: d.reset, PrivateShare: typesDKG.PrivateShare{ ProposerID: to, Round: d.round, + Reset: d.reset, }, }) } @@ -321,6 +372,20 @@ func (d *dkgProtocol) enforceNackComplaints(complaints []*typesDKG.Complaint) { } func (d *dkgProtocol) sanityCheck(prvShare *typesDKG.PrivateShare) error { + if d.round != prvShare.Round { + return ErrUnexpectedRound{ + expect: d.round, + actual: prvShare.Round, + proposerID: prvShare.ProposerID, + } + } + if d.reset != prvShare.Reset { + return ErrUnexpectedDKGResetCount{ + expect: d.reset, + actual: prvShare.Reset, + proposerID: prvShare.ProposerID, + } + } if _, exist := d.idMap[prvShare.ProposerID]; !exist { return ErrNotDKGParticipant } @@ -336,9 +401,6 @@ func (d *dkgProtocol) sanityCheck(prvShare *typesDKG.PrivateShare) error { func (d *dkgProtocol) processPrivateShare( prvShare *typesDKG.PrivateShare) error { - if d.round != prvShare.Round { - return nil - } receiverID, exist := d.idMap[prvShare.ReceiverID] // This node is not a DKG participant, ignore the private share. if !exist { @@ -361,6 +423,7 @@ func (d *dkgProtocol) processPrivateShare( } complaint := &typesDKG.Complaint{ Round: d.round, + Reset: d.reset, PrivateShare: *prvShare, } d.nodeComplained[prvShare.ProposerID] = struct{}{} @@ -387,6 +450,7 @@ func (d *dkgProtocol) proposeMPKReady() { d.recv.ProposeDKGMPKReady(&typesDKG.MPKReady{ ProposerID: d.ID, Round: d.round, + Reset: d.reset, }) } @@ -394,6 +458,7 @@ func (d *dkgProtocol) proposeFinalize() { d.recv.ProposeDKGFinalize(&typesDKG.Finalize{ ProposerID: d.ID, Round: d.round, + Reset: d.reset, }) } diff --git a/core/dkg-tsig-protocol_test.go b/core/dkg-tsig-protocol_test.go index 88d1443..a022605 100644 --- a/core/dkg-tsig-protocol_test.go +++ b/core/dkg-tsig-protocol_test.go @@ -119,7 +119,23 @@ func (s *DKGTSIGProtocolTestSuite) setupDKGParticipants(n int) { } } -func (s *DKGTSIGProtocolTestSuite) newProtocols(k, n int, round uint64) ( +func (s *DKGTSIGProtocolTestSuite) newGov( + pubKeys []crypto.PublicKey, + round, reset uint64) *test.Governance { + // NOTE: this method doesn't make the tip round in governance to the input + // one. + gov, err := test.NewGovernance(test.NewState(DKGDelayRound, + pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) + s.Require().NoError(err) + for i := uint64(0); i < reset; i++ { + s.Require().NoError(gov.State().RequestChange(test.StateResetDKG, + common.NewRandomHash())) + } + s.Require().Equal(gov.DKGResetCount(round), reset) + return gov +} + +func (s *DKGTSIGProtocolTestSuite) newProtocols(k, n int, round, reset uint64) ( map[types.NodeID]*testDKGReceiver, map[types.NodeID]*dkgProtocol) { s.setupDKGParticipants(n) @@ -131,6 +147,7 @@ func (s *DKGTSIGProtocolTestSuite) newProtocols(k, n int, round uint64) ( nID, receivers[nID], round, + reset, k, ) s.Require().NotNil(receivers[nID].mpk) @@ -146,13 +163,12 @@ func (s *DKGTSIGProtocolTestSuite) TestDKGTSIGProtocol() { k := 2 n := 10 round := uint64(1) + reset := uint64(3) _, pubKeys, err := test.NewKeys(5) s.Require().NoError(err) - gov, err := test.NewGovernance(test.NewState(DKGDelayRound, - pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) - s.Require().NoError(err) + gov := s.newGov(pubKeys, round, reset) - receivers, protocols := s.newProtocols(k, n, round) + receivers, protocols := s.newProtocols(k, n, round, reset) for _, receiver := range receivers { gov.AddDKGMasterPublicKey(round, receiver.mpk) @@ -259,13 +275,12 @@ func (s *DKGTSIGProtocolTestSuite) TestErrMPKRegistered() { k := 2 n := 10 round := uint64(1) + reset := uint64(2) _, pubKeys, err := test.NewKeys(5) s.Require().NoError(err) - gov, err := test.NewGovernance(test.NewState(DKGDelayRound, - pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) - s.Require().NoError(err) + gov := s.newGov(pubKeys, round, reset) - receivers, protocols := s.newProtocols(k, n, round) + receivers, protocols := s.newProtocols(k, n, round, reset) notRegisterID := s.nIDs[0] errRegisterID := s.nIDs[1] @@ -277,6 +292,7 @@ func (s *DKGTSIGProtocolTestSuite) TestErrMPKRegistered() { _, mpk := dkg.NewPrivateKeyShares(k) receiver.ProposeDKGMasterPublicKey(&typesDKG.MasterPublicKey{ Round: round, + Reset: reset, DKGID: typesDKG.NewID(ID), PublicKeyShares: *mpk, }) @@ -389,13 +405,12 @@ func (s *DKGTSIGProtocolTestSuite) TestNackComplaint() { k := 3 n := 10 round := uint64(1) + reset := uint64(3) _, pubKeys, err := test.NewKeys(5) s.Require().NoError(err) - gov, err := test.NewGovernance(test.NewState(DKGDelayRound, - pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) - s.Require().NoError(err) + gov := s.newGov(pubKeys, round, reset) - receivers, protocols := s.newProtocols(k, n, round) + receivers, protocols := s.newProtocols(k, n, round, reset) byzantineID := s.nIDs[0] @@ -436,13 +451,12 @@ func (s *DKGTSIGProtocolTestSuite) TestComplaint() { k := 3 n := 10 round := uint64(1) + reset := uint64(3) _, pubKeys, err := test.NewKeys(5) s.Require().NoError(err) - gov, err := test.NewGovernance(test.NewState(DKGDelayRound, - pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) - s.Require().NoError(err) + gov := s.newGov(pubKeys, round, reset) - receivers, protocols := s.newProtocols(k, n, round) + receivers, protocols := s.newProtocols(k, n, round, reset) byzantineID := s.nIDs[0] targetID := s.nIDs[1] @@ -463,12 +477,14 @@ func (s *DKGTSIGProtocolTestSuite) TestComplaint() { ProposerID: types.NodeID{Hash: common.NewRandomHash()}, ReceiverID: targetID, Round: round, + Reset: reset, }) s.Equal(ErrNotDKGParticipant, err) receivers[byzantineID].ProposeDKGPrivateShare(&typesDKG.PrivateShare{ ProposerID: byzantineID, ReceiverID: targetID, Round: round, + Reset: reset, }) invalidShare := receivers[byzantineID].prvShare[targetID] invalidShare.ReceiverID = s.nIDs[2] @@ -481,6 +497,7 @@ func (s *DKGTSIGProtocolTestSuite) TestComplaint() { ProposerID: byzantineID, ReceiverID: targetID, Round: round, + Reset: reset, PrivateShare: *dkg.NewPrivateKey(), }) invalidShare = receivers[byzantineID].prvShare[targetID] @@ -501,13 +518,12 @@ func (s *DKGTSIGProtocolTestSuite) TestDuplicateComplaint() { k := 3 n := 10 round := uint64(1) + reset := uint64(3) _, pubKeys, err := test.NewKeys(5) s.Require().NoError(err) - gov, err := test.NewGovernance(test.NewState(DKGDelayRound, - pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) - s.Require().NoError(err) + gov := s.newGov(pubKeys, round, reset) - receivers, _ := s.newProtocols(k, n, round) + receivers, _ := s.newProtocols(k, n, round, reset) byzantineID := s.nIDs[0] victomID := s.nIDs[1] @@ -522,9 +538,11 @@ func (s *DKGTSIGProtocolTestSuite) TestDuplicateComplaint() { complaints[i] = &typesDKG.Complaint{ ProposerID: byzantineID, Round: round, + Reset: reset, PrivateShare: typesDKG.PrivateShare{ ProposerID: victomID, Round: round, + Reset: reset, }, } s.Require().True(complaints[i].IsNack()) @@ -544,13 +562,12 @@ func (s *DKGTSIGProtocolTestSuite) TestAntiComplaint() { k := 3 n := 10 round := uint64(1) + reset := uint64(3) _, pubKeys, err := test.NewKeys(5) s.Require().NoError(err) - gov, err := test.NewGovernance(test.NewState(DKGDelayRound, - pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) - s.Require().NoError(err) + gov := s.newGov(pubKeys, round, reset) - receivers, protocols := s.newProtocols(k, n, round) + receivers, protocols := s.newProtocols(k, n, round, reset) byzantineID := s.nIDs[0] targetID := s.nIDs[1] @@ -602,13 +619,12 @@ func (s *DKGTSIGProtocolTestSuite) TestEncorceNackComplaint() { k := 3 n := 10 round := uint64(1) + reset := uint64(3) _, pubKeys, err := test.NewKeys(5) s.Require().NoError(err) - gov, err := test.NewGovernance(test.NewState(DKGDelayRound, - pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) - s.Require().NoError(err) + gov := s.newGov(pubKeys, round, reset) - receivers, protocols := s.newProtocols(k, n, round) + receivers, protocols := s.newProtocols(k, n, round, reset) byzantineID := s.nIDs[0] targetID := s.nIDs[1] @@ -657,13 +673,12 @@ func (s *DKGTSIGProtocolTestSuite) TestQualifyIDs() { k := 3 n := 10 round := uint64(1) + reset := uint64(3) _, pubKeys, err := test.NewKeys(5) s.Require().NoError(err) - gov, err := test.NewGovernance(test.NewState(DKGDelayRound, - pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) - s.Require().NoError(err) + gov := s.newGov(pubKeys, round, reset) - receivers, _ := s.newProtocols(k, n, round) + receivers, _ := s.newProtocols(k, n, round, reset) byzantineID := s.nIDs[0] @@ -678,9 +693,11 @@ func (s *DKGTSIGProtocolTestSuite) TestQualifyIDs() { complaints[i] = &typesDKG.Complaint{ ProposerID: nID, Round: round, + Reset: reset, PrivateShare: typesDKG.PrivateShare{ ProposerID: byzantineID, Round: round, + Reset: reset, }, } s.Require().True(complaints[i].IsNack()) @@ -723,13 +740,12 @@ func (s *DKGTSIGProtocolTestSuite) TestPartialSignature() { k := 3 n := 10 round := uint64(1) + reset := uint64(3) _, pubKeys, err := test.NewKeys(5) s.Require().NoError(err) - gov, err := test.NewGovernance(test.NewState(DKGDelayRound, - pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) - s.Require().NoError(err) + gov := s.newGov(pubKeys, round, reset) - receivers, protocols := s.newProtocols(k, n, round) + receivers, protocols := s.newProtocols(k, n, round, reset) byzantineID := s.nIDs[0] @@ -835,13 +851,14 @@ func (s *DKGTSIGProtocolTestSuite) TestProposeReady() { s.Require().NoError(err) recv := newTestDKGReceiver(s, utils.NewSigner(prvKey)) nID := types.NewNodeID(prvKey.PublicKey()) - protocol := newDKGProtocol(nID, recv, 1, 2) + protocol := newDKGProtocol(nID, recv, 1, 3, 2) protocol.proposeMPKReady() s.Require().Len(recv.ready, 1) ready := recv.ready[0] s.Equal(&typesDKG.MPKReady{ ProposerID: nID, Round: 1, + Reset: 3, }, ready) } @@ -850,28 +867,29 @@ func (s *DKGTSIGProtocolTestSuite) TestProposeFinalize() { s.Require().NoError(err) recv := newTestDKGReceiver(s, utils.NewSigner(prvKey)) nID := types.NewNodeID(prvKey.PublicKey()) - protocol := newDKGProtocol(nID, recv, 1, 2) + protocol := newDKGProtocol(nID, recv, 1, 3, 2) protocol.proposeFinalize() s.Require().Len(recv.final, 1) final := recv.final[0] s.Equal(&typesDKG.Finalize{ ProposerID: nID, Round: 1, + Reset: 3, }, final) } func (s *DKGTSIGProtocolTestSuite) TestTSigVerifierCache() { k := 3 n := 10 + round := uint64(10) + reset := uint64(0) _, pubKeys, err := test.NewKeys(n) s.Require().NoError(err) - gov, err := test.NewGovernance(test.NewState(DKGDelayRound, - pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) - s.Require().NoError(err) - gov.CatchUpWithRound(10) + gov := s.newGov(pubKeys, round, reset) + gov.CatchUpWithRound(round) for i := 0; i < 10; i++ { round := uint64(i + 1) - receivers, protocols := s.newProtocols(k, n, round) + receivers, protocols := s.newProtocols(k, n, round, reset) for _, receiver := range receivers { gov.AddDKGMasterPublicKey(round, receiver.mpk) @@ -939,6 +957,48 @@ func (s *DKGTSIGProtocolTestSuite) TestTSigVerifierCache() { } +func (s *DKGTSIGProtocolTestSuite) TestUnexpectedDKGResetCount() { + // MPKs and private shares from unexpected reset count should be ignored. + k := 2 + n := 10 + round := uint64(1) + reset := uint64(3) + receivers, protocols := s.newProtocols(k, n, round, reset) + var sourceID, targetID types.NodeID + for sourceID = range receivers { + break + } + for targetID = range receivers { + break + } + // Test private share + s.Require().NoError(protocols[targetID].processMasterPublicKeys( + []*typesDKG.MasterPublicKey{ + receivers[targetID].mpk, + receivers[sourceID].mpk})) + receivers[sourceID].ProposeDKGPrivateShare(&typesDKG.PrivateShare{ + ProposerID: sourceID, + ReceiverID: targetID, + Round: round, + Reset: reset + 1, + PrivateShare: *dkg.NewPrivateKey(), + }) + err := protocols[targetID].processPrivateShare( + receivers[sourceID].prvShare[targetID]) + s.Require().IsType(ErrUnexpectedDKGResetCount{}, err) + // Test MPK. + _, mpk := dkg.NewPrivateKeyShares(k) + receivers[sourceID].ProposeDKGMasterPublicKey(&typesDKG.MasterPublicKey{ + Round: round, + Reset: reset + 1, + DKGID: typesDKG.NewID(sourceID), + PublicKeyShares: *mpk, + }) + err = protocols[sourceID].processMasterPublicKeys( + []*typesDKG.MasterPublicKey{receivers[sourceID].mpk}) + s.Require().IsType(ErrUnexpectedDKGResetCount{}, err) +} + func TestDKGTSIGProtocol(t *testing.T) { suite.Run(t, new(DKGTSIGProtocolTestSuite)) } @@ -950,6 +1010,7 @@ func BenchmarkGPK81_121(b *testing.B) { benchmarkDKGGroupPubliKey(81, 121, b) } func benchmarkDKGGroupPubliKey(k, n int, b *testing.B) { round := uint64(1) + reset := uint64(0) _, pubKeys, err := test.NewKeys(n) if err != nil { panic(err) @@ -965,6 +1026,7 @@ func benchmarkDKGGroupPubliKey(k, n int, b *testing.B) { gov.AddDKGMasterPublicKey(round, &typesDKG.MasterPublicKey{ ProposerID: types.NewNodeID(pk), Round: round, + Reset: reset, DKGID: typesDKG.NewID(types.NewNodeID(pk)), PublicKeyShares: *pubShare, }) @@ -993,6 +1055,7 @@ func BenchmarkNPKs81_121(b *testing.B) { benchmarkDKGNodePubliKeys(81, 121, b) } func benchmarkDKGNodePubliKeys(k, n int, b *testing.B) { round := uint64(1) + reset := uint64(0) _, pubKeys, err := test.NewKeys(n) if err != nil { panic(err) @@ -1008,6 +1071,7 @@ func benchmarkDKGNodePubliKeys(k, n int, b *testing.B) { gov.AddDKGMasterPublicKey(round, &typesDKG.MasterPublicKey{ ProposerID: types.NewNodeID(pk), Round: round, + Reset: reset, DKGID: typesDKG.NewID(types.NewNodeID(pk)), PublicKeyShares: *pubShare, }) diff --git a/core/test/app_test.go b/core/test/app_test.go index 7ac9ef9..1579549 100644 --- a/core/test/app_test.go +++ b/core/test/app_test.go @@ -71,12 +71,16 @@ func (s *AppTestSuite) prepareGov() *Governance { return gov } -func (s *AppTestSuite) proposeMPK(gov *Governance, round uint64, count int) { +func (s *AppTestSuite) proposeMPK( + gov *Governance, + round, reset uint64, + count int) { for idx, pubKey := range s.pubKeys[:count] { _, pubShare := dkg.NewPrivateKeyShares(utils.GetDKGThreshold( gov.Configuration(round))) mpk := &typesDKG.MasterPublicKey{ Round: round, + Reset: reset, DKGID: typesDKG.NewID(types.NewNodeID(pubKey)), PublicKeyShares: *pubShare, } @@ -85,12 +89,15 @@ func (s *AppTestSuite) proposeMPK(gov *Governance, round uint64, count int) { } } -func (s *AppTestSuite) proposeFinalize(gov *Governance, round uint64, +func (s *AppTestSuite) proposeFinalize( + gov *Governance, + round, reset uint64, count int) { for idx, pubKey := range s.pubKeys[:count] { final := &typesDKG.Finalize{ ProposerID: types.NewNodeID(pubKey), Round: round, + Reset: reset, } s.Require().NoError(s.signers[idx].SignDKGFinalize(final)) gov.AddDKGFinalize(round, final) @@ -286,17 +293,17 @@ func (s *AppTestSuite) TestAttachedWithRoundEvent() { // Reset round#20 twice, then make it done DKG preparation. gov.ResetDKG(getCRS(20, 1)) gov.ResetDKG(getCRS(20, 2)) - s.proposeMPK(gov, 20, 3) - s.proposeFinalize(gov, 20, 3) + s.proposeMPK(gov, 20, 2, 3) + s.proposeFinalize(gov, 20, 2, 3) s.Require().Equal(gov.DKGResetCount(20), uint64(2)) // Propose CRS for round#21, and it works without reset. gov.ProposeCRS(21, getCRS(21, 0)) - s.proposeMPK(gov, 21, 3) - s.proposeFinalize(gov, 21, 3) + s.proposeMPK(gov, 21, 0, 3) + s.proposeFinalize(gov, 21, 0, 3) // Propose CRS for round#22, and it works without reset. gov.ProposeCRS(22, getCRS(22, 0)) - s.proposeMPK(gov, 22, 3) - s.proposeFinalize(gov, 22, 3) + s.proposeMPK(gov, 22, 0, 3) + s.proposeFinalize(gov, 22, 0, 3) // Prepare utils.RoundEvent, starts from round#19, reset(for round#20)#1. rEvt, err := utils.NewRoundEvent(context.Background(), gov, s.logger, 19, 1900, 2019, core.ConfigRoundShift) diff --git a/core/test/state.go b/core/test/state.go index fbf4505..89d2e90 100644 --- a/core/test/state.go +++ b/core/test/state.go @@ -74,6 +74,12 @@ var ( // ErrStatePendingChangesNotEqual means pending change requests of two // states are not equal. ErrStatePendingChangesNotEqual = errors.New("pending changes not equal") + // ErrChangeWontApply means the state change won't be applied for some + // reason. + ErrChangeWontApply = errors.New("change won't apply") + // ErrUnmatchedResetCount means an DKG message attempt to apply is not + // the latest reset count in State module. + ErrUnmatchedResetCount = errors.New("unmatched reset count of DKG message") // ErrNotInRemoteMode means callers attempts to call functions for remote // mode when the State instance is still in local mode. ErrNotInRemoteMode = errors.New( @@ -628,20 +634,33 @@ func (s *State) PackOwnRequests() (b []byte, err error) { } // isValidRequest checks if this request is valid to proceed or not. -func (s *State) isValidRequest(req *StateChangeRequest) (err error) { +func (s *State) isValidRequest(req *StateChangeRequest) error { // NOTE: there would be no lock in this helper, callers should be // responsible for acquiring appropriate lock. switch req.Type { + case StateAddDKGMPKReady: + ready := req.Payload.(*typesDKG.MPKReady) + if ready.Reset != s.dkgResetCount[ready.Round] { + return ErrUnmatchedResetCount + } + case StateAddDKGFinal: + final := req.Payload.(*typesDKG.Finalize) + if final.Reset != s.dkgResetCount[final.Round] { + return ErrUnmatchedResetCount + } case StateAddDKGMasterPublicKey: mpk := req.Payload.(*typesDKG.MasterPublicKey) + if mpk.Reset != s.dkgResetCount[mpk.Round] { + return ErrUnmatchedResetCount + } // If we've received identical MPK, ignore it. mpkForRound, exists := s.dkgMasterPublicKeys[mpk.Round] if exists { if oldMpk, exists := mpkForRound[mpk.ProposerID]; exists { if !oldMpk.Equal(mpk) { - err = ErrDuplicatedChange + return ErrDuplicatedChange } - return + return ErrChangeWontApply } } // If we've received MPK from that proposer, we would ignore @@ -651,6 +670,9 @@ func (s *State) isValidRequest(req *StateChangeRequest) (err error) { } case StateAddDKGComplaint: comp := req.Payload.(*typesDKG.Complaint) + if comp.Reset != s.dkgResetCount[comp.Round] { + return ErrUnmatchedResetCount + } // If we've received DKG final from that proposer, we would ignore // its complaint. if _, exists := s.dkgFinals[comp.Round][comp.ProposerID]; exists { @@ -687,6 +709,8 @@ func (s *State) isValidRequest(req *StateChangeRequest) (err error) { if s.crs[len(s.crs)-1].Equal(newCRS) { return ErrDuplicatedChange } + // TODO(mission): find a smart way to make sure the caller call request + // this change with correct resetCount. } return nil } diff --git a/core/test/state_test.go b/core/test/state_test.go index 8d2b2a2..2adfc95 100644 --- a/core/test/state_test.go +++ b/core/test/state_test.go @@ -37,7 +37,7 @@ type StateTestSuite struct { } func (s *StateTestSuite) newDKGMasterPublicKey( - round uint64) *typesDKG.MasterPublicKey { + round uint64, reset uint64) *typesDKG.MasterPublicKey { prvKey, err := ecdsa.NewPrivateKey() s.Require().NoError(err) pubKey := prvKey.PublicKey() @@ -48,21 +48,25 @@ func (s *StateTestSuite) newDKGMasterPublicKey( return &typesDKG.MasterPublicKey{ ProposerID: nodeID, Round: round, + Reset: reset, DKGID: dID, PublicKeyShares: *pubShare, } } -func (s *StateTestSuite) newDKGComplaint(round uint64) *typesDKG.Complaint { +func (s *StateTestSuite) newDKGComplaint( + round uint64, reset uint64) *typesDKG.Complaint { prvKey, err := ecdsa.NewPrivateKey() s.Require().NoError(err) nodeID := types.NewNodeID(prvKey.PublicKey()) comp := &typesDKG.Complaint{ Round: round, + Reset: reset, PrivateShare: typesDKG.PrivateShare{ ProposerID: nodeID, ReceiverID: nodeID, Round: round, + Reset: reset, PrivateShare: *dkg.NewPrivateKey(), }, } @@ -73,17 +77,19 @@ func (s *StateTestSuite) newDKGComplaint(round uint64) *typesDKG.Complaint { return comp } -func (s *StateTestSuite) newDKGMPKReady(round uint64) *typesDKG.MPKReady { +func (s *StateTestSuite) newDKGMPKReady( + round uint64, reset uint64) *typesDKG.MPKReady { prvKey, err := ecdsa.NewPrivateKey() s.Require().NoError(err) - ready := &typesDKG.MPKReady{Round: round} + ready := &typesDKG.MPKReady{Round: round, Reset: reset} s.Require().NoError(utils.NewSigner(prvKey).SignDKGMPKReady(ready)) return ready } -func (s *StateTestSuite) newDKGFinal(round uint64) *typesDKG.Finalize { +func (s *StateTestSuite) newDKGFinal( + round uint64, reset uint64) *typesDKG.Finalize { prvKey, err := ecdsa.NewPrivateKey() s.Require().NoError(err) - final := &typesDKG.Finalize{Round: round} + final := &typesDKG.Finalize{Round: round, Reset: reset} s.Require().NoError(utils.NewSigner(prvKey).SignDKGFinalize(final)) return final } @@ -128,10 +134,11 @@ func (s *StateTestSuite) makeDKGChanges( ready *typesDKG.MPKReady, complaint *typesDKG.Complaint, final *typesDKG.Finalize) { - st.RequestChange(StateAddDKGMasterPublicKey, masterPubKey) - st.RequestChange(StateAddDKGMPKReady, ready) - st.RequestChange(StateAddDKGComplaint, complaint) - st.RequestChange(StateAddDKGFinal, final) + s.Require().NoError(st.RequestChange(StateAddDKGMasterPublicKey, + masterPubKey)) + s.Require().NoError(st.RequestChange(StateAddDKGMPKReady, ready)) + s.Require().NoError(st.RequestChange(StateAddDKGComplaint, complaint)) + s.Require().NoError(st.RequestChange(StateAddDKGFinal, final)) } func (s *StateTestSuite) makeConfigChanges(st *State) { @@ -173,39 +180,39 @@ func (s *StateTestSuite) TestEqual() { st2 := st.Clone() req.NoError(st.Equal(st2)) s.makeConfigChanges(st) - req.Equal(st.Equal(st2), ErrStateConfigNotEqual) + req.EqualError(ErrStateConfigNotEqual, st.Equal(st2).Error()) req.NoError(st.ProposeCRS(2, common.NewRandomHash())) req.NoError(st.RequestChange(StateResetDKG, common.NewRandomHash())) - masterPubKey := s.newDKGMasterPublicKey(2) - ready := s.newDKGMPKReady(2) - comp := s.newDKGComplaint(2) - final := s.newDKGFinal(2) + masterPubKey := s.newDKGMasterPublicKey(2, 1) + ready := s.newDKGMPKReady(2, 1) + comp := s.newDKGComplaint(2, 1) + final := s.newDKGFinal(2, 1) s.makeDKGChanges(st, masterPubKey, ready, comp, final) // Remove dkg complaints from cloned one to check if equal. st3 := st.Clone() req.NoError(st.Equal(st3)) delete(st3.dkgComplaints, uint64(2)) - req.Equal(st.Equal(st3), ErrStateDKGComplaintsNotEqual) + req.EqualError(ErrStateDKGComplaintsNotEqual, st.Equal(st3).Error()) // Remove dkg master public key from cloned one to check if equal. st4 := st.Clone() req.NoError(st.Equal(st4)) delete(st4.dkgMasterPublicKeys, uint64(2)) - req.Equal(st.Equal(st4), ErrStateDKGMasterPublicKeysNotEqual) + req.EqualError(ErrStateDKGMasterPublicKeysNotEqual, st.Equal(st4).Error()) // Remove dkg ready from cloned one to check if equal. st4a := st.Clone() req.NoError(st.Equal(st4a)) delete(st4a.dkgReadys, uint64(2)) - req.Equal(st.Equal(st4a), ErrStateDKGMPKReadysNotEqual) + req.EqualError(ErrStateDKGMPKReadysNotEqual, st.Equal(st4a).Error()) // Remove dkg finalize from cloned one to check if equal. st5 := st.Clone() req.NoError(st.Equal(st5)) delete(st5.dkgFinals, uint64(2)) - req.Equal(st.Equal(st5), ErrStateDKGFinalsNotEqual) + req.EqualError(ErrStateDKGFinalsNotEqual, st.Equal(st5).Error()) // Remove dkgResetCount from cloned one to check if equal. st6 := st.Clone() req.NoError(st.Equal(st6)) delete(st6.dkgResetCount, uint64(2)) - req.Equal(st.Equal(st6), ErrStateDKGResetCountNotEqual) + req.EqualError(ErrStateDKGResetCountNotEqual, st.Equal(st6).Error()) // Switch to remote mode. st.SwitchToRemoteMode() @@ -218,7 +225,7 @@ func (s *StateTestSuite) TestEqual() { for k := range str.ownRequests { delete(str.ownRequests, k) } - req.Error(ErrStatePendingChangesNotEqual, st.Equal(str)) + req.EqualError(ErrStatePendingChangesNotEqual, st.Equal(str).Error()) } func (s *StateTestSuite) TestPendingChangesEqual() { @@ -235,10 +242,10 @@ func (s *StateTestSuite) TestPendingChangesEqual() { s.makeConfigChanges(st) crs := common.NewRandomHash() req.NoError(st.ProposeCRS(2, crs)) - masterPubKey := s.newDKGMasterPublicKey(2) - ready := s.newDKGMPKReady(2) - comp := s.newDKGComplaint(2) - final := s.newDKGFinal(2) + masterPubKey := s.newDKGMasterPublicKey(2, 0) + ready := s.newDKGMPKReady(2, 0) + comp := s.newDKGComplaint(2, 0) + final := s.newDKGFinal(2, 0) s.makeDKGChanges(st, masterPubKey, ready, comp, final) } @@ -282,10 +289,10 @@ func (s *StateTestSuite) TestLocalMode() { req.Empty(st.DKGComplaints(2)) req.False(st.IsDKGFinal(2, 0)) // Add DKG stuffs. - masterPubKey := s.newDKGMasterPublicKey(2) - ready := s.newDKGMPKReady(2) - comp := s.newDKGComplaint(2) - final := s.newDKGFinal(2) + masterPubKey := s.newDKGMasterPublicKey(2, 0) + ready := s.newDKGMPKReady(2, 0) + comp := s.newDKGComplaint(2, 0) + final := s.newDKGFinal(2, 0) s.makeDKGChanges(st, masterPubKey, ready, comp, final) // Check DKGMasterPublicKeys. masterKeyForRound := st.DKGMasterPublicKeys(2) @@ -342,10 +349,10 @@ func (s *StateTestSuite) TestPacking() { pubKey := prvKey.PublicKey() st.RequestChange(StateAddNode, pubKey) // Add DKG stuffs. - masterPubKey := s.newDKGMasterPublicKey(2) - ready := s.newDKGMPKReady(2) - comp := s.newDKGComplaint(2) - final := s.newDKGFinal(2) + masterPubKey := s.newDKGMasterPublicKey(2, 0) + ready := s.newDKGMPKReady(2, 0) + comp := s.newDKGComplaint(2, 0) + final := s.newDKGFinal(2, 0) s.makeDKGChanges(st, masterPubKey, ready, comp, final) // Make sure everything is empty before changed. req.Empty(st.DKGMasterPublicKeys(2)) @@ -383,7 +390,6 @@ func (s *StateTestSuite) TestPacking() { req.False(st.IsDKGMPKReady(2, 0)) req.Empty(st.DKGComplaints(2)) req.False(st.IsDKGFinal(2, 0)) - } func (s *StateTestSuite) TestRequestBroadcastAndPack() { @@ -414,10 +420,10 @@ func (s *StateTestSuite) TestRequestBroadcastAndPack() { pubKey := prvKey.PublicKey() st.RequestChange(StateAddNode, pubKey) // Add DKG stuffs. - masterPubKey := s.newDKGMasterPublicKey(2) - ready := s.newDKGMPKReady(2) - comp := s.newDKGComplaint(2) - final := s.newDKGFinal(2) + masterPubKey := s.newDKGMasterPublicKey(2, 0) + ready := s.newDKGMPKReady(2, 0) + comp := s.newDKGComplaint(2, 0) + final := s.newDKGFinal(2, 0) s.makeDKGChanges(st, masterPubKey, ready, comp, final) // Pack those changes into a byte stream, and pass it to other State // instance. @@ -448,6 +454,42 @@ func (s *StateTestSuite) TestRequestBroadcastAndPack() { req.NoError(st.Equal(st1)) } +func (s *StateTestSuite) TestUnmatchedResetCount() { + _, genesisNodes, err := NewKeys(20) + s.Require().NoError(err) + st := NewState(1, genesisNodes, 100*time.Millisecond, + &common.NullLogger{}, true) + // Make sure the case in older version without reset won't fail. + mpk := s.newDKGMasterPublicKey(1, 0) + ready := s.newDKGMPKReady(1, 0) + comp := s.newDKGComplaint(1, 0) + final := s.newDKGFinal(1, 0) + s.Require().NoError(st.RequestChange(StateAddDKGMasterPublicKey, mpk)) + s.Require().NoError(st.RequestChange(StateAddDKGMPKReady, ready)) + s.Require().NoError(st.RequestChange(StateAddDKGComplaint, comp)) + s.Require().NoError(st.RequestChange(StateAddDKGFinal, final)) + // Make round 1 reset twice. + s.Require().NoError(st.RequestChange(StateResetDKG, common.NewRandomHash())) + s.Require().NoError(st.RequestChange(StateResetDKG, common.NewRandomHash())) + s.Require().Equal(st.dkgResetCount[1], uint64(2)) + s.Require().EqualError(ErrUnmatchedResetCount, st.RequestChange( + StateAddDKGMasterPublicKey, mpk).Error()) + s.Require().EqualError(ErrUnmatchedResetCount, st.RequestChange( + StateAddDKGMPKReady, ready).Error()) + s.Require().EqualError(ErrUnmatchedResetCount, st.RequestChange( + StateAddDKGComplaint, comp).Error()) + s.Require().EqualError(ErrUnmatchedResetCount, st.RequestChange( + StateAddDKGFinal, final).Error()) + mpk = s.newDKGMasterPublicKey(1, 2) + ready = s.newDKGMPKReady(1, 2) + comp = s.newDKGComplaint(1, 2) + final = s.newDKGFinal(1, 2) + s.Require().NoError(st.RequestChange(StateAddDKGMasterPublicKey, mpk)) + s.Require().NoError(st.RequestChange(StateAddDKGMPKReady, ready)) + s.Require().NoError(st.RequestChange(StateAddDKGComplaint, comp)) + s.Require().NoError(st.RequestChange(StateAddDKGFinal, final)) +} + func TestState(t *testing.T) { suite.Run(t, new(StateTestSuite)) } diff --git a/core/types/dkg/dkg.go b/core/types/dkg/dkg.go index 1052ccb..6572d1e 100644 --- a/core/types/dkg/dkg.go +++ b/core/types/dkg/dkg.go @@ -47,6 +47,7 @@ type PrivateShare struct { ProposerID types.NodeID `json:"proposer_id"` ReceiverID types.NodeID `json:"receiver_id"` Round uint64 `json:"round"` + Reset uint64 `json:"reset"` PrivateShare cryptoDKG.PrivateKey `json:"private_share"` Signature crypto.Signature `json:"signature"` } @@ -56,6 +57,7 @@ func (p *PrivateShare) Equal(other *PrivateShare) bool { return p.ProposerID.Equal(other.ProposerID) && p.ReceiverID.Equal(other.ReceiverID) && p.Round == other.Round && + p.Reset == other.Reset && p.Signature.Type == other.Signature.Type && bytes.Compare(p.Signature.Signature, other.Signature.Signature) == 0 && bytes.Compare( @@ -66,21 +68,24 @@ func (p *PrivateShare) Equal(other *PrivateShare) bool { type MasterPublicKey struct { ProposerID types.NodeID `json:"proposer_id"` Round uint64 `json:"round"` + Reset uint64 `json:"reset"` DKGID cryptoDKG.ID `json:"dkg_id"` PublicKeyShares cryptoDKG.PublicKeyShares `json:"public_key_shares"` Signature crypto.Signature `json:"signature"` } func (d *MasterPublicKey) String() string { - return fmt.Sprintf("MasterPublicKey{KP:%s Round:%d}", + return fmt.Sprintf("MasterPublicKey{KP:%s Round:%d Reset:%d}", d.ProposerID.String()[:6], - d.Round) + d.Round, + d.Reset) } // Equal check equality of two DKG master public keys. func (d *MasterPublicKey) Equal(other *MasterPublicKey) bool { return d.ProposerID.Equal(other.ProposerID) && d.Round == other.Round && + d.Reset == other.Reset && d.DKGID.GetHexString() == other.DKGID.GetHexString() && d.PublicKeyShares.Equal(&other.PublicKeyShares) && d.Signature.Type == other.Signature.Type && @@ -90,6 +95,7 @@ func (d *MasterPublicKey) Equal(other *MasterPublicKey) bool { type rlpMasterPublicKey struct { ProposerID types.NodeID Round uint64 + Reset uint64 DKGID []byte PublicKeyShares *cryptoDKG.PublicKeyShares Signature crypto.Signature @@ -100,6 +106,7 @@ func (d *MasterPublicKey) EncodeRLP(w io.Writer) error { return rlp.Encode(w, rlpMasterPublicKey{ ProposerID: d.ProposerID, Round: d.Round, + Reset: d.Reset, DKGID: d.DKGID.GetLittleEndian(), PublicKeyShares: &d.PublicKeyShares, Signature: d.Signature, @@ -121,6 +128,7 @@ func (d *MasterPublicKey) DecodeRLP(s *rlp.Stream) error { *d = MasterPublicKey{ ProposerID: dec.ProposerID, Round: dec.Round, + Reset: dec.Reset, DKGID: id, PublicKeyShares: *dec.PublicKeyShares, Signature: dec.Signature, @@ -146,24 +154,26 @@ func (d *MasterPublicKey) UnmarshalJSON(data []byte) error { type Complaint struct { ProposerID types.NodeID `json:"proposer_id"` Round uint64 `json:"round"` + Reset uint64 `json:"reset"` PrivateShare PrivateShare `json:"private_share"` Signature crypto.Signature `json:"signature"` } func (c *Complaint) String() string { if c.IsNack() { - return fmt.Sprintf("DKGNackComplaint{CP:%s Round:%d PSP:%s}", - c.ProposerID.String()[:6], c.Round, + return fmt.Sprintf("DKGNackComplaint{CP:%s Round:%d Reset %d PSP:%s}", + c.ProposerID.String()[:6], c.Round, c.Reset, c.PrivateShare.ProposerID.String()[:6]) } - return fmt.Sprintf("DKGComplaint{CP:%s Round:%d PrivateShare:%v}", - c.ProposerID.String()[:6], c.Round, c.PrivateShare) + return fmt.Sprintf("DKGComplaint{CP:%s Round:%d Reset %d PrivateShare:%v}", + c.ProposerID.String()[:6], c.Round, c.Reset, c.PrivateShare) } // Equal checks equality between two Complaint instances. func (c *Complaint) Equal(other *Complaint) bool { return c.ProposerID.Equal(other.ProposerID) && c.Round == other.Round && + c.Reset == other.Reset && c.PrivateShare.Equal(&other.PrivateShare) && c.Signature.Type == other.Signature.Type && bytes.Compare(c.Signature.Signature, other.Signature.Signature) == 0 @@ -172,6 +182,7 @@ func (c *Complaint) Equal(other *Complaint) bool { type rlpComplaint struct { ProposerID types.NodeID Round uint64 + Reset uint64 IsNack bool PrivateShare []byte Signature crypto.Signature @@ -183,6 +194,7 @@ func (c *Complaint) EncodeRLP(w io.Writer) error { return rlp.Encode(w, rlpComplaint{ ProposerID: c.ProposerID, Round: c.Round, + Reset: c.Reset, IsNack: true, PrivateShare: c.PrivateShare.ProposerID.Hash[:], Signature: c.Signature, @@ -195,6 +207,7 @@ func (c *Complaint) EncodeRLP(w io.Writer) error { return rlp.Encode(w, rlpComplaint{ ProposerID: c.ProposerID, Round: c.Round, + Reset: c.Reset, IsNack: false, PrivateShare: prvShare, Signature: c.Signature, @@ -212,6 +225,7 @@ func (c *Complaint) DecodeRLP(s *rlp.Stream) error { if dec.IsNack { copy(prvShare.ProposerID.Hash[:], dec.PrivateShare) prvShare.Round = dec.Round + prvShare.Reset = dec.Reset } else { if err := rlp.DecodeBytes(dec.PrivateShare, &prvShare); err != nil { return err @@ -221,6 +235,7 @@ func (c *Complaint) DecodeRLP(s *rlp.Stream) error { *c = Complaint{ ProposerID: dec.ProposerID, Round: dec.Round, + Reset: dec.Reset, PrivateShare: prvShare, Signature: dec.Signature, } @@ -240,19 +255,22 @@ type PartialSignature struct { type MPKReady struct { ProposerID types.NodeID `json:"proposer_id"` Round uint64 `json:"round"` + Reset uint64 `json:"reset"` Signature crypto.Signature `json:"signature"` } func (ready *MPKReady) String() string { - return fmt.Sprintf("DKGMPKReady{RP:%s Round:%d}", + return fmt.Sprintf("DKGMPKReady{RP:%s Round:%d Reset:%d}", ready.ProposerID.String()[:6], - ready.Round) + ready.Round, + ready.Reset) } // Equal check equality of two MPKReady instances. func (ready *MPKReady) Equal(other *MPKReady) bool { return ready.ProposerID.Equal(other.ProposerID) && ready.Round == other.Round && + ready.Reset == other.Reset && ready.Signature.Type == other.Signature.Type && bytes.Compare(ready.Signature.Signature, other.Signature.Signature) == 0 } @@ -261,19 +279,22 @@ func (ready *MPKReady) Equal(other *MPKReady) bool { type Finalize struct { ProposerID types.NodeID `json:"proposer_id"` Round uint64 `json:"round"` + Reset uint64 `json:"reset"` Signature crypto.Signature `json:"signature"` } func (final *Finalize) String() string { - return fmt.Sprintf("DKGFinal{FP:%s Round:%d}", + return fmt.Sprintf("DKGFinal{FP:%s Round:%d Reset:%d}", final.ProposerID.String()[:6], - final.Round) + final.Round, + final.Reset) } // Equal check equality of two Finalize instances. func (final *Finalize) Equal(other *Finalize) bool { return final.ProposerID.Equal(other.ProposerID) && final.Round == other.Round && + final.Reset == other.Reset && final.Signature.Type == other.Signature.Type && bytes.Compare(final.Signature.Signature, other.Signature.Signature) == 0 } diff --git a/core/types/dkg/dkg_test.go b/core/types/dkg/dkg_test.go index 8fe6e9b..ec16a2b 100644 --- a/core/types/dkg/dkg_test.go +++ b/core/types/dkg/dkg_test.go @@ -61,6 +61,7 @@ func (s *DKGTestSuite) TestRLPEncodeDecode() { d := MasterPublicKey{ ProposerID: types.NodeID{Hash: common.Hash{1, 2, 3}}, Round: 10, + Reset: 11, DKGID: dID, PublicKeyShares: *pubShare, Signature: crypto.Signature{ @@ -89,6 +90,7 @@ func (s *DKGTestSuite) TestRLPEncodeDecode() { p := PrivateShare{ ProposerID: types.NodeID{Hash: common.Hash{1, 3, 5}}, Round: 10, + Reset: 11, PrivateShare: *cryptoDKG.NewPrivateKey(), Signature: crypto.Signature{ Type: "123", @@ -115,9 +117,11 @@ func (s *DKGTestSuite) TestRLPEncodeDecode() { c := Complaint{ ProposerID: d.ProposerID, Round: 10, + Reset: 11, PrivateShare: PrivateShare{ ProposerID: p.ProposerID, Round: 10, + Reset: 11, }, Signature: crypto.Signature{ Type: "123", @@ -145,6 +149,7 @@ func (s *DKGTestSuite) TestRLPEncodeDecode() { c = Complaint{ ProposerID: d.ProposerID, Round: 10, + Reset: 11, PrivateShare: p, Signature: crypto.Signature{ Type: "123", @@ -174,6 +179,7 @@ func (s *DKGTestSuite) TestMasterPublicKeyEquality() { master1 := &MasterPublicKey{ ProposerID: types.NodeID{Hash: common.NewRandomHash()}, Round: 1234, + Reset: 5678, DKGID: s.genID(), Signature: crypto.Signature{ Signature: s.genRandomBytes(), @@ -193,6 +199,10 @@ func (s *DKGTestSuite) TestMasterPublicKeyEquality() { master2.Round = 2345 req.False(master1.Equal(master2)) master2.Round = 1234 + // Change reset. + master2.Reset = 6789 + req.False(master1.Equal(master2)) + master2.Reset = 5678 // Change proposerID. master2.ProposerID = types.NodeID{Hash: common.NewRandomHash()} req.False(master1.Equal(master2)) @@ -218,6 +228,7 @@ func (s *DKGTestSuite) TestPrivateShareEquality() { ProposerID: types.NodeID{Hash: common.NewRandomHash()}, ReceiverID: types.NodeID{Hash: common.NewRandomHash()}, Round: 1, + Reset: 2, PrivateShare: *cryptoDKG.NewPrivateKey(), Signature: crypto.Signature{ Signature: s.genRandomBytes(), @@ -239,6 +250,10 @@ func (s *DKGTestSuite) TestPrivateShareEquality() { share2.Round = share1.Round + 1 req.False(share1.Equal(share2)) share2.Round = share1.Round + // Change reset. + share2.Reset = share1.Reset + 1 + req.False(share1.Equal(share2)) + share2.Reset = share1.Reset // Change signature. share2.Signature = crypto.Signature{ Signature: s.genRandomBytes(), @@ -258,10 +273,12 @@ func (s *DKGTestSuite) TestComplaintEquality() { comp1 := &Complaint{ ProposerID: types.NodeID{Hash: common.NewRandomHash()}, Round: 1, + Reset: 2, PrivateShare: PrivateShare{ ProposerID: types.NodeID{Hash: common.NewRandomHash()}, ReceiverID: types.NodeID{Hash: common.NewRandomHash()}, Round: 2, + Reset: 3, PrivateShare: *cryptoDKG.NewPrivateKey(), Signature: crypto.Signature{ Signature: s.genRandomBytes(), @@ -283,6 +300,10 @@ func (s *DKGTestSuite) TestComplaintEquality() { comp2.Round = comp1.Round + 1 req.False(comp1.Equal(comp2)) comp2.Round = comp1.Round + // Change reset. + comp2.Reset = comp1.Reset + 1 + req.False(comp1.Equal(comp2)) + comp2.Reset = comp1.Reset // Change signature. comp2.Signature = crypto.Signature{ Signature: s.genRandomBytes(), @@ -293,6 +314,10 @@ func (s *DKGTestSuite) TestComplaintEquality() { comp2.PrivateShare.Round = comp1.PrivateShare.Round + 1 req.False(comp1.Equal(comp2)) comp2.PrivateShare.Round = comp1.PrivateShare.Round + // Change share's reset. + comp2.PrivateShare.Reset = comp1.PrivateShare.Reset + 1 + req.False(comp1.Equal(comp2)) + comp2.PrivateShare.Reset = comp1.PrivateShare.Reset // After changing every field back, should be equal. req.True(comp1.Equal(comp2)) } @@ -302,6 +327,7 @@ func (s *DKGTestSuite) TestMPKReadyEquality() { ready1 := &MPKReady{ ProposerID: types.NodeID{Hash: common.NewRandomHash()}, Round: 1, + Reset: 2, Signature: crypto.Signature{ Signature: s.genRandomBytes(), }, @@ -318,6 +344,10 @@ func (s *DKGTestSuite) TestMPKReadyEquality() { ready2.Round = ready1.Round + 1 req.False(ready1.Equal(ready2)) ready2.Round = ready1.Round + // Change reset. + ready2.Reset = ready1.Reset + 1 + req.False(ready1.Equal(ready2)) + ready2.Reset = ready1.Reset // Change signature. ready2.Signature = crypto.Signature{ Signature: s.genRandomBytes(), @@ -333,6 +363,7 @@ func (s *DKGTestSuite) TestFinalizeEquality() { final1 := &Finalize{ ProposerID: types.NodeID{Hash: common.NewRandomHash()}, Round: 1, + Reset: 2, Signature: crypto.Signature{ Signature: s.genRandomBytes(), }, @@ -349,6 +380,10 @@ func (s *DKGTestSuite) TestFinalizeEquality() { final2.Round = final1.Round + 1 req.False(final1.Equal(final2)) final2.Round = final1.Round + // Change reset. + final2.Reset = final1.Reset + 1 + req.False(final1.Equal(final2)) + final2.Reset = final1.Reset // Change signature. final2.Signature = crypto.Signature{ Signature: s.genRandomBytes(), diff --git a/core/utils/crypto.go b/core/utils/crypto.go index f5343ca..7532d29 100644 --- a/core/utils/crypto.go +++ b/core/utils/crypto.go @@ -148,11 +148,14 @@ func hashPosition(position types.Position) common.Hash { func hashDKGPrivateShare(prvShare *typesDKG.PrivateShare) common.Hash { binaryRound := make([]byte, 8) binary.LittleEndian.PutUint64(binaryRound, prvShare.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, prvShare.Reset) return crypto.Keccak256Hash( prvShare.ProposerID.Hash[:], prvShare.ReceiverID.Hash[:], binaryRound, + binaryReset, prvShare.PrivateShare.Bytes(), ) } @@ -175,12 +178,15 @@ func VerifyDKGPrivateShareSignature( func hashDKGMasterPublicKey(mpk *typesDKG.MasterPublicKey) common.Hash { binaryRound := make([]byte, 8) binary.LittleEndian.PutUint64(binaryRound, mpk.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, mpk.Reset) return crypto.Keccak256Hash( mpk.ProposerID.Hash[:], mpk.DKGID.GetLittleEndian(), mpk.PublicKeyShares.MasterKeyBytes(), binaryRound, + binaryReset, ) } @@ -201,12 +207,15 @@ func VerifyDKGMasterPublicKeySignature( func hashDKGComplaint(complaint *typesDKG.Complaint) common.Hash { binaryRound := make([]byte, 8) binary.LittleEndian.PutUint64(binaryRound, complaint.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, complaint.Reset) hashPrvShare := hashDKGPrivateShare(&complaint.PrivateShare) return crypto.Keccak256Hash( complaint.ProposerID.Hash[:], binaryRound, + binaryReset, hashPrvShare[:], ) } @@ -217,6 +226,9 @@ func VerifyDKGComplaintSignature( if complaint.Round != complaint.PrivateShare.Round { return false, nil } + if complaint.Reset != complaint.PrivateShare.Reset { + return false, nil + } hash := hashDKGComplaint(complaint) pubKey, err := crypto.SigToPub(hash, complaint.Signature) if err != nil { @@ -261,10 +273,13 @@ func VerifyDKGPartialSignatureSignature( func hashDKGMPKReady(ready *typesDKG.MPKReady) common.Hash { binaryRound := make([]byte, 8) binary.LittleEndian.PutUint64(binaryRound, ready.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, ready.Reset) return crypto.Keccak256Hash( ready.ProposerID.Hash[:], binaryRound, + binaryReset, ) } @@ -285,10 +300,13 @@ func VerifyDKGMPKReadySignature( func hashDKGFinalize(final *typesDKG.Finalize) common.Hash { binaryRound := make([]byte, 8) binary.LittleEndian.PutUint64(binaryRound, final.Round) + binaryReset := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryReset, final.Reset) return crypto.Keccak256Hash( final.ProposerID.Hash[:], binaryRound, + binaryReset, ) } diff --git a/core/utils/crypto_test.go b/core/utils/crypto_test.go index 1077277..3151a39 100644 --- a/core/utils/crypto_test.go +++ b/core/utils/crypto_test.go @@ -160,6 +160,7 @@ func (s *CryptoTestSuite) TestDKGSignature() { prvShare := &typesDKG.PrivateShare{ ProposerID: nID, Round: 5, + Reset: 6, PrivateShare: *dkg.NewPrivateKey(), } prvShare.Signature, err = prv.Sign(hashDKGPrivateShare(prvShare)) @@ -171,12 +172,19 @@ func (s *CryptoTestSuite) TestDKGSignature() { ok, err = VerifyDKGPrivateShareSignature(prvShare) s.Require().NoError(err) s.False(ok) + prvShare.Round-- + prvShare.Reset++ + ok, err = VerifyDKGPrivateShareSignature(prvShare) + s.Require().NoError(err) + s.False(ok) + prvShare.Reset-- id := dkg.NewID([]byte{13}) _, pkShare := dkg.NewPrivateKeyShares(1) mpk := &typesDKG.MasterPublicKey{ ProposerID: nID, Round: 5, + Reset: 6, DKGID: id, PublicKeyShares: *pkShare, } @@ -185,17 +193,25 @@ func (s *CryptoTestSuite) TestDKGSignature() { ok, err = VerifyDKGMasterPublicKeySignature(mpk) s.Require().NoError(err) s.True(ok) + // Test incorrect round. mpk.Round++ ok, err = VerifyDKGMasterPublicKeySignature(mpk) s.Require().NoError(err) s.False(ok) + mpk.Round-- + // Test incorrect reset. + mpk.Reset++ + ok, err = VerifyDKGMasterPublicKeySignature(mpk) + s.Require().NoError(err) + s.False(ok) + mpk.Reset-- - prvShare.Round = 5 prvShare.Signature, err = prv.Sign(hashDKGPrivateShare(prvShare)) s.Require().NoError(err) complaint := &typesDKG.Complaint{ ProposerID: nID, Round: 5, + Reset: 6, PrivateShare: *prvShare, } complaint.Signature, err = prv.Sign(hashDKGComplaint(complaint)) @@ -208,14 +224,23 @@ func (s *CryptoTestSuite) TestDKGSignature() { ok, err = VerifyDKGComplaintSignature(complaint) s.Require().NoError(err) s.False(ok) - // Test mismatch round. complaint.Round-- + // Test mismatch round. complaint.PrivateShare.Round++ complaint.Signature, err = prv.Sign(hashDKGComplaint(complaint)) s.Require().NoError(err) ok, err = VerifyDKGComplaintSignature(complaint) s.Require().NoError(err) s.False(ok) + complaint.PrivateShare.Round-- + // Test mismatch reset. + complaint.PrivateShare.Reset++ + complaint.Signature, err = prv.Sign(hashDKGComplaint(complaint)) + s.Require().NoError(err) + ok, err = VerifyDKGComplaintSignature(complaint) + s.Require().NoError(err) + s.False(ok) + complaint.PrivateShare.Reset-- // Test incorrect private share signature. complaint.PrivateShare.Round-- complaint.PrivateShare.ReceiverID = types.NodeID{Hash: common.NewRandomHash()} @@ -243,30 +268,48 @@ func (s *CryptoTestSuite) TestDKGSignature() { ready := &typesDKG.MPKReady{ ProposerID: nID, Round: 5, + Reset: 6, } ready.Signature, err = prv.Sign(hashDKGMPKReady(ready)) s.Require().NoError(err) ok, err = VerifyDKGMPKReadySignature(ready) s.Require().NoError(err) s.True(ok) + // Test incorrect round. ready.Round++ ok, err = VerifyDKGMPKReadySignature(ready) s.Require().NoError(err) s.False(ok) + ready.Round-- + // Test incorrect reset. + ready.Reset++ + ok, err = VerifyDKGMPKReadySignature(ready) + s.Require().NoError(err) + s.False(ok) + ready.Reset-- final := &typesDKG.Finalize{ ProposerID: nID, Round: 5, + Reset: 6, } final.Signature, err = prv.Sign(hashDKGFinalize(final)) s.Require().NoError(err) ok, err = VerifyDKGFinalizeSignature(final) s.Require().NoError(err) s.True(ok) + // Test incorrect round. final.Round++ ok, err = VerifyDKGFinalizeSignature(final) s.Require().NoError(err) s.False(ok) + final.Round-- + // Test incorrect reset. + final.Reset++ + ok, err = VerifyDKGFinalizeSignature(final) + s.Require().NoError(err) + s.False(ok) + final.Reset-- } func TestCrypto(t *testing.T) { |