diff options
Diffstat (limited to 'vendor/github.com/dexon-foundation/dexon-consensus-core/core/dkg-tsig-protocol.go')
-rw-r--r-- | vendor/github.com/dexon-foundation/dexon-consensus-core/core/dkg-tsig-protocol.go | 578 |
1 files changed, 0 insertions, 578 deletions
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus-core/core/dkg-tsig-protocol.go b/vendor/github.com/dexon-foundation/dexon-consensus-core/core/dkg-tsig-protocol.go deleted file mode 100644 index 6645ecbae..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus-core/core/dkg-tsig-protocol.go +++ /dev/null @@ -1,578 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// <http://www.gnu.org/licenses/>. - -package core - -import ( - "fmt" - "sync" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" - "github.com/dexon-foundation/dexon-consensus/core/types" - typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg" -) - -// Errors for dkg module. -var ( - ErrNotDKGParticipant = fmt.Errorf( - "not a DKG participant") - ErrNotQualifyDKGParticipant = fmt.Errorf( - "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( - "mismatch partialSignature hash") - ErrIncorrectPartialSignatureSignature = fmt.Errorf( - "incorrect partialSignature signature") - ErrIncorrectPartialSignature = fmt.Errorf( - "incorrect partialSignature") - ErrNotEnoughtPartialSignatures = fmt.Errorf( - "not enough of partial signatures") - ErrRoundAlreadyPurged = fmt.Errorf( - "cache of round already been purged") -) - -type dkgReceiver interface { - // ProposeDKGComplaint proposes a DKGComplaint. - ProposeDKGComplaint(complaint *typesDKG.Complaint) - - // ProposeDKGMasterPublicKey propose a DKGMasterPublicKey. - ProposeDKGMasterPublicKey(mpk *typesDKG.MasterPublicKey) - - // ProposeDKGPrivateShare propose a DKGPrivateShare. - ProposeDKGPrivateShare(prv *typesDKG.PrivateShare) - - // ProposeDKGAntiNackComplaint propose a DKGPrivateShare as an anti complaint. - ProposeDKGAntiNackComplaint(prv *typesDKG.PrivateShare) - - // ProposeDKGFinalize propose a DKGFinalize message. - ProposeDKGFinalize(final *typesDKG.Finalize) -} - -type dkgProtocol struct { - ID types.NodeID - recv dkgReceiver - round uint64 - threshold int - idMap map[types.NodeID]dkg.ID - mpkMap map[types.NodeID]*dkg.PublicKeyShares - masterPrivateShare *dkg.PrivateKeyShares - prvShares *dkg.PrivateKeyShares - prvSharesReceived map[types.NodeID]struct{} - nodeComplained map[types.NodeID]struct{} - // Complaint[from][to]'s anti is saved to antiComplaint[from][to]. - antiComplaintReceived map[types.NodeID]map[types.NodeID]struct{} -} - -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 -} - -// TSigVerifierCacheInterface specifies interface used by TSigVerifierCache. -type TSigVerifierCacheInterface interface { - // Configuration returns the configuration at a given round. - // Return the genesis configuration if round == 0. - Configuration(round uint64) *types.Config - - // DKGComplaints gets all the DKGComplaints of round. - DKGComplaints(round uint64) []*typesDKG.Complaint - - // DKGMasterPublicKeys gets all the DKGMasterPublicKey of round. - DKGMasterPublicKeys(round uint64) []*typesDKG.MasterPublicKey - - // IsDKGFinal checks if DKG is final. - IsDKGFinal(round uint64) bool -} - -// TSigVerifierCache is the cache for TSigVerifier. -type TSigVerifierCache struct { - intf TSigVerifierCacheInterface - verifier map[uint64]TSigVerifier - minRound uint64 - cacheSize int - lock sync.RWMutex -} - -type tsigProtocol struct { - groupPublicKey *DKGGroupPublicKey - hash common.Hash - sigs map[dkg.ID]dkg.PartialSignature - threshold int -} - -func newDKGID(ID types.NodeID) dkg.ID { - return dkg.NewID(ID.Hash[:]) -} - -func newDKGProtocol( - ID types.NodeID, - recv dkgReceiver, - round uint64, - threshold int) *dkgProtocol { - - prvShare, pubShare := dkg.NewPrivateKeyShares(threshold) - - recv.ProposeDKGMasterPublicKey(&typesDKG.MasterPublicKey{ - ProposerID: ID, - Round: round, - DKGID: newDKGID(ID), - PublicKeyShares: *pubShare, - }) - - return &dkgProtocol{ - ID: ID, - recv: recv, - round: round, - threshold: threshold, - idMap: make(map[types.NodeID]dkg.ID), - mpkMap: make(map[types.NodeID]*dkg.PublicKeyShares), - masterPrivateShare: prvShare, - prvShares: dkg.NewEmptyPrivateKeyShares(), - prvSharesReceived: make(map[types.NodeID]struct{}), - nodeComplained: make(map[types.NodeID]struct{}), - antiComplaintReceived: make(map[types.NodeID]map[types.NodeID]struct{}), - } -} - -func (d *dkgProtocol) processMasterPublicKeys( - mpks []*typesDKG.MasterPublicKey) error { - d.idMap = make(map[types.NodeID]dkg.ID, len(mpks)) - d.mpkMap = make(map[types.NodeID]*dkg.PublicKeyShares, len(mpks)) - d.prvSharesReceived = make(map[types.NodeID]struct{}, len(mpks)) - ids := make(dkg.IDs, len(mpks)) - for i := range mpks { - nID := mpks[i].ProposerID - d.idMap[nID] = mpks[i].DKGID - d.mpkMap[nID] = &mpks[i].PublicKeyShares - ids[i] = mpks[i].DKGID - } - d.masterPrivateShare.SetParticipants(ids) - for _, mpk := range mpks { - share, ok := d.masterPrivateShare.Share(mpk.DKGID) - if !ok { - return ErrIDShareNotFound - } - d.recv.ProposeDKGPrivateShare(&typesDKG.PrivateShare{ - ProposerID: d.ID, - ReceiverID: mpk.ProposerID, - Round: d.round, - PrivateShare: *share, - }) - } - return nil -} - -func (d *dkgProtocol) proposeNackComplaints() { - for nID := range d.mpkMap { - if _, exist := d.prvSharesReceived[nID]; exist { - continue - } - d.recv.ProposeDKGComplaint(&typesDKG.Complaint{ - ProposerID: d.ID, - Round: d.round, - PrivateShare: typesDKG.PrivateShare{ - ProposerID: nID, - Round: d.round, - }, - }) - } -} - -func (d *dkgProtocol) processNackComplaints(complaints []*typesDKG.Complaint) ( - err error) { - for _, complaint := range complaints { - if !complaint.IsNack() { - continue - } - if complaint.PrivateShare.ProposerID != d.ID { - continue - } - id, exist := d.idMap[complaint.ProposerID] - if !exist { - err = ErrNotDKGParticipant - continue - } - share, ok := d.masterPrivateShare.Share(id) - if !ok { - err = ErrIDShareNotFound - continue - } - d.recv.ProposeDKGAntiNackComplaint(&typesDKG.PrivateShare{ - ProposerID: d.ID, - ReceiverID: complaint.ProposerID, - Round: d.round, - PrivateShare: *share, - }) - } - return -} - -func (d *dkgProtocol) enforceNackComplaints(complaints []*typesDKG.Complaint) { - for _, complaint := range complaints { - if !complaint.IsNack() { - continue - } - to := complaint.PrivateShare.ProposerID - // Do not propose nack complaint to itself. - if to == d.ID { - continue - } - from := complaint.ProposerID - // Nack complaint is already proposed. - if from == d.ID { - continue - } - if _, exist := - d.antiComplaintReceived[from][to]; !exist { - d.recv.ProposeDKGComplaint(&typesDKG.Complaint{ - ProposerID: d.ID, - Round: d.round, - PrivateShare: typesDKG.PrivateShare{ - ProposerID: to, - Round: d.round, - }, - }) - } - } -} - -func (d *dkgProtocol) sanityCheck(prvShare *typesDKG.PrivateShare) error { - if _, exist := d.idMap[prvShare.ProposerID]; !exist { - return ErrNotDKGParticipant - } - ok, err := verifyDKGPrivateShareSignature(prvShare) - if err != nil { - return err - } - if !ok { - return ErrIncorrectPrivateShareSignature - } - return nil -} - -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 { - return nil - } - if err := d.sanityCheck(prvShare); err != nil { - return err - } - mpk := d.mpkMap[prvShare.ProposerID] - ok, err := mpk.VerifyPrvShare(receiverID, &prvShare.PrivateShare) - if err != nil { - return err - } - if prvShare.ReceiverID == d.ID { - d.prvSharesReceived[prvShare.ProposerID] = struct{}{} - } - if !ok { - if _, exist := d.nodeComplained[prvShare.ProposerID]; exist { - return nil - } - complaint := &typesDKG.Complaint{ - ProposerID: d.ID, - Round: d.round, - PrivateShare: *prvShare, - } - d.nodeComplained[prvShare.ProposerID] = struct{}{} - d.recv.ProposeDKGComplaint(complaint) - } else if prvShare.ReceiverID == d.ID { - sender := d.idMap[prvShare.ProposerID] - if err := d.prvShares.AddShare(sender, &prvShare.PrivateShare); err != nil { - return err - } - } else { - // The prvShare is an anti complaint. - if _, exist := d.antiComplaintReceived[prvShare.ReceiverID]; !exist { - d.antiComplaintReceived[prvShare.ReceiverID] = - make(map[types.NodeID]struct{}) - d.recv.ProposeDKGAntiNackComplaint(prvShare) - } - d.antiComplaintReceived[prvShare.ReceiverID][prvShare.ProposerID] = - struct{}{} - } - return nil -} - -func (d *dkgProtocol) proposeFinalize() { - d.recv.ProposeDKGFinalize(&typesDKG.Finalize{ - ProposerID: d.ID, - Round: d.round, - }) -} - -func (d *dkgProtocol) recoverShareSecret(qualifyIDs dkg.IDs) ( - *dkgShareSecret, error) { - if len(qualifyIDs) < d.threshold { - return nil, ErrNotReachThreshold - } - prvKey, err := d.prvShares.RecoverPrivateKey(qualifyIDs) - if err != nil { - return nil, err - } - return &dkgShareSecret{ - privateKey: prvKey, - }, nil -} - -func (ss *dkgShareSecret) sign(hash common.Hash) dkg.PartialSignature { - // DKG sign will always success. - sig, _ := ss.privateKey.Sign(hash) - 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]int{} - for _, complaint := range complaints { - if complaint.IsNack() { - complaintsByID[complaint.PrivateShare.ProposerID]++ - } else { - disqualifyIDs[complaint.PrivateShare.ProposerID] = struct{}{} - } - } - for nID, num := range complaintsByID { - if num > threshold { - disqualifyIDs[nID] = struct{}{} - } - } - qualifyIDs := make(dkg.IDs, 0, len(mpks)-len(disqualifyIDs)) - 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. -func NewTSigVerifierCache( - intf TSigVerifierCacheInterface, cacheSize int) *TSigVerifierCache { - return &TSigVerifierCache{ - intf: intf, - verifier: make(map[uint64]TSigVerifier), - cacheSize: cacheSize, - } -} - -// UpdateAndGet calls Update and then Get. -func (tc *TSigVerifierCache) UpdateAndGet(round uint64) ( - TSigVerifier, bool, error) { - ok, err := tc.Update(round) - if err != nil { - return nil, false, err - } - if !ok { - return nil, false, nil - } - v, ok := tc.Get(round) - return v, ok, nil -} - -// Update the cache and returns if success. -func (tc *TSigVerifierCache) Update(round uint64) (bool, error) { - tc.lock.Lock() - defer tc.lock.Unlock() - if round < tc.minRound { - return false, ErrRoundAlreadyPurged - } - if _, exist := tc.verifier[round]; exist { - return true, nil - } - if !tc.intf.IsDKGFinal(round) { - return false, nil - } - gpk, err := NewDKGGroupPublicKey(round, - tc.intf.DKGMasterPublicKeys(round), - tc.intf.DKGComplaints(round), - int(tc.intf.Configuration(round).DKGSetSize/3)+1) - if err != nil { - return false, err - } - if len(tc.verifier) == 0 { - tc.minRound = round - } - tc.verifier[round] = gpk - if len(tc.verifier) > tc.cacheSize { - delete(tc.verifier, tc.minRound) - } - for { - if _, exist := tc.verifier[tc.minRound]; !exist { - tc.minRound++ - } else { - break - } - } - return true, nil -} - -// Get the TSigVerifier of round and returns if it exists. -func (tc *TSigVerifierCache) Get(round uint64) (TSigVerifier, bool) { - tc.lock.RLock() - defer tc.lock.RUnlock() - verifier, exist := tc.verifier[round] - return verifier, exist -} - -func newTSigProtocol( - gpk *DKGGroupPublicKey, - hash common.Hash) *tsigProtocol { - return &tsigProtocol{ - groupPublicKey: gpk, - hash: hash, - sigs: make(map[dkg.ID]dkg.PartialSignature, gpk.threshold+1), - } -} - -func (tsig *tsigProtocol) sanityCheck(psig *typesDKG.PartialSignature) error { - _, exist := tsig.groupPublicKey.publicKeys[psig.ProposerID] - if !exist { - return ErrNotQualifyDKGParticipant - } - ok, err := verifyDKGPartialSignatureSignature(psig) - if err != nil { - return err - } - if !ok { - return ErrIncorrectPartialSignatureSignature - } - if psig.Hash != tsig.hash { - return ErrMismatchPartialSignatureHash - } - return nil -} - -func (tsig *tsigProtocol) processPartialSignature( - psig *typesDKG.PartialSignature) error { - if psig.Round != tsig.groupPublicKey.round { - return nil - } - 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] - if !pubKey.VerifySignature( - tsig.hash, crypto.Signature(psig.PartialSignature)) { - return ErrIncorrectPartialSignature - } - tsig.sigs[id] = psig.PartialSignature - return nil -} - -func (tsig *tsigProtocol) signature() (crypto.Signature, error) { - if len(tsig.sigs) < tsig.groupPublicKey.threshold { - return crypto.Signature{}, ErrNotEnoughtPartialSignatures - } - ids := make(dkg.IDs, 0, len(tsig.sigs)) - psigs := make([]dkg.PartialSignature, 0, len(tsig.sigs)) - for id, psig := range tsig.sigs { - ids = append(ids, id) - psigs = append(psigs, psig) - } - return dkg.RecoverSignature(psigs, ids) -} |