diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/configuration-chain.go | 239 | ||||
-rw-r--r-- | core/consensus.go | 77 | ||||
-rw-r--r-- | core/consensus_test.go | 6 | ||||
-rw-r--r-- | core/crypto.go | 4 | ||||
-rw-r--r-- | core/dkg-tsig-protocol.go | 19 | ||||
-rw-r--r-- | core/dkg-tsig-protocol_test.go | 25 | ||||
-rw-r--r-- | core/interfaces.go | 11 | ||||
-rw-r--r-- | core/test/governance.go | 15 | ||||
-rw-r--r-- | core/types/config.go | 43 | ||||
-rw-r--r-- | core/types/dkg.go | 18 | ||||
-rw-r--r-- | core/utils.go | 28 |
11 files changed, 427 insertions, 58 deletions
diff --git a/core/configuration-chain.go b/core/configuration-chain.go new file mode 100644 index 0000000..88232c6 --- /dev/null +++ b/core/configuration-chain.go @@ -0,0 +1,239 @@ +// Copyright 2018 The dexon-consensus-core Authors +// This file is part of the dexon-consensus-core library. +// +// The dexon-consensus-core 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-core 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-core library. If not, see +// <http://www.gnu.org/licenses/>. + +package core + +import ( + "fmt" + "log" + "sync" + + "github.com/dexon-foundation/dexon-consensus-core/common" + "github.com/dexon-foundation/dexon-consensus-core/core/types" + "github.com/dexon-foundation/dexon-consensus-core/crypto" +) + +// Errors for configuration chain.. +var ( + ErrDKGNotRegistered = fmt.Errorf( + "not yet registered in DKG protocol") + ErrDKGNotReady = fmt.Errorf( + "DKG is not ready") +) + +type configurationChain struct { + ID types.NodeID + recv dkgReceiver + gov Governance + sigToPub SigToPubFn + dkg *dkgProtocol + dkgLock sync.RWMutex + dkgSigner map[uint64]*dkgShareSecret + gpk map[uint64]*dkgGroupPublicKey + dkgResult sync.RWMutex + tsig *tsigProtocol + tsigReady *sync.Cond + // TODO(jimmy-dexon): add timeout to pending psig. + pendingPsig []*types.DKGPartialSignature + prevHash common.Hash +} + +func newConfigurationChain( + ID types.NodeID, + recv dkgReceiver, + gov Governance, + sigToPub SigToPubFn) *configurationChain { + return &configurationChain{ + ID: ID, + recv: recv, + gov: gov, + sigToPub: sigToPub, + dkgSigner: make(map[uint64]*dkgShareSecret), + gpk: make(map[uint64]*dkgGroupPublicKey), + tsigReady: sync.NewCond(&sync.Mutex{}), + } +} + +func (cc *configurationChain) registerDKG(round uint64, threshold int) { + cc.dkg = newDKGProtocol( + cc.ID, + cc.recv, + round, + threshold, + cc.sigToPub) +} + +func (cc *configurationChain) runDKG(round uint64) error { + cc.dkgLock.Lock() + defer cc.dkgLock.Unlock() + if cc.dkg == nil || cc.dkg.round != round { + return ErrDKGNotRegistered + } + if func() bool { + cc.dkgResult.RLock() + defer cc.dkgResult.RUnlock() + _, exist := cc.gpk[round] + return exist + }() { + return nil + } + + ticker := newTicker(cc.gov, TickerDKG) + cc.dkgLock.Unlock() + <-ticker.Tick() + cc.dkgLock.Lock() + // Phase 2(T = 0): Exchange DKG secret key share. + cc.dkg.processMasterPublicKeys(cc.gov.DKGMasterPublicKeys(round)) + // Phase 3(T = 0~λ): Propose complaint. + // Propose complaint is done in `processMasterPublicKeys`. + cc.dkgLock.Unlock() + <-ticker.Tick() + cc.dkgLock.Lock() + // Phase 4(T = λ): Propose nack complaints. + cc.dkg.proposeNackComplaints() + cc.dkgLock.Unlock() + <-ticker.Tick() + cc.dkgLock.Lock() + // Phase 5(T = 2λ): Propose Anti nack complaint. + cc.dkg.processNackComplaints(cc.gov.DKGComplaints(round)) + cc.dkgLock.Unlock() + <-ticker.Tick() + cc.dkgLock.Lock() + // Phase 6(T = 3λ): Rebroadcast anti nack complaint. + // Rebroadcast is done in `processPrivateShare`. + cc.dkgLock.Unlock() + <-ticker.Tick() + cc.dkgLock.Lock() + // Phase 7(T = 4λ): Enforce complaints and nack complaints. + cc.dkg.enforceNackComplaints(cc.gov.DKGComplaints(round)) + // Enforce complaint is done in `processPrivateShare`. + // Phase 8(T = 5λ): DKG is ready. + cc.dkgLock.Unlock() + <-ticker.Tick() + cc.dkgLock.Lock() + gpk, err := newDKGGroupPublicKey(round, + cc.gov.DKGMasterPublicKeys(round), + cc.gov.DKGComplaints(round), + cc.dkg.threshold, cc.sigToPub) + if err != nil { + return err + } + signer, err := cc.dkg.recoverShareSecret(gpk.qualifyIDs) + if err != nil { + return err + } + qualifies := "" + for _, nID := range gpk.qualifyNodeIDs { + qualifies += fmt.Sprintf("%s ", nID.String()[:6]) + } + log.Printf("[%s] Qualify Nodes(%d): %s\n", + cc.ID, len(gpk.qualifyIDs), qualifies) + cc.dkgResult.Lock() + defer cc.dkgResult.Unlock() + cc.dkgSigner[round] = signer + cc.gpk[round] = gpk + return nil +} + +func (cc *configurationChain) preparePartialSignature( + round uint64, hash common.Hash) (*types.DKGPartialSignature, error) { + signer, exist := func() (*dkgShareSecret, bool) { + cc.dkgResult.RLock() + defer cc.dkgResult.RUnlock() + signer, exist := cc.dkgSigner[round] + return signer, exist + }() + if !exist { + return nil, ErrDKGNotReady + } + return &types.DKGPartialSignature{ + ProposerID: cc.ID, + Round: round, + PartialSignature: signer.sign(hash), + }, nil +} + +func (cc *configurationChain) runBlockTSig( + round uint64, hash common.Hash) error { + gpk, exist := func() (*dkgGroupPublicKey, bool) { + cc.dkgResult.RLock() + defer cc.dkgResult.RUnlock() + gpk, exist := cc.gpk[round] + return gpk, exist + }() + if !exist { + return ErrDKGNotReady + } + cc.tsigReady.L.Lock() + defer cc.tsigReady.L.Unlock() + cc.tsig = newTSigProtocol(gpk, hash, types.TSigConfigurationBlock) + pendingPsig := cc.pendingPsig + cc.pendingPsig = []*types.DKGPartialSignature{} + go func() { + for _, psig := range pendingPsig { + if err := cc.processPartialSignature(psig); err != nil { + log.Printf("[%s] %s", cc.ID, err) + } + } + }() + var signature crypto.Signature + var err error + for func() bool { + signature, err = cc.tsig.signature() + return err == ErrNotEnoughtPartialSignatures + }() { + cc.tsigReady.Wait() + } + cc.tsig = nil + if err != nil { + return err + } + log.Printf("[%s] TSIG: %s\n", cc.ID, signature) + return nil +} + +func (cc *configurationChain) processPrivateShare( + prvShare *types.DKGPrivateShare) error { + cc.dkgLock.Lock() + defer cc.dkgLock.Unlock() + if cc.dkg == nil { + return nil + } + return cc.dkg.processPrivateShare(prvShare) +} + +func (cc *configurationChain) processPartialSignature( + psig *types.DKGPartialSignature) error { + cc.tsigReady.L.Lock() + defer cc.tsigReady.L.Unlock() + if cc.tsig == nil { + ok, err := verifyDKGPartialSignatureSignature(psig, cc.sigToPub) + if err != nil { + return err + } + if !ok { + return ErrIncorrectPartialSignatureSignature + } + cc.pendingPsig = append(cc.pendingPsig, psig) + return nil + } + if err := cc.tsig.processPartialSignature(psig); err != nil { + return err + } + cc.tsigReady.Broadcast() + return nil +} diff --git a/core/consensus.go b/core/consensus.go index fc7cd70..f6ce3de 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -186,7 +186,7 @@ type Consensus struct { // DKG. dkgRunning int32 dkgReady *sync.Cond - dkgModule *dkgProtocol + cfgModule *configurationChain // Dexon consensus modules. rbModule *reliableBroadcast @@ -243,8 +243,7 @@ func NewConsensus( uint64(float32(len(notarySet)-1)*config.PhiRatio+1), config.NumChains) - // Setup DKG Protocol. - dkgModule := newDKGProtocol( + cfgModule := newConfigurationChain( ID, &consensusDKGReceiver{ ID: ID, @@ -252,9 +251,11 @@ func NewConsensus( prvKey: prv, network: network, }, - 0, - len(notarySet)/3, + gov, sigToPub) + // Register DKG for the initial round. This is a temporary function call for + // simulation. + cfgModule.registerDKG(0, len(notarySet)/3) // Check if the application implement Debug interface. debug, _ := app.(Debug) @@ -272,7 +273,7 @@ func NewConsensus( tickerObj: newTicker(gov, TickerBA), prvKey: prv, dkgReady: sync.NewCond(&sync.Mutex{}), - dkgModule: dkgModule, + cfgModule: cfgModule, sigToPub: sigToPub, notarySet: notarySet, ctx: ctx, @@ -308,7 +309,7 @@ func NewConsensus( // Run starts running DEXON Consensus. func (con *Consensus) Run() { go con.processMsg(con.network.ReceiveChan(), con.PreProcessBlock) - con.runDKG() + con.runDKGTSIG() con.dkgReady.L.Lock() defer con.dkgReady.L.Unlock() for con.dkgRunning != 2 { @@ -374,8 +375,8 @@ BALoop: } } -// runDKG starts running DKG protocol. -func (con *Consensus) runDKG() { +// runDKGTSIG starts running DKG+TSIG protocol. +func (con *Consensus) runDKGTSIG() { con.dkgReady.L.Lock() defer con.dkgReady.L.Unlock() if con.dkgRunning != 0 { @@ -389,40 +390,30 @@ func (con *Consensus) runDKG() { con.dkgReady.Broadcast() con.dkgRunning = 2 }() - ticker := newTicker(con.gov, TickerDKG) - round := con.dkgModule.round - <-ticker.Tick() - // Phase 2(T = 0): Exchange DKG secret key share. - con.dkgModule.processMasterPublicKeys(con.gov.DKGMasterPublicKeys(round)) - // Phase 3(T = 0~λ): Propose complaint. - // Propose complaint is done in `processMasterPublicKeys`. - <-ticker.Tick() - // Phase 4(T = λ): Propose nack complaints. - con.dkgModule.proposeNackComplaints() - <-ticker.Tick() - // Phase 5(T = 2λ): Propose Anti nack complaint. - con.dkgModule.processNackComplaints(con.gov.DKGComplaints(round)) - <-ticker.Tick() - // Phase 6(T = 3λ): Rebroadcast anti nack complaint. - // Rebroadcast is done in `processPrivateShare`. - <-ticker.Tick() - // Phase 7(T = 4λ): Enforce complaints and nack complaints. - con.dkgModule.enforceNackComplaints(con.gov.DKGComplaints(round)) - // Enforce complaint is done in `processPrivateShare`. - // Phase 8(T = 5λ): DKG is ready. - gpk, err := newDKGGroupPublicKey(round, - con.gov.DKGMasterPublicKeys(round), - con.gov.DKGComplaints(round), - con.dkgModule.threshold, con.sigToPub) + round := con.cfgModule.dkg.round + if err := con.cfgModule.runDKG(round); err != nil { + panic(err) + } + hash := HashConfigurationBlock( + con.gov.GetNotarySet(0), + con.gov.GetConfiguration(0), + common.Hash{}, + con.cfgModule.prevHash) + psig, err := con.cfgModule.preparePartialSignature(round, hash) + if err != nil { + panic(err) + } + psig.Signature, err = con.prvKey.Sign(hashDKGPartialSignature(psig)) if err != nil { panic(err) } - qualifies := "" - for _, nID := range gpk.qualifyNodeIDs { - qualifies += fmt.Sprintf("%s ", nID.String()[:6]) + if err = con.cfgModule.processPartialSignature(psig); err != nil { + panic(err) + } + con.network.BroadcastDKGPartialSignature(psig) + if err = con.cfgModule.runBlockTSig(round, hash); err != nil { + panic(err) } - log.Printf("[%s] Qualify Nodes(%d): %s\n", - con.ID, len(gpk.qualifyIDs), qualifies) }() } @@ -512,10 +503,12 @@ func (con *Consensus) processMsg( log.Println(err) } case *types.DKGPrivateShare: - if con.dkgRunning == 0 { - break + if err := con.cfgModule.processPrivateShare(val); err != nil { + log.Println(err) } - if err := con.dkgModule.processPrivateShare(val); err != nil { + + case *types.DKGPartialSignature: + if err := con.cfgModule.processPartialSignature(val); err != nil { log.Println(err) } } diff --git a/core/consensus_test.go b/core/consensus_test.go index 2b71d6b..a58d3e8 100644 --- a/core/consensus_test.go +++ b/core/consensus_test.go @@ -55,6 +55,12 @@ func (n *network) BroadcastDKGPrivateShare( prvShare *types.DKGPrivateShare) { } +// BroadcastDKGPartialSignature broadcasts partialSignature to all +// DKG participants. +func (n *network) BroadcastDKGPartialSignature( + psig *types.DKGPartialSignature) { +} + // ReceiveChan returns a channel to receive messages from DEXON network. func (n *network) ReceiveChan() <-chan interface{} { return make(chan interface{}) diff --git a/core/crypto.go b/core/crypto.go index c95811e..26e44f9 100644 --- a/core/crypto.go +++ b/core/crypto.go @@ -225,9 +225,13 @@ func hashDKGPartialSignature(psig *types.DKGPartialSignature) common.Hash { binaryRound := make([]byte, 8) binary.LittleEndian.PutUint64(binaryRound, psig.Round) + binaryType := make([]byte, 4) + binary.LittleEndian.PutUint32(binaryType, uint32(psig.Type)) + return crypto.Keccak256Hash( psig.ProposerID.Hash[:], binaryRound, + binaryType, psig.PartialSignature[:], ) } diff --git a/core/dkg-tsig-protocol.go b/core/dkg-tsig-protocol.go index ccd2439..0f5cb0b 100644 --- a/core/dkg-tsig-protocol.go +++ b/core/dkg-tsig-protocol.go @@ -38,6 +38,8 @@ var ( "threshold not reach") ErrIncorrectPrivateShareSignature = fmt.Errorf( "incorrect private share signature") + ErrMismatchPartialSignatureType = fmt.Errorf( + "mismatch partialSignature type") ErrIncorrectPartialSignatureSignature = fmt.Errorf( "incorrect partialSignature signature") ErrIncorrectPartialSignature = fmt.Errorf( @@ -93,6 +95,8 @@ type dkgGroupPublicKey struct { type tsigProtocol struct { groupPublicKey *dkgGroupPublicKey + hash common.Hash + psigType types.DKGPartialSignatureType sigs map[dkg.ID]dkg.PartialSignature threshold int } @@ -386,9 +390,14 @@ func (gpk *dkgGroupPublicKey) verifySignature( return gpk.groupPublicKey.VerifySignature(hash, sig) } -func newTSigProtocol(gpk *dkgGroupPublicKey) *tsigProtocol { +func newTSigProtocol( + gpk *dkgGroupPublicKey, + hash common.Hash, + psigType types.DKGPartialSignatureType) *tsigProtocol { return &tsigProtocol{ groupPublicKey: gpk, + hash: hash, + psigType: psigType, sigs: make(map[dkg.ID]dkg.PartialSignature, gpk.threshold+1), } } @@ -406,11 +415,14 @@ func (tsig *tsigProtocol) sanityCheck(psig *types.DKGPartialSignature) error { if !ok { return ErrIncorrectPartialSignatureSignature } + if psig.Type != tsig.psigType { + return ErrMismatchPartialSignatureType + } return nil } func (tsig *tsigProtocol) processPartialSignature( - hash common.Hash, psig *types.DKGPartialSignature) error { + psig *types.DKGPartialSignature) error { if psig.Round != tsig.groupPublicKey.round { return nil } @@ -422,7 +434,8 @@ func (tsig *tsigProtocol) processPartialSignature( return err } pubKey := tsig.groupPublicKey.publicKeys[psig.ProposerID] - if !pubKey.VerifySignature(hash, crypto.Signature(psig.PartialSignature)) { + if !pubKey.VerifySignature( + tsig.hash, crypto.Signature(psig.PartialSignature)) { return ErrIncorrectPartialSignature } tsig.sigs[id] = psig.PartialSignature diff --git a/core/dkg-tsig-protocol_test.go b/core/dkg-tsig-protocol_test.go index 19709d3..0c938f7 100644 --- a/core/dkg-tsig-protocol_test.go +++ b/core/dkg-tsig-protocol_test.go @@ -211,18 +211,19 @@ func (s *DKGTSIGProtocolTestSuite) TestDKGTSIGProtocol() { s.Require().NoError(err) } - tsig := newTSigProtocol(gpk) msgHash := crypto.Keccak256Hash([]byte("🏖🍹")) + tsig := newTSigProtocol(gpk, msgHash, types.TSigConfigurationBlock) for nID, shareSecret := range shareSecrets { psig := &types.DKGPartialSignature{ ProposerID: nID, Round: round, + Type: types.TSigConfigurationBlock, PartialSignature: shareSecret.sign(msgHash), } var err error psig.Signature, err = s.prvKeys[nID].Sign(hashDKGPartialSignature(psig)) s.Require().NoError(err) - s.Require().NoError(tsig.processPartialSignature(msgHash, psig)) + s.Require().NoError(tsig.processPartialSignature(psig)) if len(tsig.sigs) > k { break } @@ -577,28 +578,36 @@ func (s *DKGTSIGProtocolTestSuite) TestPartialSignature() { s.Require().NoError(err) } - tsig := newTSigProtocol(gpk) msgHash := crypto.Keccak256Hash([]byte("🏖🍹")) + tsig := newTSigProtocol(gpk, msgHash, types.TSigConfigurationBlock) byzantineID2 := s.nIDs[1] + byzantineID3 := s.nIDs[2] for nID, shareSecret := range shareSecrets { psig := &types.DKGPartialSignature{ ProposerID: nID, Round: round, + Type: types.TSigConfigurationBlock, PartialSignature: shareSecret.sign(msgHash), } - if nID == byzantineID2 { + switch nID { + case byzantineID2: psig.PartialSignature = shareSecret.sign( crypto.Keccak256Hash([]byte("💣"))) + case byzantineID3: + psig.Type = types.TSigNotaryAck } var err error psig.Signature, err = s.prvKeys[nID].Sign(hashDKGPartialSignature(psig)) s.Require().NoError(err) - err = tsig.processPartialSignature(msgHash, psig) - if nID == byzantineID { + err = tsig.processPartialSignature(psig) + switch nID { + case byzantineID: s.Require().Equal(ErrNotQualifyDKGParticipant, err) - } else if nID == byzantineID2 { + case byzantineID2: s.Require().Equal(ErrIncorrectPartialSignature, err) - } else { + case byzantineID3: + s.Require().Equal(ErrMismatchPartialSignatureType, err) + default: s.Require().NoError(err) } } diff --git a/core/interfaces.go b/core/interfaces.go index 940d9b5..7f6ff2b 100644 --- a/core/interfaces.go +++ b/core/interfaces.go @@ -22,6 +22,7 @@ import ( "github.com/dexon-foundation/dexon-consensus-core/common" "github.com/dexon-foundation/dexon-consensus-core/core/types" + "github.com/dexon-foundation/dexon-consensus-core/crypto" ) // Application describes the application interface that interacts with DEXON @@ -76,6 +77,10 @@ type Network interface { // BroadcastDKGPrivateShare broadcasts PrivateShare to all DKG participants. BroadcastDKGPrivateShare(prvShare *types.DKGPrivateShare) + // BroadcastDKGPartialSignature broadcasts partialSignature to all + // DKG participants. + BroadcastDKGPartialSignature(psig *types.DKGPartialSignature) + // ReceiveChan returns a channel to receive messages from DEXON network. ReceiveChan() <-chan interface{} } @@ -92,6 +97,12 @@ type Governance interface { // Return the genesis notary set if blockHeight == 0. GetNotarySet(blockHeight uint64) map[types.NodeID]struct{} + // Porpose a ThresholdSignature of round. + ProposeThresholdSignature(round uint64, signature crypto.Signature) + + // Get a ThresholdSignature of round. + GetThresholdSignature(round uint64) (sig crypto.Signature, exist bool) + //// DKG-related methods. // AddDKGComplaint adds a DKGComplaint. diff --git a/core/test/governance.go b/core/test/governance.go index 0bcb39a..1225b4a 100644 --- a/core/test/governance.go +++ b/core/test/governance.go @@ -38,6 +38,7 @@ type Governance struct { lambdaDKG time.Duration notarySet map[types.NodeID]struct{} privateKeys map[types.NodeID]crypto.PrivateKey + tsig map[uint64]crypto.Signature DKGComplaint map[uint64][]*types.DKGComplaint DKGMasterPublicKey map[uint64][]*types.DKGMasterPublicKey } @@ -50,6 +51,7 @@ func NewGovernance(nodeCount int, lambda time.Duration) ( lambdaDKG: lambda * 10, notarySet: make(map[types.NodeID]struct{}), privateKeys: make(map[types.NodeID]crypto.PrivateKey), + tsig: make(map[uint64]crypto.Signature), DKGComplaint: make(map[uint64][]*types.DKGComplaint), DKGMasterPublicKey: make(map[uint64][]*types.DKGMasterPublicKey), } @@ -103,6 +105,19 @@ func (g *Governance) GetPrivateKey( return } +// ProposeThresholdSignature porposes a ThresholdSignature of round. +func (g *Governance) ProposeThresholdSignature( + round uint64, signature crypto.Signature) { + g.tsig[round] = signature +} + +// GetThresholdSignature gets a ThresholdSignature of round. +func (g *Governance) GetThresholdSignature(round uint64) ( + sig crypto.Signature, exist bool) { + sig, exist = g.tsig[round] + return +} + // AddDKGComplaint add a DKGComplaint. func (g *Governance) AddDKGComplaint(complaint *types.DKGComplaint) { g.DKGComplaint[complaint.Round] = append(g.DKGComplaint[complaint.Round], complaint) diff --git a/core/types/config.go b/core/types/config.go index 3c0bced..034853e 100644 --- a/core/types/config.go +++ b/core/types/config.go @@ -17,7 +17,11 @@ package types -import "time" +import ( + "encoding/binary" + "math" + "time" +) // Config stands for Current Configuration Parameters. type Config struct { @@ -35,4 +39,41 @@ type Config struct { // Total ordering related. K int PhiRatio float32 + + // Confiuration chain related. + RoundHeight uint64 +} + +// Bytes returns []byte representation of Config. +func (c *Config) Bytes() []byte { + binaryNumShards := make([]byte, 4) + binary.LittleEndian.PutUint32(binaryNumShards, c.NumShards) + binaryNumChains := make([]byte, 4) + binary.LittleEndian.PutUint32(binaryNumChains, c.NumChains) + + binaryLambdaBA := make([]byte, 8) + binary.LittleEndian.PutUint64( + binaryLambdaBA, uint64(c.LambdaBA.Nanoseconds())) + binaryLambdaDKG := make([]byte, 8) + binary.LittleEndian.PutUint64( + binaryLambdaDKG, uint64(c.LambdaDKG.Nanoseconds())) + + binaryK := make([]byte, 4) + binary.LittleEndian.PutUint32(binaryK, uint32(c.K)) + binaryPhiRatio := make([]byte, 4) + binary.LittleEndian.PutUint32(binaryPhiRatio, math.Float32bits(c.PhiRatio)) + + binaryRoundHeight := make([]byte, 8) + binary.LittleEndian.PutUint64(binaryRoundHeight, c.RoundHeight) + + enc := make([]byte, 0, 40) + enc = append(enc, binaryNumShards...) + enc = append(enc, binaryNumChains...) + enc = append(enc, binaryLambdaBA...) + enc = append(enc, binaryLambdaDKG...) + enc = append(enc, binaryK...) + enc = append(enc, binaryPhiRatio...) + enc = append(enc, binaryRoundHeight...) + + return enc } diff --git a/core/types/dkg.go b/core/types/dkg.go index ff0aa75..10a31ee 100644 --- a/core/types/dkg.go +++ b/core/types/dkg.go @@ -59,12 +59,22 @@ type DKGComplaint struct { Signature crypto.Signature `json:"signature"` } +// DKGPartialSignatureType specifies ths threshold signature type. +type DKGPartialSignatureType uint32 + +// TSig enums. +const ( + TSigConfigurationBlock DKGPartialSignatureType = iota + TSigNotaryAck +) + // DKGPartialSignature describe a partial signature in DKG protocol. type DKGPartialSignature struct { - ProposerID NodeID `json:"proposerID"` - Round uint64 `json:"round"` - PartialSignature dkg.PartialSignature `json:"partial_signature"` - Signature crypto.Signature `json:"signature"` + ProposerID NodeID `json:"proposerID"` + Round uint64 `json:"round"` + Type DKGPartialSignatureType `json:"type"` + PartialSignature dkg.PartialSignature `json:"partial_signature"` + Signature crypto.Signature `json:"signature"` } // IsNack returns true if it's a nack complaint in DKG protocol. diff --git a/core/utils.go b/core/utils.go index 7aa99f0..30456ef 100644 --- a/core/utils.go +++ b/core/utils.go @@ -25,6 +25,8 @@ import ( "time" "github.com/dexon-foundation/dexon-consensus-core/common" + "github.com/dexon-foundation/dexon-consensus-core/core/types" + "github.com/dexon-foundation/dexon-consensus-core/crypto" ) var ( @@ -102,3 +104,29 @@ func removeFromSortedUint32Slice(xs []uint32, x uint32) []uint32 { } return append(xs[:indexToRemove], xs[indexToRemove+1:]...) } + +// HashConfigurationBlock returns the hash value of configuration block. +func HashConfigurationBlock( + notarySet map[types.NodeID]struct{}, + config *types.Config, + snapshotHash common.Hash, + prevHash common.Hash, +) common.Hash { + notaryIDs := make(types.NodeIDs, 0, len(notarySet)) + for nID := range notarySet { + notaryIDs = append(notaryIDs, nID) + } + sort.Sort(notaryIDs) + notarySetBytes := make([]byte, 0, len(notarySet)*len(common.Hash{})) + for _, nID := range notaryIDs { + notarySetBytes = append(notarySetBytes, nID.Hash[:]...) + } + configBytes := config.Bytes() + + return crypto.Keccak256Hash( + notarySetBytes[:], + configBytes[:], + snapshotHash[:], + prevHash[:], + ) +} |