aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-09-19 18:58:15 +0800
committerGitHub <noreply@github.com>2018-09-19 18:58:15 +0800
commit37f117d35c6617e1944d45e001e03813a6a278ed (patch)
tree57314b479533bce05827acf0bcf64548a836e68f
parent22e70f6da486ed6796a493f25e04679b9afa1439 (diff)
downloadtangerine-consensus-37f117d35c6617e1944d45e001e03813a6a278ed.tar.gz
tangerine-consensus-37f117d35c6617e1944d45e001e03813a6a278ed.tar.zst
tangerine-consensus-37f117d35c6617e1944d45e001e03813a6a278ed.zip
core: Add dkg test (#119)
-rw-r--r--core/dkg-tsig-protocol_test.go194
-rw-r--r--crypto/dkg/dkg.go3
-rw-r--r--crypto/dkg/dkg_test.go13
3 files changed, 210 insertions, 0 deletions
diff --git a/core/dkg-tsig-protocol_test.go b/core/dkg-tsig-protocol_test.go
index 1ea65b2..7da8866 100644
--- a/core/dkg-tsig-protocol_test.go
+++ b/core/dkg-tsig-protocol_test.go
@@ -22,6 +22,7 @@ import (
"github.com/stretchr/testify/suite"
+ "github.com/dexon-foundation/dexon-consensus-core/common"
"github.com/dexon-foundation/dexon-consensus-core/core/test"
"github.com/dexon-foundation/dexon-consensus-core/core/types"
"github.com/dexon-foundation/dexon-consensus-core/crypto"
@@ -238,6 +239,199 @@ func (s *DKGTSIGProtocolTestSuite) TestNackComplaint() {
}
}
+// TestComplaint tests if the received private share is not valid, a complaint
+// should be proposed.
+func (s *DKGTSIGProtocolTestSuite) TestComplaint() {
+ k := 3
+ n := 10
+ round := uint64(1)
+ gov, err := test.NewGovernance(5, 100)
+ s.Require().NoError(err)
+
+ receivers, protocols := s.newProtocols(k, n, round)
+
+ byzantineID := s.vIDs[0]
+ targetID := s.vIDs[1]
+ receiver := receivers[targetID]
+ protocol := protocols[targetID]
+
+ for _, receiver := range receivers {
+ gov.AddDKGMasterPublicKey(receiver.mpk)
+ }
+
+ for _, protocol := range protocols {
+ s.Require().NoError(
+ protocol.processMasterPublicKeys(gov.DKGMasterPublicKeys(round)))
+ }
+
+ // These messages are not valid.
+ err = protocol.processPrivateShare(&types.DKGPrivateShare{
+ ProposerID: types.ValidatorID{Hash: common.NewRandomHash()},
+ Round: round,
+ })
+ s.Error(ErrNotDKGParticipant, err)
+ err = protocol.processPrivateShare(&types.DKGPrivateShare{
+ ProposerID: byzantineID,
+ Round: round,
+ })
+ s.Error(ErrIncorrectPrivateShareSignature, err)
+
+ // Byzantine node is sending incorrect private share.
+ err = protocol.processPrivateShare(receivers[byzantineID].prvShare[byzantineID])
+ s.NoError(err)
+ s.Require().Len(receiver.complaints, 1)
+ complaint, exist := receiver.complaints[byzantineID]
+ s.True(exist)
+ s.Equal(byzantineID, complaint.PrivateShare.ProposerID)
+}
+
+// TestQualifyIDs tests if there is a id with t+1 complaints, it should not be
+// in the qualifyIDs.
+func (s *DKGTSIGProtocolTestSuite) TestQualifyIDs() {
+ k := 3
+ n := 10
+ round := uint64(1)
+ gov, err := test.NewGovernance(5, 100)
+ s.Require().NoError(err)
+
+ receivers, _ := s.newProtocols(k, n, round)
+
+ byzantineID := s.vIDs[0]
+
+ for _, receiver := range receivers {
+ gov.AddDKGMasterPublicKey(receiver.mpk)
+ }
+
+ complaints := make([]*types.DKGComplaint, k+1)
+ for i := range complaints {
+ vID := s.vIDs[i]
+ complaints[i] = &types.DKGComplaint{
+ ProposerID: vID,
+ Round: round,
+ PrivateShare: types.DKGPrivateShare{
+ ProposerID: byzantineID,
+ Round: round,
+ },
+ }
+ }
+
+ gpk, err := newDKGGroupPublicKey(round,
+ gov.DKGMasterPublicKeys(round), complaints,
+ k, eth.SigToPub,
+ )
+ s.Require().NoError(err)
+ s.Require().Len(gpk.qualifyIDs, n-1)
+ for _, id := range gpk.qualifyIDs {
+ s.NotEqual(id, byzantineID)
+ }
+
+ gpk2, err := newDKGGroupPublicKey(round,
+ gov.DKGMasterPublicKeys(round), complaints[:k],
+ k, eth.SigToPub,
+ )
+ s.Require().NoError(err)
+ s.Require().Len(gpk2.qualifyIDs, n)
+}
+
+// TestPartialSignature tests if tsigProtocol can handle incorrect partial
+// signature and report error.
+func (s *DKGTSIGProtocolTestSuite) TestPartialSignature() {
+ k := 3
+ n := 10
+ round := uint64(1)
+ gov, err := test.NewGovernance(5, 100)
+ s.Require().NoError(err)
+
+ receivers, protocols := s.newProtocols(k, n, round)
+
+ byzantineID := s.vIDs[0]
+
+ for _, receiver := range receivers {
+ gov.AddDKGMasterPublicKey(receiver.mpk)
+ }
+
+ for _, protocol := range protocols {
+ s.Require().NoError(
+ protocol.processMasterPublicKeys(gov.DKGMasterPublicKeys(round)))
+ }
+
+ for senderID, receiver := range receivers {
+ s.Require().Len(receiver.prvShare, n)
+ if senderID == byzantineID {
+ continue
+ }
+ for vID, prvShare := range receiver.prvShare {
+ s.Require().NoError(protocols[vID].processPrivateShare(prvShare))
+ }
+ }
+
+ for _, protocol := range protocols {
+ protocol.proposeNackComplaints()
+ }
+
+ for _, recv := range receivers {
+ s.Require().Len(recv.complaints, 1)
+ complaint, exist := recv.complaints[byzantineID]
+ s.Require().True(exist)
+ gov.AddDKGComplaint(complaint)
+ }
+
+ // DKG is fininished.
+ gpk, err := newDKGGroupPublicKey(round,
+ gov.DKGMasterPublicKeys(round), gov.DKGComplaints(round),
+ k, eth.SigToPub,
+ )
+ 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 {
+ qualifyIDs[id] = struct{}{}
+ }
+
+ shareSecrets := make(
+ map[types.ValidatorID]*dkgShareSecret, len(qualifyIDs))
+
+ for vID, protocol := range protocols {
+ _, exist := qualifyIDs[s.dkgIDs[vID]]
+ if vID == byzantineID {
+ exist = !exist
+ }
+ s.Require().True(exist)
+ var err error
+ shareSecrets[vID], err = protocol.recoverShareSecret(gpk.qualifyIDs)
+ s.Require().NoError(err)
+ }
+
+ tsig := newTSigProtocol(gpk)
+ msgHash := crypto.Keccak256Hash([]byte("🏖🍹"))
+ byzantineID2 := s.vIDs[1]
+ for vID, shareSecret := range shareSecrets {
+ psig := &types.DKGPartialSignature{
+ ProposerID: vID,
+ Round: round,
+ PartialSignature: shareSecret.sign(msgHash),
+ }
+ if vID == byzantineID2 {
+ psig.PartialSignature[0]++
+ }
+ var err error
+ psig.Signature, err = s.prvKeys[vID].Sign(hashDKGPartialSignature(psig))
+ s.Require().NoError(err)
+ err = tsig.processPartialSignature(msgHash, psig)
+ if vID == byzantineID {
+ s.Require().Error(ErrNotQualifyDKGParticipant, err)
+ } else if vID == byzantineID2 {
+ s.Require().Error(ErrIncorrectPartialSignature, err)
+ } else {
+ s.Require().NoError(err)
+ }
+ }
+
+ sig, err := tsig.signature()
+ s.Require().NoError(err)
+ s.True(gpk.verifySignature(msgHash, sig))
+}
+
func TestDKGTSIGProtocol(t *testing.T) {
suite.Run(t, new(DKGTSIGProtocolTestSuite))
}
diff --git a/crypto/dkg/dkg.go b/crypto/dkg/dkg.go
index 4e21d45..df01078 100644
--- a/crypto/dkg/dkg.go
+++ b/crypto/dkg/dkg.go
@@ -304,6 +304,9 @@ func (prv *PrivateKey) Bytes() []byte {
// VerifySignature checks that the given public key created signature over hash.
func (pub PublicKey) VerifySignature(
hash common.Hash, signature crypto.Signature) bool {
+ if len(signature) == 0 {
+ return false
+ }
var sig bls.Sign
if err := sig.Deserialize(signature[:]); err != nil {
fmt.Println(err)
diff --git a/crypto/dkg/dkg_test.go b/crypto/dkg/dkg_test.go
index 8e8ce79..badb0ce 100644
--- a/crypto/dkg/dkg_test.go
+++ b/crypto/dkg/dkg_test.go
@@ -277,6 +277,19 @@ func (s *DKGTestSuite) TestDKGProtocol() {
s.True(groupPK.VerifySignature(hash, recoverSig2))
}
+func (s *DKGTestSuite) TestSignature() {
+ prvKey := NewPrivateKey()
+ pubKey := prvKey.PublicKey()
+ hash := crypto.Keccak256Hash([]byte("🛫"))
+ sig, err := prvKey.Sign(hash)
+ s.Require().NoError(err)
+ s.True(pubKey.VerifySignature(hash, sig))
+ sig[0]++
+ s.False(pubKey.VerifySignature(hash, sig))
+ sig = crypto.Signature{}
+ s.False(pubKey.VerifySignature(hash, sig))
+}
+
func TestDKG(t *testing.T) {
suite.Run(t, new(DKGTestSuite))
}