diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/configuration-chain.go | 48 | ||||
-rw-r--r-- | core/configuration-chain_test.go | 28 | ||||
-rw-r--r-- | core/dkg-tsig-protocol.go | 18 | ||||
-rw-r--r-- | core/dkg-tsig-protocol_test.go | 99 | ||||
-rw-r--r-- | core/types/dkg/dkg.go | 101 |
5 files changed, 220 insertions, 74 deletions
diff --git a/core/configuration-chain.go b/core/configuration-chain.go index ecca43c..9e8df6b 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]*typesDKG.GroupPublicKey + npks map[uint64]*typesDKG.NodePublicKeys 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]*typesDKG.GroupPublicKey), + npks: make(map[uint64]*typesDKG.NodePublicKeys), 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 := typesDKG.NewGroupPublicKey(round, + npks, err := typesDKG.NewNodePublicKeys(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 npks.QualifyNodeIDs { qualifies += fmt.Sprintf("%s ", nID.String()[:6]) } cc.logger.Info("Qualify Nodes", "nodeID", cc.ID, "round", round, - "count", len(gpk.QualifyIDs), + "count", len(npks.QualifyIDs), "qualifies", qualifies) - if _, exist := gpk.QualifyNodeIDs[cc.ID]; !exist { + if _, exist := npks.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(npks.QualifyIDs) if err != nil { return err } @@ -252,7 +252,7 @@ func (cc *configurationChain) runDKG(round uint64) error { cc.dkgResult.Lock() defer cc.dkgResult.Unlock() cc.dkgSigner[round] = signer - cc.gpk[round] = gpk + cc.npks[round] = npks return nil } @@ -265,40 +265,40 @@ func (cc *configurationChain) isDKGFinal(round uint64) bool { } func (cc *configurationChain) getDKGInfo( - round uint64) (*typesDKG.GroupPublicKey, *dkgShareSecret, error) { - getFromCache := func() (*typesDKG.GroupPublicKey, *dkgShareSecret) { + round uint64) (*typesDKG.NodePublicKeys, *dkgShareSecret, error) { + getFromCache := func() (*typesDKG.NodePublicKeys, *dkgShareSecret) { cc.dkgResult.RLock() defer cc.dkgResult.RUnlock() - gpk := cc.gpk[round] + npks := cc.npks[round] signer := cc.dkgSigner[round] - return gpk, signer + return npks, signer } - gpk, signer := getFromCache() - if gpk == nil || signer == nil { + npks, signer := getFromCache() + if npks == nil || signer == nil { if err := cc.recoverDKGInfo(round); err != nil { return nil, nil, err } - gpk, signer = getFromCache() + npks, signer = getFromCache() } - if gpk == nil || signer == nil { + if npks == nil || signer == nil { return nil, nil, ErrDKGNotReady } - return gpk, signer, nil + return npks, signer, nil } func (cc *configurationChain) recoverDKGInfo(round uint64) error { cc.dkgResult.Lock() defer cc.dkgResult.Unlock() _, signerExists := cc.dkgSigner[round] - _, gpkExists := cc.gpk[round] - if signerExists && gpkExists { + _, npksExists := cc.npks[round] + if signerExists && npksExists { return nil } if !cc.gov.IsDKGFinal(round) { return ErrDKGNotReady } // Restore group public key. - gpk, err := typesDKG.NewGroupPublicKey(round, + npks, err := typesDKG.NewNodePublicKeys(round, cc.gov.DKGMasterPublicKeys(round), cc.gov.DKGComplaints(round), utils.GetDKGThreshold( @@ -311,7 +311,7 @@ func (cc *configurationChain) recoverDKGInfo(round uint64) error { if err != nil { return err } - cc.gpk[round] = gpk + cc.npks[round] = npks cc.dkgSigner[round] = &dkgShareSecret{ privateKey: &prvKey, } @@ -349,8 +349,8 @@ func (cc *configurationChain) untouchTSigHash(hash common.Hash) { func (cc *configurationChain) runTSig( round uint64, hash common.Hash) ( crypto.Signature, error) { - gpk, _, _ := cc.getDKGInfo(round) - if gpk == nil { + npks, _, _ := cc.getDKGInfo(round) + if npks == nil { return crypto.Signature{}, ErrDKGNotReady } cc.tsigReady.L.Lock() @@ -358,7 +358,7 @@ func (cc *configurationChain) runTSig( if _, exist := cc.tsig[hash]; exist { return crypto.Signature{}, ErrTSigAlreadyRunning } - cc.tsig[hash] = newTSigProtocol(gpk, hash) + cc.tsig[hash] = newTSigProtocol(npks, hash) pendingPsig := cc.pendingPsig[hash] delete(cc.pendingPsig, hash) go func() { diff --git a/core/configuration-chain_test.go b/core/configuration-chain_test.go index f7a81da..fd7e6a3 100644 --- a/core/configuration-chain_test.go +++ b/core/configuration-chain_test.go @@ -247,10 +247,10 @@ func (s *ConfigurationChainTestSuite) preparePartialSignature( psigs []*typesDKG.PartialSignature) { psigs = make([]*typesDKG.PartialSignature, 0, len(cfgChains)) for nID, cc := range cfgChains { - if _, exist := cc.gpk[round]; !exist { + if _, exist := cc.npks[round]; !exist { continue } - if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { + if _, exist := cc.npks[round].QualifyNodeIDs[nID]; !exist { continue } psig, err := cc.preparePartialSignature(round, hash) @@ -281,10 +281,10 @@ func (s *ConfigurationChainTestSuite) TestConfigurationChain() { errs := make(chan error, n) tsigChan := make(chan crypto.Signature, n) for nID, cc := range cfgChains { - if _, exist := cc.gpk[round]; !exist { + if _, exist := cc.npks[round]; !exist { continue } - if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { + if _, exist := cc.npks[round].QualifyNodeIDs[nID]; !exist { continue } go func(cc *configurationChain) { @@ -299,10 +299,10 @@ func (s *ConfigurationChainTestSuite) TestConfigurationChain() { } } for nID, cc := range cfgChains { - if _, exist := cc.gpk[round]; !exist { + if _, exist := cc.npks[round]; !exist { s.FailNow("Should be qualifyied") } - if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { + if _, exist := cc.npks[round].QualifyNodeIDs[nID]; !exist { s.FailNow("Should be qualifyied") } s.Require().NoError(<-errs) @@ -369,12 +369,12 @@ func (s *ConfigurationChainTestSuite) TestDKGMasterPublicKeyDelayAdd() { } for nID, cc := range cfgChains { shouldExist := nID != delayNode - _, exist := cc.gpk[round] + _, exist := cc.npks[round] s.Equal(shouldExist, exist) if !exist { continue } - _, exist = cc.gpk[round].QualifyNodeIDs[nID] + _, exist = cc.npks[round].QualifyNodeIDs[nID] s.Equal(shouldExist, exist) } } @@ -446,10 +446,10 @@ func (s *ConfigurationChainTestSuite) TestDKGComplaintDelayAdd() { s.Require().NoError(<-errs) } for nID, cc := range cfgChains { - if _, exist := cc.gpk[round]; !exist { + if _, exist := cc.npks[round]; !exist { s.FailNow("Should be qualifyied") } - if _, exist := cc.gpk[round].QualifyNodeIDs[nID]; !exist { + if _, exist := cc.npks[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.npks[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.npks[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.npks[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.npks[round].QualifyNodeIDs[nID]; !exist { continue } s.Equal(<-errs, ErrNotEnoughtPartialSignatures) diff --git a/core/dkg-tsig-protocol.go b/core/dkg-tsig-protocol.go index 46e975a..6c812db 100644 --- a/core/dkg-tsig-protocol.go +++ b/core/dkg-tsig-protocol.go @@ -129,7 +129,7 @@ type TSigVerifierCache struct { } type tsigProtocol struct { - groupPublicKey *typesDKG.GroupPublicKey + nodePublicKeys *typesDKG.NodePublicKeys hash common.Hash sigs map[dkg.ID]dkg.PartialSignature threshold int @@ -464,17 +464,17 @@ func (tc *TSigVerifierCache) Get(round uint64) (TSigVerifier, bool) { } func newTSigProtocol( - gpk *typesDKG.GroupPublicKey, + npks *typesDKG.NodePublicKeys, hash common.Hash) *tsigProtocol { return &tsigProtocol{ - groupPublicKey: gpk, + nodePublicKeys: npks, hash: hash, - sigs: make(map[dkg.ID]dkg.PartialSignature, gpk.Threshold+1), + sigs: make(map[dkg.ID]dkg.PartialSignature, npks.Threshold+1), } } func (tsig *tsigProtocol) sanityCheck(psig *typesDKG.PartialSignature) error { - _, exist := tsig.groupPublicKey.PublicKeys[psig.ProposerID] + _, exist := tsig.nodePublicKeys.PublicKeys[psig.ProposerID] if !exist { return ErrNotQualifyDKGParticipant } @@ -493,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.nodePublicKeys.Round { return nil } - id, exist := tsig.groupPublicKey.IDMap[psig.ProposerID] + id, exist := tsig.nodePublicKeys.IDMap[psig.ProposerID] if !exist { return ErrNotQualifyDKGParticipant } if err := tsig.sanityCheck(psig); err != nil { return err } - pubKey := tsig.groupPublicKey.PublicKeys[psig.ProposerID] + pubKey := tsig.nodePublicKeys.PublicKeys[psig.ProposerID] if !pubKey.VerifySignature( tsig.hash, crypto.Signature(psig.PartialSignature)) { return ErrIncorrectPartialSignature @@ -513,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.nodePublicKeys.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 88f78d3..88d1443 100644 --- a/core/dkg-tsig-protocol_test.go +++ b/core/dkg-tsig-protocol_test.go @@ -204,8 +204,7 @@ func (s *DKGTSIGProtocolTestSuite) TestDKGTSIGProtocol() { // DKG is fininished. gpk, err := typesDKG.NewGroupPublicKey(round, gov.DKGMasterPublicKeys(round), gov.DKGComplaints(round), - k, - ) + k) s.Require().NoError(err) s.Require().Len(gpk.QualifyIDs, n) qualifyIDs := make(map[dkg.ID]struct{}, len(gpk.QualifyIDs)) @@ -231,8 +230,11 @@ func (s *DKGTSIGProtocolTestSuite) TestDKGTSIGProtocol() { s.Require().NoError(err) } + npks, err := typesDKG.NewNodePublicKeys(round, + gov.DKGMasterPublicKeys(round), gov.DKGComplaints(round), k) + s.Require().NoError(err) msgHash := crypto.Keccak256Hash([]byte("🏖🍹")) - tsig := newTSigProtocol(gpk, msgHash) + tsig := newTSigProtocol(npks, msgHash) for nID, shareSecret := range shareSecrets { psig := &typesDKG.PartialSignature{ ProposerID: nID, @@ -788,7 +790,10 @@ func (s *DKGTSIGProtocolTestSuite) TestPartialSignature() { } msgHash := crypto.Keccak256Hash([]byte("🏖🍹")) - tsig := newTSigProtocol(gpk, msgHash) + npks, err := typesDKG.NewNodePublicKeys(round, + gov.DKGMasterPublicKeys(round), gov.DKGComplaints(round), k) + s.Require().NoError(err) + tsig := newTSigProtocol(npks, msgHash) byzantineID2 := s.nIDs[1] byzantineID3 := s.nIDs[2] for nID, shareSecret := range shareSecrets { @@ -937,3 +942,89 @@ func (s *DKGTSIGProtocolTestSuite) TestTSigVerifierCache() { func TestDKGTSIGProtocol(t *testing.T) { suite.Run(t, new(DKGTSIGProtocolTestSuite)) } + +func BenchmarkGPK4_7(b *testing.B) { benchmarkDKGGroupPubliKey(4, 7, b) } +func BenchmarkGPK9_13(b *testing.B) { benchmarkDKGGroupPubliKey(9, 13, b) } +func BenchmarkGPK17_24(b *testing.B) { benchmarkDKGGroupPubliKey(17, 24, b) } +func BenchmarkGPK81_121(b *testing.B) { benchmarkDKGGroupPubliKey(81, 121, b) } + +func benchmarkDKGGroupPubliKey(k, n int, b *testing.B) { + round := uint64(1) + _, pubKeys, err := test.NewKeys(n) + if err != nil { + panic(err) + } + gov, err := test.NewGovernance(test.NewState(DKGDelayRound, + pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) + if err != nil { + panic(err) + } + + for _, pk := range pubKeys { + _, pubShare := dkg.NewPrivateKeyShares(k) + gov.AddDKGMasterPublicKey(round, &typesDKG.MasterPublicKey{ + ProposerID: types.NewNodeID(pk), + Round: round, + DKGID: typesDKG.NewID(types.NewNodeID(pk)), + PublicKeyShares: *pubShare, + }) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // DKG is fininished. + gpk, err := typesDKG.NewGroupPublicKey(round, + gov.DKGMasterPublicKeys(round), gov.DKGComplaints(round), + k, + ) + if err != nil { + panic(err) + } + if len(gpk.QualifyIDs) != n { + panic("not enough of qualify id") + } + } +} + +func BenchmarkNPKs4_7(b *testing.B) { benchmarkDKGNodePubliKeys(4, 7, b) } +func BenchmarkNPKs9_13(b *testing.B) { benchmarkDKGNodePubliKeys(9, 13, b) } +func BenchmarkNPKs17_24(b *testing.B) { benchmarkDKGNodePubliKeys(17, 24, b) } +func BenchmarkNPKs81_121(b *testing.B) { benchmarkDKGNodePubliKeys(81, 121, b) } + +func benchmarkDKGNodePubliKeys(k, n int, b *testing.B) { + round := uint64(1) + _, pubKeys, err := test.NewKeys(n) + if err != nil { + panic(err) + } + gov, err := test.NewGovernance(test.NewState(DKGDelayRound, + pubKeys, 100, &common.NullLogger{}, true), ConfigRoundShift) + if err != nil { + panic(err) + } + + for _, pk := range pubKeys { + _, pubShare := dkg.NewPrivateKeyShares(k) + gov.AddDKGMasterPublicKey(round, &typesDKG.MasterPublicKey{ + ProposerID: types.NewNodeID(pk), + Round: round, + DKGID: typesDKG.NewID(types.NewNodeID(pk)), + PublicKeyShares: *pubShare, + }) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // DKG is fininished. + npks, err := typesDKG.NewNodePublicKeys(round, + gov.DKGMasterPublicKeys(round), gov.DKGComplaints(round), + k, + ) + if err != nil { + panic(err) + } + if len(npks.QualifyIDs) != n { + panic("not enough of qualify id") + } + } +} diff --git a/core/types/dkg/dkg.go b/core/types/dkg/dkg.go index 00c04be..1052ccb 100644 --- a/core/types/dkg/dkg.go +++ b/core/types/dkg/dkg.go @@ -289,7 +289,6 @@ type GroupPublicKey struct { 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 } @@ -300,15 +299,12 @@ func (gpk *GroupPublicKey) VerifySignature( return gpk.GroupPublicKey.VerifySignature(hash, sig) } -// NewGroupPublicKey creats a GroupPublicKey instance. -func NewGroupPublicKey( - round uint64, - mpks []*MasterPublicKey, complaints []*Complaint, - threshold int) ( - *GroupPublicKey, error) { - +func calcQualifyNodes( + mpks []*MasterPublicKey, complaints []*Complaint, threshold int) ( + qualifyIDs cryptoDKG.IDs, qualifyNodeIDs map[types.NodeID]struct{}, err error) { if len(mpks) < threshold { - return nil, ErrInvalidThreshold + err = ErrInvalidThreshold + return } // Calculate qualify members. @@ -331,21 +327,87 @@ func NewGroupPublicKey( disqualifyIDs[nID] = struct{}{} } } - qualifyIDs := make(cryptoDKG.IDs, 0, len(mpks)-len(disqualifyIDs)) + qualifyIDs = make(cryptoDKG.IDs, 0, len(mpks)-len(disqualifyIDs)) if cap(qualifyIDs) < threshold { - return nil, ErrNotReachThreshold + err = ErrNotReachThreshold + return + } + qualifyNodeIDs = make(map[types.NodeID]struct{}) + for _, mpk := range mpks { + if _, exist := disqualifyIDs[mpk.ProposerID]; exist { + continue + } + qualifyIDs = append(qualifyIDs, mpk.DKGID) + qualifyNodeIDs[mpk.ProposerID] = struct{}{} + } + return +} + +// NewGroupPublicKey creats a GroupPublicKey instance. +func NewGroupPublicKey( + round uint64, + mpks []*MasterPublicKey, complaints []*Complaint, + threshold int) ( + *GroupPublicKey, error) { + qualifyIDs, qualifyNodeIDs, err := + calcQualifyNodes(mpks, complaints, threshold) + if err != nil { + return nil, err } - 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 { + if _, exist := qualifyNodeIDs[mpk.ProposerID]; !exist { + continue + } + mpkMap[mpk.DKGID] = mpk + idMap[mpk.ProposerID] = mpk.DKGID + } + // 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, + Threshold: threshold, + GroupPublicKey: groupPK, + }, nil +} + +// NodePublicKeys is the result of DKG protocol. +type NodePublicKeys struct { + Round uint64 + QualifyIDs cryptoDKG.IDs + QualifyNodeIDs map[types.NodeID]struct{} + IDMap map[types.NodeID]cryptoDKG.ID + PublicKeys map[types.NodeID]*cryptoDKG.PublicKey + Threshold int +} + +// NewNodePublicKeys creats a NodePublicKeys instance. +func NewNodePublicKeys( + round uint64, + mpks []*MasterPublicKey, complaints []*Complaint, + threshold int) ( + *NodePublicKeys, error) { + qualifyIDs, qualifyNodeIDs, err := + calcQualifyNodes(mpks, complaints, threshold) + if err != nil { + return nil, err + } + mpkMap := make(map[cryptoDKG.ID]*MasterPublicKey, cap(qualifyIDs)) + idMap := make(map[types.NodeID]cryptoDKG.ID) + for _, mpk := range mpks { + if _, exist := qualifyNodeIDs[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)) @@ -366,19 +428,12 @@ func NewGroupPublicKey( } 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{ + return &NodePublicKeys{ Round: round, QualifyIDs: qualifyIDs, QualifyNodeIDs: qualifyNodeIDs, IDMap: idMap, PublicKeys: pubKeys, Threshold: threshold, - GroupPublicKey: groupPK, }, nil } |