diff options
author | Mission Liao <mission.liao@dexon.org> | 2019-03-11 13:35:05 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-11 13:35:05 +0800 |
commit | c3bda77db1c2620c5212d4369792b923227d2570 (patch) | |
tree | 3f71c76926f8008ab3eabce3dfd147ebb683dafa | |
parent | 4345050093710739c9e417956bc3a8339e7d99a6 (diff) | |
download | dexon-consensus-c3bda77db1c2620c5212d4369792b923227d2570.tar dexon-consensus-c3bda77db1c2620c5212d4369792b923227d2570.tar.gz dexon-consensus-c3bda77db1c2620c5212d4369792b923227d2570.tar.bz2 dexon-consensus-c3bda77db1c2620c5212d4369792b923227d2570.tar.lz dexon-consensus-c3bda77db1c2620c5212d4369792b923227d2570.tar.xz dexon-consensus-c3bda77db1c2620c5212d4369792b923227d2570.tar.zst dexon-consensus-c3bda77db1c2620c5212d4369792b923227d2570.zip |
core: move some dkg utils (#476)
* Move core.getDKGThreshold to
core.utils.GetDKGThreshold
* Move core.DKGGroupPublicKey to
typesDKG.GroupPublicKey
-rw-r--r-- | core/configuration-chain.go | 26 | ||||
-rw-r--r-- | core/configuration-chain_test.go | 18 | ||||
-rw-r--r-- | core/consensus.go | 2 | ||||
-rw-r--r-- | core/dkg-tsig-protocol.go | 128 | ||||
-rw-r--r-- | core/dkg-tsig-protocol_test.go | 56 | ||||
-rw-r--r-- | core/interfaces.go | 2 | ||||
-rw-r--r-- | core/types/dkg/dkg.go | 106 | ||||
-rw-r--r-- | core/utils.go | 4 | ||||
-rw-r--r-- | core/utils/utils.go | 5 |
9 files changed, 174 insertions, 173 deletions
diff --git a/core/configuration-chain.go b/core/configuration-chain.go index ad4d7e6..ecca43c 100644 --- a/core/configuration-chain.go +++ b/core/configuration-chain.go @@ -48,7 +48,7 @@ type configurationChain struct { logger common.Logger dkgLock sync.RWMutex dkgSigner map[uint64]*dkgShareSecret - gpk map[uint64]*DKGGroupPublicKey + gpk map[uint64]*typesDKG.GroupPublicKey dkgResult sync.RWMutex tsig map[common.Hash]*tsigProtocol tsigTouched map[common.Hash]struct{} @@ -76,7 +76,7 @@ func newConfigurationChain( gov: gov, logger: logger, dkgSigner: make(map[uint64]*dkgShareSecret), - gpk: make(map[uint64]*DKGGroupPublicKey), + gpk: make(map[uint64]*typesDKG.GroupPublicKey), tsig: make(map[common.Hash]*tsigProtocol), tsigTouched: make(map[common.Hash]struct{}), tsigReady: sync.NewCond(&sync.Mutex{}), @@ -221,7 +221,7 @@ func (cc *configurationChain) runDKG(round uint64) error { } cc.logger.Debug("Calling Governance.DKGMasterPublicKeys", "round", round) cc.logger.Debug("Calling Governance.DKGComplaints", "round", round) - gpk, err := NewDKGGroupPublicKey(round, + gpk, err := typesDKG.NewGroupPublicKey(round, cc.gov.DKGMasterPublicKeys(round), cc.gov.DKGComplaints(round), cc.dkg.threshold) @@ -229,19 +229,19 @@ func (cc *configurationChain) runDKG(round uint64) error { return err } qualifies := "" - for nID := range gpk.qualifyNodeIDs { + for nID := range gpk.QualifyNodeIDs { qualifies += fmt.Sprintf("%s ", nID.String()[:6]) } cc.logger.Info("Qualify Nodes", "nodeID", cc.ID, "round", round, - "count", len(gpk.qualifyIDs), + "count", len(gpk.QualifyIDs), "qualifies", qualifies) - if _, exist := gpk.qualifyNodeIDs[cc.ID]; !exist { + if _, exist := gpk.QualifyNodeIDs[cc.ID]; !exist { cc.logger.Warn("Self is not in Qualify Nodes") return nil } - signer, err := cc.dkg.recoverShareSecret(gpk.qualifyIDs) + signer, err := cc.dkg.recoverShareSecret(gpk.QualifyIDs) if err != nil { return err } @@ -265,8 +265,8 @@ func (cc *configurationChain) isDKGFinal(round uint64) bool { } func (cc *configurationChain) getDKGInfo( - round uint64) (*DKGGroupPublicKey, *dkgShareSecret, error) { - getFromCache := func() (*DKGGroupPublicKey, *dkgShareSecret) { + round uint64) (*typesDKG.GroupPublicKey, *dkgShareSecret, error) { + getFromCache := func() (*typesDKG.GroupPublicKey, *dkgShareSecret) { cc.dkgResult.RLock() defer cc.dkgResult.RUnlock() gpk := cc.gpk[round] @@ -297,14 +297,12 @@ func (cc *configurationChain) recoverDKGInfo(round uint64) error { if !cc.gov.IsDKGFinal(round) { return ErrDKGNotReady } - - threshold := getDKGThreshold( - utils.GetConfigWithPanic(cc.gov, round, cc.logger)) // Restore group public key. - gpk, err := NewDKGGroupPublicKey(round, + gpk, err := typesDKG.NewGroupPublicKey(round, cc.gov.DKGMasterPublicKeys(round), cc.gov.DKGComplaints(round), - threshold) + utils.GetDKGThreshold( + utils.GetConfigWithPanic(cc.gov, round, cc.logger))) if err != nil { return err } diff --git a/core/configuration-chain_test.go b/core/configuration-chain_test.go index 939cf65..f7a81da 100644 --- a/core/configuration-chain_test.go +++ b/core/configuration-chain_test.go @@ -250,7 +250,7 @@ func (s *ConfigurationChainTestSuite) preparePartialSignature( if _, exist := cc.gpk[round]; !exist { continue } - if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist { + if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { continue } psig, err := cc.preparePartialSignature(round, hash) @@ -284,7 +284,7 @@ func (s *ConfigurationChainTestSuite) TestConfigurationChain() { if _, exist := cc.gpk[round]; !exist { continue } - if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist { + if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { continue } go func(cc *configurationChain) { @@ -302,7 +302,7 @@ func (s *ConfigurationChainTestSuite) TestConfigurationChain() { if _, exist := cc.gpk[round]; !exist { s.FailNow("Should be qualifyied") } - if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist { + if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { s.FailNow("Should be qualifyied") } s.Require().NoError(<-errs) @@ -374,7 +374,7 @@ func (s *ConfigurationChainTestSuite) TestDKGMasterPublicKeyDelayAdd() { if !exist { continue } - _, exist = cc.gpk[round].qualifyNodeIDs[nID] + _, exist = cc.gpk[round].QualifyNodeIDs[nID] s.Equal(shouldExist, exist) } } @@ -449,7 +449,7 @@ func (s *ConfigurationChainTestSuite) TestDKGComplaintDelayAdd() { if _, exist := cc.gpk[round]; !exist { s.FailNow("Should be qualifyied") } - if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist { + if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { s.FailNow("Should be qualifyied") } } @@ -474,7 +474,7 @@ func (s *ConfigurationChainTestSuite) TestMultipleTSig() { tsigChan1 := make(chan crypto.Signature, n) tsigChan2 := make(chan crypto.Signature, n) for nID, cc := range cfgChains { - if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist { + if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { continue } go func(cc *configurationChain) { @@ -499,7 +499,7 @@ func (s *ConfigurationChainTestSuite) TestMultipleTSig() { } } for nID, cc := range cfgChains { - if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist { + if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { continue } s.Require().NoError(<-errs) @@ -529,7 +529,7 @@ func (s *ConfigurationChainTestSuite) TestTSigTimeout() { errs := make(chan error, n) qualify := 0 for nID, cc := range cfgChains { - if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist { + if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { continue } qualify++ @@ -545,7 +545,7 @@ func (s *ConfigurationChainTestSuite) TestTSigTimeout() { time.Sleep(timeout) s.Require().Len(errs, qualify) for nID, cc := range cfgChains { - if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist { + if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { continue } s.Equal(<-errs, ErrNotEnoughtPartialSignatures) diff --git a/core/consensus.go b/core/consensus.go index 5945406..ccb3326 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -814,7 +814,7 @@ func (con *Consensus) initialRound( return } con.logger.Info("Selected as DKG set", "round", nextRound) - con.cfgModule.registerDKG(nextRound, getDKGThreshold(config)) + con.cfgModule.registerDKG(nextRound, utils.GetDKGThreshold(config)) con.event.RegisterHeight(startHeight+config.RoundLength*2/3, func(uint64) { func() { diff --git a/core/dkg-tsig-protocol.go b/core/dkg-tsig-protocol.go index 45fe822..46e975a 100644 --- a/core/dkg-tsig-protocol.go +++ b/core/dkg-tsig-protocol.go @@ -37,10 +37,6 @@ var ( "not a qualified DKG participant") ErrIDShareNotFound = fmt.Errorf( "private share not found for specific ID") - ErrNotReachThreshold = fmt.Errorf( - "threshold not reach") - ErrInvalidThreshold = fmt.Errorf( - "invalid threshold") ErrIncorrectPrivateShareSignature = fmt.Errorf( "incorrect private share signature") ErrMismatchPartialSignatureHash = fmt.Errorf( @@ -102,17 +98,6 @@ type dkgShareSecret struct { privateKey *dkg.PrivateKey } -// DKGGroupPublicKey is the result of DKG protocol. -type DKGGroupPublicKey struct { - round uint64 - qualifyIDs dkg.IDs - qualifyNodeIDs map[types.NodeID]struct{} - idMap map[types.NodeID]dkg.ID - publicKeys map[types.NodeID]*dkg.PublicKey - groupPublicKey *dkg.PublicKey - threshold int -} - // TSigVerifier is the interface verifying threshold signature. type TSigVerifier interface { VerifySignature(hash common.Hash, sig crypto.Signature) bool @@ -144,7 +129,7 @@ type TSigVerifierCache struct { } type tsigProtocol struct { - groupPublicKey *DKGGroupPublicKey + groupPublicKey *typesDKG.GroupPublicKey hash common.Hash sigs map[dkg.ID]dkg.PartialSignature threshold int @@ -385,7 +370,7 @@ func (d *dkgProtocol) proposeFinalize() { func (d *dkgProtocol) recoverShareSecret(qualifyIDs dkg.IDs) ( *dkgShareSecret, error) { if len(qualifyIDs) < d.threshold { - return nil, ErrNotReachThreshold + return nil, typesDKG.ErrNotReachThreshold } prvKey, err := d.prvShares.RecoverPrivateKey(qualifyIDs) if err != nil { @@ -402,96 +387,7 @@ func (ss *dkgShareSecret) sign(hash common.Hash) dkg.PartialSignature { return dkg.PartialSignature(sig) } -// NewDKGGroupPublicKey creats a DKGGroupPublicKey instance. -func NewDKGGroupPublicKey( - round uint64, - mpks []*typesDKG.MasterPublicKey, complaints []*typesDKG.Complaint, - threshold int) ( - *DKGGroupPublicKey, error) { - - if len(mpks) < threshold { - return nil, ErrInvalidThreshold - } - - // Calculate qualify members. - disqualifyIDs := map[types.NodeID]struct{}{} - complaintsByID := map[types.NodeID]map[types.NodeID]struct{}{} - for _, complaint := range complaints { - if complaint.IsNack() { - if _, exist := complaintsByID[complaint.PrivateShare.ProposerID]; !exist { - complaintsByID[complaint.PrivateShare.ProposerID] = - make(map[types.NodeID]struct{}) - } - complaintsByID[complaint.PrivateShare.ProposerID][complaint.ProposerID] = - struct{}{} - } else { - disqualifyIDs[complaint.PrivateShare.ProposerID] = struct{}{} - } - } - for nID, complaints := range complaintsByID { - if len(complaints) > threshold { - disqualifyIDs[nID] = struct{}{} - } - } - qualifyIDs := make(dkg.IDs, 0, len(mpks)-len(disqualifyIDs)) - if cap(qualifyIDs) < threshold { - return nil, ErrNotReachThreshold - } - qualifyNodeIDs := make(map[types.NodeID]struct{}) - mpkMap := make(map[dkg.ID]*typesDKG.MasterPublicKey, cap(qualifyIDs)) - idMap := make(map[types.NodeID]dkg.ID) - for _, mpk := range mpks { - if _, exist := disqualifyIDs[mpk.ProposerID]; exist { - continue - } - mpkMap[mpk.DKGID] = mpk - idMap[mpk.ProposerID] = mpk.DKGID - qualifyIDs = append(qualifyIDs, mpk.DKGID) - qualifyNodeIDs[mpk.ProposerID] = struct{}{} - } - // Recover qualify members' public key. - pubKeys := make(map[types.NodeID]*dkg.PublicKey, len(qualifyIDs)) - for _, recvID := range qualifyIDs { - pubShares := dkg.NewEmptyPublicKeyShares() - for _, id := range qualifyIDs { - pubShare, err := mpkMap[id].PublicKeyShares.Share(recvID) - if err != nil { - return nil, err - } - if err := pubShares.AddShare(id, pubShare); err != nil { - return nil, err - } - } - pubKey, err := pubShares.RecoverPublicKey(qualifyIDs) - if err != nil { - return nil, err - } - pubKeys[mpkMap[recvID].ProposerID] = pubKey - } - // Recover Group Public Key. - pubShares := make([]*dkg.PublicKeyShares, 0, len(qualifyIDs)) - for _, id := range qualifyIDs { - pubShares = append(pubShares, &mpkMap[id].PublicKeyShares) - } - groupPK := dkg.RecoverGroupPublicKey(pubShares) - return &DKGGroupPublicKey{ - round: round, - qualifyIDs: qualifyIDs, - qualifyNodeIDs: qualifyNodeIDs, - idMap: idMap, - publicKeys: pubKeys, - threshold: threshold, - groupPublicKey: groupPK, - }, nil -} - -// VerifySignature verifies if the signature is correct. -func (gpk *DKGGroupPublicKey) VerifySignature( - hash common.Hash, sig crypto.Signature) bool { - return gpk.groupPublicKey.VerifySignature(hash, sig) -} - -// NewTSigVerifierCache creats a DKGGroupPublicKey instance. +// NewTSigVerifierCache creats a TSigVerifierCache instance. func NewTSigVerifierCache( intf TSigVerifierCacheInterface, cacheSize int) *TSigVerifierCache { return &TSigVerifierCache{ @@ -528,10 +424,10 @@ func (tc *TSigVerifierCache) Update(round uint64) (bool, error) { if !tc.intf.IsDKGFinal(round) { return false, nil } - gpk, err := NewDKGGroupPublicKey(round, + gpk, err := typesDKG.NewGroupPublicKey(round, tc.intf.DKGMasterPublicKeys(round), tc.intf.DKGComplaints(round), - int(utils.GetConfigWithPanic(tc.intf, round, nil).DKGSetSize/3)+1) + utils.GetDKGThreshold(utils.GetConfigWithPanic(tc.intf, round, nil))) if err != nil { return false, err } @@ -568,17 +464,17 @@ func (tc *TSigVerifierCache) Get(round uint64) (TSigVerifier, bool) { } func newTSigProtocol( - gpk *DKGGroupPublicKey, + gpk *typesDKG.GroupPublicKey, hash common.Hash) *tsigProtocol { return &tsigProtocol{ groupPublicKey: gpk, hash: hash, - sigs: make(map[dkg.ID]dkg.PartialSignature, gpk.threshold+1), + sigs: make(map[dkg.ID]dkg.PartialSignature, gpk.Threshold+1), } } func (tsig *tsigProtocol) sanityCheck(psig *typesDKG.PartialSignature) error { - _, exist := tsig.groupPublicKey.publicKeys[psig.ProposerID] + _, exist := tsig.groupPublicKey.PublicKeys[psig.ProposerID] if !exist { return ErrNotQualifyDKGParticipant } @@ -597,17 +493,17 @@ func (tsig *tsigProtocol) sanityCheck(psig *typesDKG.PartialSignature) error { func (tsig *tsigProtocol) processPartialSignature( psig *typesDKG.PartialSignature) error { - if psig.Round != tsig.groupPublicKey.round { + if psig.Round != tsig.groupPublicKey.Round { return nil } - id, exist := tsig.groupPublicKey.idMap[psig.ProposerID] + id, exist := tsig.groupPublicKey.IDMap[psig.ProposerID] if !exist { return ErrNotQualifyDKGParticipant } if err := tsig.sanityCheck(psig); err != nil { return err } - pubKey := tsig.groupPublicKey.publicKeys[psig.ProposerID] + pubKey := tsig.groupPublicKey.PublicKeys[psig.ProposerID] if !pubKey.VerifySignature( tsig.hash, crypto.Signature(psig.PartialSignature)) { return ErrIncorrectPartialSignature @@ -617,7 +513,7 @@ func (tsig *tsigProtocol) processPartialSignature( } func (tsig *tsigProtocol) signature() (crypto.Signature, error) { - if len(tsig.sigs) < tsig.groupPublicKey.threshold { + if len(tsig.sigs) < tsig.groupPublicKey.Threshold { return crypto.Signature{}, ErrNotEnoughtPartialSignatures } ids := make(dkg.IDs, 0, len(tsig.sigs)) diff --git a/core/dkg-tsig-protocol_test.go b/core/dkg-tsig-protocol_test.go index 1176bc4..88f78d3 100644 --- a/core/dkg-tsig-protocol_test.go +++ b/core/dkg-tsig-protocol_test.go @@ -202,19 +202,19 @@ func (s *DKGTSIGProtocolTestSuite) TestDKGTSIGProtocol() { } // DKG is fininished. - gpk, err := NewDKGGroupPublicKey(round, + gpk, err := typesDKG.NewGroupPublicKey(round, gov.DKGMasterPublicKeys(round), gov.DKGComplaints(round), k, ) s.Require().NoError(err) - s.Require().Len(gpk.qualifyIDs, n) - qualifyIDs := make(map[dkg.ID]struct{}, len(gpk.qualifyIDs)) - for _, id := range gpk.qualifyIDs { + s.Require().Len(gpk.QualifyIDs, n) + qualifyIDs := make(map[dkg.ID]struct{}, len(gpk.QualifyIDs)) + for _, id := range gpk.QualifyIDs { qualifyIDs[id] = struct{}{} } - for nID := range gpk.qualifyNodeIDs { - id, exist := gpk.idMap[nID] + for nID := range gpk.QualifyNodeIDs { + id, exist := gpk.IDMap[nID] s.Require().True(exist) _, exist = qualifyIDs[id] s.Require().True(exist) @@ -227,7 +227,7 @@ func (s *DKGTSIGProtocolTestSuite) TestDKGTSIGProtocol() { _, exist := qualifyIDs[s.dkgIDs[nID]] s.Require().True(exist) var err error - shareSecrets[nID], err = protocol.recoverShareSecret(gpk.qualifyIDs) + shareSecrets[nID], err = protocol.recoverShareSecret(gpk.QualifyIDs) s.Require().NoError(err) } @@ -360,22 +360,22 @@ func (s *DKGTSIGProtocolTestSuite) TestErrMPKRegistered() { } // DKG is fininished. - gpk, err := NewDKGGroupPublicKey(round, + gpk, err := typesDKG.NewGroupPublicKey(round, gov.DKGMasterPublicKeys(round), gov.DKGComplaints(round), k, ) s.Require().NoError(err) - s.Require().Len(gpk.qualifyIDs, n-2) - qualifyIDs := make(map[dkg.ID]struct{}, len(gpk.qualifyIDs)) - for _, id := range gpk.qualifyIDs { + s.Require().Len(gpk.QualifyIDs, n-2) + qualifyIDs := make(map[dkg.ID]struct{}, len(gpk.QualifyIDs)) + for _, id := range gpk.QualifyIDs { qualifyIDs[id] = struct{}{} } - for nID := range gpk.qualifyNodeIDs { + for nID := range gpk.QualifyNodeIDs { if nID == notRegisterID || nID == errRegisterID { continue } - id, exist := gpk.idMap[nID] + id, exist := gpk.IDMap[nID] s.Require().True(exist) _, exist = qualifyIDs[id] s.Require().True(exist) @@ -528,12 +528,12 @@ func (s *DKGTSIGProtocolTestSuite) TestDuplicateComplaint() { s.Require().True(complaints[i].IsNack()) } - gpk, err := NewDKGGroupPublicKey(round, + gpk, err := typesDKG.NewGroupPublicKey(round, gov.DKGMasterPublicKeys(round), complaints, k, ) s.Require().NoError(err) - s.Require().Len(gpk.qualifyIDs, n) + s.Require().Len(gpk.QualifyIDs, n) } // TestAntiComplaint tests if a nack complaint is received, @@ -684,33 +684,33 @@ func (s *DKGTSIGProtocolTestSuite) TestQualifyIDs() { s.Require().True(complaints[i].IsNack()) } - gpk, err := NewDKGGroupPublicKey(round, + gpk, err := typesDKG.NewGroupPublicKey(round, gov.DKGMasterPublicKeys(round), complaints, k, ) s.Require().NoError(err) - s.Require().Len(gpk.qualifyIDs, n-1) - for _, id := range gpk.qualifyIDs { + s.Require().Len(gpk.QualifyIDs, n-1) + for _, id := range gpk.QualifyIDs { s.NotEqual(id, byzantineID) } - gpk2, err := NewDKGGroupPublicKey(round, + gpk2, err := typesDKG.NewGroupPublicKey(round, gov.DKGMasterPublicKeys(round), complaints[:k], k, ) s.Require().NoError(err) - s.Require().Len(gpk2.qualifyIDs, n) + s.Require().Len(gpk2.QualifyIDs, n) // Test for complaint. complaints[0].PrivateShare.Signature = crypto.Signature{Signature: []byte{0}} s.Require().False(complaints[0].IsNack()) - gpk3, err := NewDKGGroupPublicKey(round, + gpk3, err := typesDKG.NewGroupPublicKey(round, gov.DKGMasterPublicKeys(round), complaints[:1], k, ) s.Require().NoError(err) - s.Require().Len(gpk3.qualifyIDs, n-1) - for _, id := range gpk3.qualifyIDs { + s.Require().Len(gpk3.QualifyIDs, n-1) + for _, id := range gpk3.QualifyIDs { s.NotEqual(id, byzantineID) } } @@ -762,14 +762,14 @@ func (s *DKGTSIGProtocolTestSuite) TestPartialSignature() { } // DKG is fininished. - gpk, err := NewDKGGroupPublicKey(round, + gpk, err := typesDKG.NewGroupPublicKey(round, gov.DKGMasterPublicKeys(round), gov.DKGComplaints(round), k, ) s.Require().NoError(err) - s.Require().Len(gpk.qualifyIDs, n-1) - qualifyIDs := make(map[dkg.ID]struct{}, len(gpk.qualifyIDs)) - for _, id := range gpk.qualifyIDs { + s.Require().Len(gpk.QualifyIDs, n-1) + qualifyIDs := make(map[dkg.ID]struct{}, len(gpk.QualifyIDs)) + for _, id := range gpk.QualifyIDs { qualifyIDs[id] = struct{}{} } @@ -783,7 +783,7 @@ func (s *DKGTSIGProtocolTestSuite) TestPartialSignature() { } s.Require().True(exist) var err error - shareSecrets[nID], err = protocol.recoverShareSecret(gpk.qualifyIDs) + shareSecrets[nID], err = protocol.recoverShareSecret(gpk.QualifyIDs) s.Require().NoError(err) } diff --git a/core/interfaces.go b/core/interfaces.go index b7e000a..45a1fc7 100644 --- a/core/interfaces.go +++ b/core/interfaces.go @@ -129,7 +129,7 @@ type Governance interface { // AddDKGMPKReady adds a DKG ready message. AddDKGMPKReady(round uint64, ready *typesDKG.MPKReady) - // IsDKGFinal checks if DKG is ready. + // IsDKGMPKReady checks if DKG's master public key preparation is ready. IsDKGMPKReady(round uint64) bool // AddDKGFinalize adds a DKG finalize message. diff --git a/core/types/dkg/dkg.go b/core/types/dkg/dkg.go index db58168..00c04be 100644 --- a/core/types/dkg/dkg.go +++ b/core/types/dkg/dkg.go @@ -31,6 +31,12 @@ import ( "github.com/dexon-foundation/dexon-consensus/core/types" ) +// Errors for typesDKG package. +var ( + ErrNotReachThreshold = fmt.Errorf("threshold not reach") + ErrInvalidThreshold = fmt.Errorf("invalid threshold") +) + // NewID creates a DKGID from NodeID. func NewID(ID types.NodeID) cryptoDKG.ID { return cryptoDKG.NewID(ID.Hash[:]) @@ -276,3 +282,103 @@ func (final *Finalize) Equal(other *Finalize) bool { func (c *Complaint) IsNack() bool { return len(c.PrivateShare.Signature.Signature) == 0 } + +// GroupPublicKey is the result of DKG protocol. +type GroupPublicKey struct { + Round uint64 + QualifyIDs cryptoDKG.IDs + QualifyNodeIDs map[types.NodeID]struct{} + IDMap map[types.NodeID]cryptoDKG.ID + PublicKeys map[types.NodeID]*cryptoDKG.PublicKey + GroupPublicKey *cryptoDKG.PublicKey + Threshold int +} + +// VerifySignature verifies if the signature is correct. +func (gpk *GroupPublicKey) VerifySignature( + hash common.Hash, sig crypto.Signature) bool { + return gpk.GroupPublicKey.VerifySignature(hash, sig) +} + +// NewGroupPublicKey creats a GroupPublicKey instance. +func NewGroupPublicKey( + round uint64, + mpks []*MasterPublicKey, complaints []*Complaint, + threshold int) ( + *GroupPublicKey, error) { + + if len(mpks) < threshold { + return nil, ErrInvalidThreshold + } + + // Calculate qualify members. + disqualifyIDs := map[types.NodeID]struct{}{} + complaintsByID := map[types.NodeID]map[types.NodeID]struct{}{} + for _, complaint := range complaints { + if complaint.IsNack() { + if _, exist := complaintsByID[complaint.PrivateShare.ProposerID]; !exist { + complaintsByID[complaint.PrivateShare.ProposerID] = + make(map[types.NodeID]struct{}) + } + complaintsByID[complaint.PrivateShare.ProposerID][complaint.ProposerID] = + struct{}{} + } else { + disqualifyIDs[complaint.PrivateShare.ProposerID] = struct{}{} + } + } + for nID, complaints := range complaintsByID { + if len(complaints) > threshold { + disqualifyIDs[nID] = struct{}{} + } + } + qualifyIDs := make(cryptoDKG.IDs, 0, len(mpks)-len(disqualifyIDs)) + if cap(qualifyIDs) < threshold { + return nil, ErrNotReachThreshold + } + qualifyNodeIDs := make(map[types.NodeID]struct{}) + mpkMap := make(map[cryptoDKG.ID]*MasterPublicKey, cap(qualifyIDs)) + idMap := make(map[types.NodeID]cryptoDKG.ID) + for _, mpk := range mpks { + if _, exist := disqualifyIDs[mpk.ProposerID]; exist { + continue + } + mpkMap[mpk.DKGID] = mpk + idMap[mpk.ProposerID] = mpk.DKGID + qualifyIDs = append(qualifyIDs, mpk.DKGID) + qualifyNodeIDs[mpk.ProposerID] = struct{}{} + } + // Recover qualify members' public key. + pubKeys := make(map[types.NodeID]*cryptoDKG.PublicKey, len(qualifyIDs)) + for _, recvID := range qualifyIDs { + pubShares := cryptoDKG.NewEmptyPublicKeyShares() + for _, id := range qualifyIDs { + pubShare, err := mpkMap[id].PublicKeyShares.Share(recvID) + if err != nil { + return nil, err + } + if err := pubShares.AddShare(id, pubShare); err != nil { + return nil, err + } + } + pubKey, err := pubShares.RecoverPublicKey(qualifyIDs) + if err != nil { + return nil, err + } + pubKeys[mpkMap[recvID].ProposerID] = pubKey + } + // Recover Group Public Key. + pubShares := make([]*cryptoDKG.PublicKeyShares, 0, len(qualifyIDs)) + for _, id := range qualifyIDs { + pubShares = append(pubShares, &mpkMap[id].PublicKeyShares) + } + groupPK := cryptoDKG.RecoverGroupPublicKey(pubShares) + return &GroupPublicKey{ + Round: round, + QualifyIDs: qualifyIDs, + QualifyNodeIDs: qualifyNodeIDs, + IDMap: idMap, + PublicKeys: pubKeys, + Threshold: threshold, + GroupPublicKey: groupPK, + }, nil +} diff --git a/core/utils.go b/core/utils.go index 46aa77a..f7dee75 100644 --- a/core/utils.go +++ b/core/utils.go @@ -229,10 +229,6 @@ func isTravisCI() bool { return isCI() && os.Getenv("TRAVIS") == "true" } -func getDKGThreshold(config *types.Config) int { - return int(config.DKGSetSize/3) + 1 -} - // checkWithCancel is a helper to perform periodic checking with cancel. func checkWithCancel(parentCtx context.Context, interval time.Duration, checker func() bool) (ret bool) { diff --git a/core/utils/utils.go b/core/utils/utils.go index 220240c..b8bd95e 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -133,3 +133,8 @@ func LaunchDummyReceiver( }() return dummyCancel, finishedChan } + +// GetDKGThreshold return expected threshold for given DKG set size. +func GetDKGThreshold(config *types.Config) int { + return int(config.DKGSetSize/3) + 1 +} |