aboutsummaryrefslogtreecommitdiffstats
path: root/core/types/dkg
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2018-10-25 09:55:59 +0800
committerGitHub <noreply@github.com>2018-10-25 09:55:59 +0800
commit9839a1c6fecbada7d1736680930c3e527f984470 (patch)
tree400c69e60c132dd5101f125eda7114e4bb098b45 /core/types/dkg
parent14b91441825d6b990527e947c021a5311e951c25 (diff)
downloaddexon-consensus-9839a1c6fecbada7d1736680930c3e527f984470.tar
dexon-consensus-9839a1c6fecbada7d1736680930c3e527f984470.tar.gz
dexon-consensus-9839a1c6fecbada7d1736680930c3e527f984470.tar.bz2
dexon-consensus-9839a1c6fecbada7d1736680930c3e527f984470.tar.lz
dexon-consensus-9839a1c6fecbada7d1736680930c3e527f984470.tar.xz
dexon-consensus-9839a1c6fecbada7d1736680930c3e527f984470.tar.zst
dexon-consensus-9839a1c6fecbada7d1736680930c3e527f984470.zip
core: Move dkg in types to types/dkg. (#253)
Diffstat (limited to 'core/types/dkg')
-rw-r--r--core/types/dkg/dkg.go194
-rw-r--r--core/types/dkg/dkg_test.go248
2 files changed, 442 insertions, 0 deletions
diff --git a/core/types/dkg/dkg.go b/core/types/dkg/dkg.go
new file mode 100644
index 0000000..ee00f14
--- /dev/null
+++ b/core/types/dkg/dkg.go
@@ -0,0 +1,194 @@
+// 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 dkg
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+
+ "github.com/dexon-foundation/dexon/rlp"
+
+ "github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/dexon-foundation/dexon-consensus-core/core/crypto"
+ cryptoDKG "github.com/dexon-foundation/dexon-consensus-core/core/crypto/dkg"
+ "github.com/dexon-foundation/dexon-consensus-core/core/types"
+)
+
+// PrivateShare describe a secret share in DKG protocol.
+type PrivateShare struct {
+ ProposerID types.NodeID `json:"proposer_id"`
+ ReceiverID types.NodeID `json:"receiver_id"`
+ Round uint64 `json:"round"`
+ PrivateShare cryptoDKG.PrivateKey `json:"private_share"`
+ Signature crypto.Signature `json:"signature"`
+}
+
+// Equal checks equality between two PrivateShare instances.
+func (p *PrivateShare) Equal(other *PrivateShare) bool {
+ return p.ProposerID.Equal(other.ProposerID) &&
+ p.ReceiverID.Equal(other.ReceiverID) &&
+ p.Round == other.Round &&
+ p.Signature.Type == other.Signature.Type &&
+ bytes.Compare(p.Signature.Signature, other.Signature.Signature) == 0 &&
+ bytes.Compare(
+ p.PrivateShare.Bytes(), other.PrivateShare.Bytes()) == 0
+}
+
+// MasterPublicKey decrtibe a master public key in DKG protocol.
+type MasterPublicKey struct {
+ ProposerID types.NodeID `json:"proposer_id"`
+ Round uint64 `json:"round"`
+ DKGID cryptoDKG.ID `json:"dkg_id"`
+ PublicKeyShares cryptoDKG.PublicKeyShares `json:"public_key_shares"`
+ Signature crypto.Signature `json:"signature"`
+}
+
+func (d *MasterPublicKey) String() string {
+ return fmt.Sprintf("MasterPublicKey[%s:%d]",
+ d.ProposerID.String()[:6],
+ d.Round)
+}
+
+// Equal check equality of two DKG master public keys.
+func (d *MasterPublicKey) Equal(other *MasterPublicKey) bool {
+ return d.ProposerID.Equal(other.ProposerID) &&
+ d.Round == other.Round &&
+ d.DKGID.GetHexString() == other.DKGID.GetHexString() &&
+ d.PublicKeyShares.Equal(&other.PublicKeyShares) &&
+ d.Signature.Type == other.Signature.Type &&
+ bytes.Compare(d.Signature.Signature, other.Signature.Signature) == 0
+}
+
+type rlpMasterPublicKey struct {
+ ProposerID types.NodeID
+ Round uint64
+ DKGID []byte
+ PublicKeyShares *cryptoDKG.PublicKeyShares
+ Signature crypto.Signature
+}
+
+// EncodeRLP implements rlp.Encoder
+func (d *MasterPublicKey) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, rlpMasterPublicKey{
+ ProposerID: d.ProposerID,
+ Round: d.Round,
+ DKGID: d.DKGID.GetLittleEndian(),
+ PublicKeyShares: &d.PublicKeyShares,
+ Signature: d.Signature,
+ })
+}
+
+// DecodeRLP implements rlp.Decoder
+func (d *MasterPublicKey) DecodeRLP(s *rlp.Stream) error {
+ var dec rlpMasterPublicKey
+ if err := s.Decode(&dec); err != nil {
+ return err
+ }
+
+ id, err := cryptoDKG.BytesID(dec.DKGID)
+ if err != nil {
+ return err
+ }
+
+ *d = MasterPublicKey{
+ ProposerID: dec.ProposerID,
+ Round: dec.Round,
+ DKGID: id,
+ PublicKeyShares: *dec.PublicKeyShares,
+ Signature: dec.Signature,
+ }
+ return err
+}
+
+// NewMasterPublicKey returns a new MasterPublicKey instance.
+func NewMasterPublicKey() *MasterPublicKey {
+ return &MasterPublicKey{
+ PublicKeyShares: *cryptoDKG.NewEmptyPublicKeyShares(),
+ }
+}
+
+// UnmarshalJSON implements json.Unmarshaller.
+func (d *MasterPublicKey) UnmarshalJSON(data []byte) error {
+ type innertMasterPublicKey MasterPublicKey
+ d.PublicKeyShares = *cryptoDKG.NewEmptyPublicKeyShares()
+ return json.Unmarshal(data, (*innertMasterPublicKey)(d))
+}
+
+// Complaint describe a complaint in DKG protocol.
+type Complaint struct {
+ ProposerID types.NodeID `json:"proposer_id"`
+ Round uint64 `json:"round"`
+ PrivateShare PrivateShare `json:"private_share"`
+ Signature crypto.Signature `json:"signature"`
+}
+
+func (c *Complaint) String() string {
+ if c.IsNack() {
+ return fmt.Sprintf("DKGNackComplaint[%s:%d]%s",
+ c.ProposerID.String()[:6], c.Round,
+ c.PrivateShare.ProposerID.String()[:6])
+ }
+ return fmt.Sprintf("Complaint[%s:%d]%v",
+ c.ProposerID.String()[:6], c.Round, c.PrivateShare)
+}
+
+// Equal checks equality between two Complaint instances.
+func (c *Complaint) Equal(other *Complaint) bool {
+ return c.ProposerID.Equal(other.ProposerID) &&
+ c.Round == other.Round &&
+ c.PrivateShare.Equal(&other.PrivateShare) &&
+ c.Signature.Type == other.Signature.Type &&
+ bytes.Compare(c.Signature.Signature, other.Signature.Signature) == 0
+}
+
+// PartialSignature describe a partial signature in DKG protocol.
+type PartialSignature struct {
+ ProposerID types.NodeID `json:"proposer_id"`
+ Round uint64 `json:"round"`
+ Hash common.Hash `json:"hash"`
+ PartialSignature cryptoDKG.PartialSignature `json:"partial_signature"`
+ Signature crypto.Signature `json:"signature"`
+}
+
+// Finalize describe a dig finalize message in DKG protocol.
+type Finalize struct {
+ ProposerID types.NodeID `json:"proposer_id"`
+ Round uint64 `json:"round"`
+ Signature crypto.Signature `json:"signature"`
+}
+
+func (final *Finalize) String() string {
+ return fmt.Sprintf("DKGFinal[%s:%d]",
+ final.ProposerID.String()[:6],
+ final.Round)
+}
+
+// Equal check equality of two Finalize instances.
+func (final *Finalize) Equal(other *Finalize) bool {
+ return final.ProposerID.Equal(other.ProposerID) &&
+ final.Round == other.Round &&
+ final.Signature.Type == other.Signature.Type &&
+ bytes.Compare(final.Signature.Signature, other.Signature.Signature) == 0
+}
+
+// IsNack returns true if it's a nack complaint in DKG protocol.
+func (c *Complaint) IsNack() bool {
+ return len(c.PrivateShare.Signature.Signature) == 0
+}
diff --git a/core/types/dkg/dkg_test.go b/core/types/dkg/dkg_test.go
new file mode 100644
index 0000000..0186c50
--- /dev/null
+++ b/core/types/dkg/dkg_test.go
@@ -0,0 +1,248 @@
+// 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 dkg
+
+import (
+ "math/rand"
+ "reflect"
+ "testing"
+
+ "github.com/stretchr/testify/suite"
+
+ "github.com/dexon-foundation/dexon-consensus-core/common"
+ "github.com/dexon-foundation/dexon-consensus-core/core/crypto"
+ cryptoDKG "github.com/dexon-foundation/dexon-consensus-core/core/crypto/dkg"
+ "github.com/dexon-foundation/dexon-consensus-core/core/types"
+ "github.com/dexon-foundation/dexon/rlp"
+)
+
+type DKGTestSuite struct {
+ suite.Suite
+}
+
+func (s *DKGTestSuite) genRandomBytes() []byte {
+ randomness := make([]byte, 32)
+ _, err := rand.Read(randomness)
+ s.Require().NoError(err)
+ return randomness
+}
+
+func (s *DKGTestSuite) genID() cryptoDKG.ID {
+ dID, err := cryptoDKG.BytesID(s.genRandomBytes())
+ s.Require().NoError(err)
+ return dID
+}
+
+func (s *DKGTestSuite) clone(src, dst interface{}) {
+ b, err := rlp.EncodeToBytes(src)
+ s.Require().NoError(err)
+ s.Require().NoError(rlp.DecodeBytes(b, dst))
+}
+
+func (s *DKGTestSuite) TestRLPEncodeDecode() {
+ dID := s.genID()
+ // Prepare master public key for testing.
+ d := MasterPublicKey{
+ ProposerID: types.NodeID{Hash: common.Hash{1, 2, 3}},
+ Round: 10,
+ DKGID: dID,
+ Signature: crypto.Signature{
+ Type: "123",
+ Signature: []byte{4, 5, 6},
+ },
+ }
+
+ b, err := rlp.EncodeToBytes(&d)
+ s.Require().NoError(err)
+
+ var dd MasterPublicKey
+ err = rlp.DecodeBytes(b, &dd)
+ s.Require().NoError(err)
+
+ bb, err := rlp.EncodeToBytes(&dd)
+ s.Require().NoError(err)
+ s.Require().True(reflect.DeepEqual(b, bb))
+ s.Require().True(d.ProposerID.Equal(dd.ProposerID))
+ s.Require().True(d.Round == dd.Round)
+ s.Require().True(reflect.DeepEqual(d.Signature, dd.Signature))
+ s.Require().Equal(d.DKGID.GetHexString(), dd.DKGID.GetHexString())
+}
+
+func (s *DKGTestSuite) TestMasterPublicKeyEquality() {
+ var req = s.Require()
+ // Prepare source master public key.
+ master1 := &MasterPublicKey{
+ ProposerID: types.NodeID{Hash: common.NewRandomHash()},
+ Round: 1234,
+ DKGID: s.genID(),
+ Signature: crypto.Signature{
+ Signature: s.genRandomBytes(),
+ },
+ }
+ prvKey := cryptoDKG.NewPrivateKey()
+ pubKey := prvKey.PublicKey().(cryptoDKG.PublicKey)
+ _, pubShares := cryptoDKG.NewPrivateKeyShares(2)
+ req.NoError(pubShares.AddShare(s.genID(), &pubKey))
+ master1.PublicKeyShares = *pubShares
+ // Prepare another master public key by copying every field.
+ master2 := &MasterPublicKey{}
+ s.clone(master1, master2)
+ // They should be equal.
+ req.True(master1.Equal(master2))
+ // Change round.
+ master2.Round = 2345
+ req.False(master1.Equal(master2))
+ master2.Round = 1234
+ // Change proposerID.
+ master2.ProposerID = types.NodeID{Hash: common.NewRandomHash()}
+ req.False(master1.Equal(master2))
+ master2.ProposerID = master1.ProposerID
+ // Change DKGID.
+ master2.DKGID = cryptoDKG.NewID(s.genRandomBytes())
+ req.False(master1.Equal(master2))
+ master2.DKGID = master1.DKGID
+ // Change signature.
+ master2.Signature = crypto.Signature{
+ Signature: s.genRandomBytes(),
+ }
+ req.False(master1.Equal(master2))
+ master2.Signature = master1.Signature
+ // Change public key share.
+ master2.PublicKeyShares = *cryptoDKG.NewEmptyPublicKeyShares()
+ req.False(master1.Equal(master2))
+}
+
+func (s *DKGTestSuite) TestPrivateShareEquality() {
+ var req = s.Require()
+ share1 := &PrivateShare{
+ ProposerID: types.NodeID{Hash: common.NewRandomHash()},
+ ReceiverID: types.NodeID{Hash: common.NewRandomHash()},
+ Round: 1,
+ PrivateShare: *cryptoDKG.NewPrivateKey(),
+ Signature: crypto.Signature{
+ Signature: s.genRandomBytes(),
+ },
+ }
+ // Make a copy.
+ share2 := &PrivateShare{}
+ s.clone(share1, share2)
+ req.True(share1.Equal(share2))
+ // Change proposer ID.
+ share2.ProposerID = types.NodeID{Hash: common.NewRandomHash()}
+ req.False(share1.Equal(share2))
+ share2.ProposerID = share1.ProposerID
+ // Change receiver ID.
+ share2.ReceiverID = types.NodeID{Hash: common.NewRandomHash()}
+ req.False(share1.Equal(share2))
+ share2.ReceiverID = share1.ReceiverID
+ // Change round.
+ share2.Round = share1.Round + 1
+ req.False(share1.Equal(share2))
+ share2.Round = share1.Round
+ // Change signature.
+ share2.Signature = crypto.Signature{
+ Signature: s.genRandomBytes(),
+ }
+ req.False(share1.Equal(share2))
+ share2.Signature = share1.Signature
+ // Change private share.
+ share2.PrivateShare = *cryptoDKG.NewPrivateKey()
+ req.False(share1.Equal(share2))
+ share2.PrivateShare = share1.PrivateShare
+ // They should be equal after chaning fields back.
+ req.True(share1.Equal(share2))
+}
+
+func (s *DKGTestSuite) TestComplaintEquality() {
+ var req = s.Require()
+ comp1 := &Complaint{
+ ProposerID: types.NodeID{Hash: common.NewRandomHash()},
+ Round: 1,
+ PrivateShare: PrivateShare{
+ ProposerID: types.NodeID{Hash: common.NewRandomHash()},
+ ReceiverID: types.NodeID{Hash: common.NewRandomHash()},
+ Round: 2,
+ PrivateShare: *cryptoDKG.NewPrivateKey(),
+ Signature: crypto.Signature{
+ Signature: s.genRandomBytes(),
+ },
+ },
+ Signature: crypto.Signature{
+ Signature: s.genRandomBytes(),
+ },
+ }
+ // Make a copy.
+ comp2 := &Complaint{}
+ s.clone(comp1, comp2)
+ req.True(comp1.Equal(comp2))
+ // Change proposer ID.
+ comp2.ProposerID = types.NodeID{Hash: common.NewRandomHash()}
+ req.False(comp1.Equal(comp2))
+ comp2.ProposerID = comp1.ProposerID
+ // Change round.
+ comp2.Round = comp1.Round + 1
+ req.False(comp1.Equal(comp2))
+ comp2.Round = comp1.Round
+ // Change signature.
+ comp2.Signature = crypto.Signature{
+ Signature: s.genRandomBytes(),
+ }
+ req.False(comp1.Equal(comp2))
+ comp2.Signature = comp1.Signature
+ // Change share's round.
+ comp2.PrivateShare.Round = comp1.PrivateShare.Round + 1
+ req.False(comp1.Equal(comp2))
+ comp2.PrivateShare.Round = comp1.PrivateShare.Round
+ // After changing every field back, should be equal.
+ req.True(comp1.Equal(comp2))
+}
+
+func (s *DKGTestSuite) TestFinalizeEquality() {
+ var req = s.Require()
+ final1 := &Finalize{
+ ProposerID: types.NodeID{Hash: common.NewRandomHash()},
+ Round: 1,
+ Signature: crypto.Signature{
+ Signature: s.genRandomBytes(),
+ },
+ }
+ // Make a copy
+ final2 := &Finalize{}
+ s.clone(final1, final2)
+ req.True(final1.Equal(final2))
+ // Change proposer ID.
+ final2.ProposerID = types.NodeID{Hash: common.NewRandomHash()}
+ req.False(final1.Equal(final2))
+ final2.ProposerID = final1.ProposerID
+ // Change round.
+ final2.Round = final1.Round + 1
+ req.False(final1.Equal(final2))
+ final2.Round = final1.Round
+ // Change signature.
+ final2.Signature = crypto.Signature{
+ Signature: s.genRandomBytes(),
+ }
+ req.False(final1.Equal(final2))
+ final2.Signature = final1.Signature
+ // After changing every field back, they should be equal.
+ req.True(final1.Equal(final2))
+}
+
+func TestDKG(t *testing.T) {
+ suite.Run(t, new(DKGTestSuite))
+}