aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorMission Liao <mission.liao@dexon.org>2019-03-17 09:56:23 +0800
committerJimmy Hu <jimmy.hu@dexon.org>2019-03-17 09:56:23 +0800
commit4b40c1b8990d2a371a77018feea32d038163f2ec (patch)
treeb482aee945e1f60c6c9c9efd86c39abe812a353b /core
parentb636901c60aa666c6c6b532d06e78b529537d315 (diff)
downloaddexon-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.go41
-rw-r--r--core/configuration-chain_test.go30
-rw-r--r--core/consensus.go11
-rw-r--r--core/consensus_test.go4
-rw-r--r--core/dkg-tsig-protocol.go73
-rw-r--r--core/dkg-tsig-protocol_test.go152
-rw-r--r--core/test/app_test.go23
-rw-r--r--core/test/state.go30
-rw-r--r--core/test/state_test.go118
-rw-r--r--core/types/dkg/dkg.go41
-rw-r--r--core/types/dkg/dkg_test.go35
-rw-r--r--core/utils/crypto.go18
-rw-r--r--core/utils/crypto_test.go47
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) {