diff options
author | Mission Liao <mission.liao@dexon.org> | 2018-09-26 16:55:15 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-26 16:55:15 +0800 |
commit | 663817d3e0d5a3c28cb0c5e378a533e242af5fdf (patch) | |
tree | 8d1952cc04a5735ce7cd060445667160bb21fc60 /crypto | |
parent | e8468d7206dbee2a8dfb34bfccc29d0d7273a777 (diff) | |
download | dexon-consensus-663817d3e0d5a3c28cb0c5e378a533e242af5fdf.tar dexon-consensus-663817d3e0d5a3c28cb0c5e378a533e242af5fdf.tar.gz dexon-consensus-663817d3e0d5a3c28cb0c5e378a533e242af5fdf.tar.bz2 dexon-consensus-663817d3e0d5a3c28cb0c5e378a533e242af5fdf.tar.lz dexon-consensus-663817d3e0d5a3c28cb0c5e378a533e242af5fdf.tar.xz dexon-consensus-663817d3e0d5a3c28cb0c5e378a533e242af5fdf.tar.zst dexon-consensus-663817d3e0d5a3c28cb0c5e378a533e242af5fdf.zip |
core: move crypto to core/crypto (#140)
- Move key-holder to authenticator
Make core.keyHolder public as core.Authenticator, it
is not required to make this part an interface.
- Make private when there is no need to go public.
- Fix data race
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/dkg/constant.go | 26 | ||||
-rw-r--r-- | crypto/dkg/dkg.go | 381 | ||||
-rw-r--r-- | crypto/dkg/dkg_test.go | 461 | ||||
-rw-r--r-- | crypto/dkg/utils.go | 69 | ||||
-rw-r--r-- | crypto/eth/eth.go | 120 | ||||
-rw-r--r-- | crypto/eth/eth_test.go | 93 | ||||
-rw-r--r-- | crypto/interfaces.go | 45 | ||||
-rw-r--r-- | crypto/utils.go | 41 | ||||
-rw-r--r-- | crypto/utils_test.go | 52 |
9 files changed, 0 insertions, 1288 deletions
diff --git a/crypto/dkg/constant.go b/crypto/dkg/constant.go deleted file mode 100644 index 119613b..0000000 --- a/crypto/dkg/constant.go +++ /dev/null @@ -1,26 +0,0 @@ -// 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 ( - "github.com/Spiderpowa/bls/ffi/go/bls" -) - -const ( - curve = bls.CurveFp382_2 -) diff --git a/crypto/dkg/dkg.go b/crypto/dkg/dkg.go deleted file mode 100644 index f2a2f3a..0000000 --- a/crypto/dkg/dkg.go +++ /dev/null @@ -1,381 +0,0 @@ -// 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 ( - "encoding/json" - "fmt" - - "github.com/Spiderpowa/bls/ffi/go/bls" - - "github.com/dexon-foundation/dexon-consensus-core/common" - "github.com/dexon-foundation/dexon-consensus-core/crypto" -) - -var ( - // ErrDuplicatedShare is reported when adding an private key share of same id. - ErrDuplicatedShare = fmt.Errorf("invalid share") - // ErrNoIDToRecover is reported when no id is provided for recovering private - // key. - ErrNoIDToRecover = fmt.Errorf("no id to recover private key") - // ErrShareNotFound is reported when the private key share of id is not found - // when recovering private key. - ErrShareNotFound = fmt.Errorf("share not found") -) - -var publicKeyLength int - -func init() { - bls.Init(curve) - - pubKey := &bls.PublicKey{} - publicKeyLength = len(pubKey.Serialize()) -} - -// PrivateKey represents a private key structure implments -// Crypto.PrivateKey interface. -type PrivateKey struct { - privateKey bls.SecretKey - publicKey PublicKey -} - -// MarshalJSON implements json.Marshaller. -func (prv *PrivateKey) MarshalJSON() ([]byte, error) { - return json.Marshal(&prv.privateKey) -} - -// UnmarshalJSON implements json.Unmarshaller. -func (prv *PrivateKey) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &prv.privateKey) -} - -// ID is the id for DKG protocol. -type ID = bls.ID - -// IDs is an array of ID. -type IDs []ID - -// PublicKey represents a public key structure implements -// Crypto.PublicKey interface. -type PublicKey struct { - publicKey bls.PublicKey -} - -// PrivateKeyShares represents a private key shares for DKG protocol. -type PrivateKeyShares struct { - shares []PrivateKey - shareIndex map[ID]int - masterPrivateKey []bls.SecretKey -} - -// PublicKeyShares represents a public key shares for DKG protocol. -type PublicKeyShares struct { - shares []PublicKey - shareIndex map[ID]int - masterPublicKey []bls.PublicKey -} - -// MarshalJSON implements json.Marshaller. -func (pubs *PublicKeyShares) MarshalJSON() ([]byte, error) { - type Alias PublicKeyShares - data := &struct { - MasterPublicKeys []*bls.PublicKey `json:"master_public_keys"` - }{ - make([]*bls.PublicKey, len(pubs.masterPublicKey)), - } - for i := range pubs.masterPublicKey { - data.MasterPublicKeys[i] = &pubs.masterPublicKey[i] - } - return json.Marshal(data) -} - -// UnmarshalJSON implements json.Unmarshaller. -func (pubs *PublicKeyShares) UnmarshalJSON(data []byte) error { - type Alias PublicKeyShares - aux := &struct { - MasterPublicKeys []*bls.PublicKey `json:"master_public_keys"` - }{} - if err := json.Unmarshal(data, &aux); err != nil { - return err - } - mpk := make([]bls.PublicKey, len(aux.MasterPublicKeys)) - for i, pk := range aux.MasterPublicKeys { - mpk[i] = *pk - } - pubs.masterPublicKey = mpk - return nil -} - -// NewID creates a ew ID structure. -func NewID(id []byte) ID { - var blsID bls.ID - blsID.SetLittleEndian(id) - return blsID -} - -// NewPrivateKey creates a new PrivateKey structure. -func NewPrivateKey() *PrivateKey { - var key bls.SecretKey - key.SetByCSPRNG() - return &PrivateKey{ - privateKey: key, - publicKey: *newPublicKey(&key), - } -} - -// NewPrivateKeyShares creates a DKG private key shares of threshold t. -func NewPrivateKeyShares(t int) (*PrivateKeyShares, *PublicKeyShares) { - var prv bls.SecretKey - prv.SetByCSPRNG() - msk := prv.GetMasterSecretKey(t) - mpk := bls.GetMasterPublicKey(msk) - return &PrivateKeyShares{ - masterPrivateKey: msk, - shareIndex: make(map[ID]int), - }, &PublicKeyShares{ - shareIndex: make(map[ID]int), - masterPublicKey: mpk, - } -} - -// NewEmptyPrivateKeyShares creates an empty private key shares. -func NewEmptyPrivateKeyShares() *PrivateKeyShares { - return &PrivateKeyShares{ - shareIndex: make(map[ID]int), - } -} - -// SetParticipants sets the DKG participants. -func (prvs *PrivateKeyShares) SetParticipants(IDs IDs) { - prvs.shares = make([]PrivateKey, len(IDs)) - prvs.shareIndex = make(map[ID]int, len(IDs)) - for idx, ID := range IDs { - prvs.shares[idx].privateKey.Set(prvs.masterPrivateKey, &ID) - prvs.shareIndex[ID] = idx - } -} - -// AddShare adds a share. -func (prvs *PrivateKeyShares) AddShare(ID ID, share *PrivateKey) error { - if idx, exist := prvs.shareIndex[ID]; exist { - if !share.privateKey.IsEqual(&prvs.shares[idx].privateKey) { - return ErrDuplicatedShare - } - return nil - } - prvs.shareIndex[ID] = len(prvs.shares) - prvs.shares = append(prvs.shares, *share) - return nil -} - -// RecoverPrivateKey recovers private key from the shares. -func (prvs *PrivateKeyShares) RecoverPrivateKey(qualifyIDs IDs) ( - *PrivateKey, error) { - var prv PrivateKey - if len(qualifyIDs) == 0 { - return nil, ErrNoIDToRecover - } - for i, ID := range qualifyIDs { - idx, exist := prvs.shareIndex[ID] - if !exist { - return nil, ErrShareNotFound - } - if i == 0 { - prv.privateKey = prvs.shares[idx].privateKey - continue - } - prv.privateKey.Add(&prvs.shares[idx].privateKey) - } - return &prv, nil -} - -// RecoverPublicKey recovers public key from the shares. -func (prvs *PrivateKeyShares) RecoverPublicKey(qualifyIDs IDs) ( - *PublicKey, error) { - var pub PublicKey - if len(qualifyIDs) == 0 { - return nil, ErrNoIDToRecover - } - for i, ID := range qualifyIDs { - idx, exist := prvs.shareIndex[ID] - if !exist { - return nil, ErrShareNotFound - } - if i == 0 { - pub.publicKey = *prvs.shares[idx].privateKey.GetPublicKey() - continue - } - pub.publicKey.Add(prvs.shares[idx].privateKey.GetPublicKey()) - } - return &pub, nil -} - -// Share returns the share for the ID. -func (prvs *PrivateKeyShares) Share(ID ID) (*PrivateKey, bool) { - idx, exist := prvs.shareIndex[ID] - if !exist { - return nil, false - } - return &prvs.shares[idx], true -} - -// NewEmptyPublicKeyShares creates an empty public key shares. -func NewEmptyPublicKeyShares() *PublicKeyShares { - return &PublicKeyShares{ - shareIndex: make(map[ID]int), - } -} - -// Share returns the share for the ID. -func (pubs *PublicKeyShares) Share(ID ID) (*PublicKey, error) { - idx, exist := pubs.shareIndex[ID] - if exist { - return &pubs.shares[idx], nil - } - var pk PublicKey - if err := pk.publicKey.Set(pubs.masterPublicKey, &ID); err != nil { - return nil, err - } - pubs.AddShare(ID, &pk) - return &pk, nil -} - -// AddShare adds a share. -func (pubs *PublicKeyShares) AddShare(ID ID, share *PublicKey) error { - if idx, exist := pubs.shareIndex[ID]; exist { - if !share.publicKey.IsEqual(&pubs.shares[idx].publicKey) { - return ErrDuplicatedShare - } - return nil - } - pubs.shareIndex[ID] = len(pubs.shares) - pubs.shares = append(pubs.shares, *share) - return nil -} - -// VerifyPrvShare verifies if the private key shares is valid. -func (pubs *PublicKeyShares) VerifyPrvShare(ID ID, share *PrivateKey) ( - bool, error) { - var pk bls.PublicKey - if err := pk.Set(pubs.masterPublicKey, &ID); err != nil { - return false, err - } - return pk.IsEqual(share.privateKey.GetPublicKey()), nil -} - -// VerifyPubShare verifies if the public key shares is valid. -func (pubs *PublicKeyShares) VerifyPubShare(ID ID, share *PublicKey) ( - bool, error) { - var pk bls.PublicKey - if err := pk.Set(pubs.masterPublicKey, &ID); err != nil { - return false, err - } - return pk.IsEqual(&share.publicKey), nil -} - -// RecoverPublicKey recovers private key from the shares. -func (pubs *PublicKeyShares) RecoverPublicKey(qualifyIDs IDs) ( - *PublicKey, error) { - var pub PublicKey - if len(qualifyIDs) == 0 { - return nil, ErrNoIDToRecover - } - for i, ID := range qualifyIDs { - idx, exist := pubs.shareIndex[ID] - if !exist { - return nil, ErrShareNotFound - } - if i == 0 { - pub.publicKey = pubs.shares[idx].publicKey - continue - } - pub.publicKey.Add(&pubs.shares[idx].publicKey) - } - return &pub, nil -} - -// MasterKeyBytes returns []byte representation of master public key. -func (pubs *PublicKeyShares) MasterKeyBytes() []byte { - bytes := make([]byte, 0, len(pubs.masterPublicKey)*publicKeyLength) - for _, pk := range pubs.masterPublicKey { - bytes = append(bytes, pk.Serialize()...) - } - return bytes -} - -// newPublicKey creates a new PublicKey structure. -func newPublicKey(prvKey *bls.SecretKey) *PublicKey { - return &PublicKey{ - publicKey: *prvKey.GetPublicKey(), - } -} - -// PublicKey returns the public key associate this private key. -func (prv *PrivateKey) PublicKey() crypto.PublicKey { - return prv.publicKey -} - -// Sign calculates a signature. -func (prv *PrivateKey) Sign(hash common.Hash) (crypto.Signature, error) { - msg := string(hash[:]) - sign := prv.privateKey.Sign(msg) - return crypto.Signature(sign.Serialize()), nil -} - -// Bytes returns []byte representation of private key. -func (prv *PrivateKey) Bytes() []byte { - return prv.privateKey.GetLittleEndian() -} - -// SetBytes sets the private key data to []byte. -func (prv *PrivateKey) SetBytes(bytes []byte) error { - var key bls.SecretKey - if err := key.SetLittleEndian(bytes); err != nil { - return err - } - prv.privateKey = key - prv.publicKey = *newPublicKey(&prv.privateKey) - return nil -} - -// String returns string representation of privat key. -func (prv *PrivateKey) String() string { - return prv.privateKey.GetHexString() -} - -// 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) - return false - } - msg := string(hash[:]) - return sig.Verify(&pub.publicKey, msg) -} - -// Bytes returns []byte representation of public key. -func (pub PublicKey) Bytes() []byte { - var bytes []byte - pub.publicKey.Deserialize(bytes) - return bytes -} diff --git a/crypto/dkg/dkg_test.go b/crypto/dkg/dkg_test.go deleted file mode 100644 index badb0ce..0000000 --- a/crypto/dkg/dkg_test.go +++ /dev/null @@ -1,461 +0,0 @@ -// 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 ( - "encoding/binary" - "math/rand" - "sort" - "sync" - "testing" - - "github.com/stretchr/testify/suite" - - "github.com/dexon-foundation/dexon-consensus-core/common" - "github.com/dexon-foundation/dexon-consensus-core/crypto" -) - -type DKGTestSuite struct { - suite.Suite -} - -type member struct { - id ID - prvShares *PrivateKeyShares - pubShares *PublicKeyShares - receivedPrvShares *PrivateKeyShares - receivedPubShares map[ID]*PublicKeyShares -} - -func (s *DKGTestSuite) genID(k int) IDs { - IDs := make(IDs, 0, k) - for i := 0; i < k; i++ { - id := make([]byte, 8) - binary.LittleEndian.PutUint64(id, rand.Uint64()) - IDs = append(IDs, NewID(id)) - } - return IDs -} - -func (s *DKGTestSuite) sendKey(senders []member, receivers []member) { - receiveFrom := make(map[ID][]member) - for _, sender := range senders { - for _, receiver := range receivers { - // Here's the demonstration of DKG protocol. `pubShares` is broadcasted - // and all the receiver would save it to the `receivedPubShares`. - // Do not optimize the memory usage of this part. - receiver.receivedPubShares[sender.id] = sender.pubShares - prvShare, ok := sender.prvShares.Share(receiver.id) - s.Require().True(ok) - pubShare, err := sender.pubShares.Share(receiver.id) - s.Require().NoError(err) - valid, err := receiver.receivedPubShares[sender.id]. - VerifyPrvShare(receiver.id, prvShare) - s.Require().NoError(err) - s.Require().True(valid) - valid, err = receiver.receivedPubShares[sender.id]. - VerifyPubShare(receiver.id, pubShare) - s.Require().NoError(err) - s.Require().True(valid) - receiveFrom[receiver.id] = append(receiveFrom[receiver.id], sender) - } - } - // The received order do not need to be the same. - for _, receiver := range receivers { - rand.Shuffle(len(senders), func(i, j int) { - receiveFrom[receiver.id][i], receiveFrom[receiver.id][j] = - receiveFrom[receiver.id][j], receiveFrom[receiver.id][i] - }) - for _, sender := range receiveFrom[receiver.id] { - prvShare, ok := sender.prvShares.Share(receiver.id) - s.Require().True(ok) - err := receiver.receivedPrvShares.AddShare(sender.id, prvShare) - s.Require().NoError(err) - } - } -} - -func (s *DKGTestSuite) signWithQualifyIDs( - member member, qualifyIDs IDs, hash common.Hash) PartialSignature { - prvKey, err := member.receivedPrvShares.RecoverPrivateKey(qualifyIDs) - s.Require().NoError(err) - sig, err := prvKey.Sign(hash) - s.Require().NoError(err) - return PartialSignature(sig) -} - -func (s *DKGTestSuite) verifySigWithQualifyIDs( - members []member, qualifyIDs IDs, - signer ID, hash common.Hash, sig PartialSignature) bool { - membersIdx := make(map[ID]int) - for idx, member := range members { - membersIdx[member.id] = idx - } - pubShares := NewEmptyPublicKeyShares() - for _, id := range qualifyIDs { - idx, exist := membersIdx[id] - s.Require().True(exist) - member := members[idx] - pubShare, err := member.pubShares.Share(signer) - s.Require().NoError(err) - err = pubShares.AddShare(id, pubShare) - s.Require().NoError(err) - } - pubKey, err := pubShares.RecoverPublicKey(qualifyIDs) - s.Require().NoError(err) - return pubKey.VerifySignature(hash, crypto.Signature(sig)) -} - -func (s *DKGTestSuite) TestVerifyKeyShares() { - invalidID := NewID([]byte{0}) - ids := []ID{NewID([]byte{1}), NewID([]byte{2}), NewID([]byte{3})} - members := []member{} - for _, id := range ids { - members = append(members, member{ - id: id, - receivedPubShares: make(map[ID]*PublicKeyShares), - }) - } - - prvShares, pubShares := NewPrivateKeyShares(2) - prvShares.SetParticipants(ids) - - _, ok := prvShares.Share(invalidID) - s.False(ok) - for _, id := range ids { - prvShare, ok := prvShares.Share(id) - s.Require().True(ok) - valid, err := pubShares.VerifyPrvShare(id, prvShare) - s.Require().NoError(err) - s.True(valid) - pubShare, err := pubShares.Share(id) - s.Require().NoError(err) - valid, err = pubShares.VerifyPubShare(id, pubShare) - s.Require().NoError(err) - s.True(valid) - } - - // Test of faulty private/public key. - invalidPrvShare := NewPrivateKey() - valid, err := pubShares.VerifyPrvShare(ids[0], invalidPrvShare) - s.Require().NoError(err) - s.False(valid) - - invalidPubShare, ok := invalidPrvShare.PublicKey().(PublicKey) - s.Require().True(ok) - valid, err = pubShares.VerifyPubShare(ids[0], &invalidPubShare) - s.Require().NoError(err) - s.False(valid) - - // Test of faulty signature. - for idx := range members { - members[idx].prvShares, members[idx].pubShares = NewPrivateKeyShares(2) - members[idx].prvShares.SetParticipants(ids) - members[idx].receivedPrvShares = NewEmptyPrivateKeyShares() - } - s.sendKey(members, members) - hash := crypto.Keccak256Hash([]byte("πΎπΎπΎπΎπΎπΎ")) - sig, err := invalidPrvShare.Sign(hash) - s.Require().NoError(err) - psig := PartialSignature(sig) - for _, member := range members { - valid = s.verifySigWithQualifyIDs(members, ids, member.id, hash, psig) - s.False(valid) - } - - // Test of faulty group signature. - groupPubShares := make([]*PublicKeyShares, 0, len(members)) - sigs := make([]PartialSignature, 0, len(members)) - for _, member := range members { - sigs = append(sigs, s.signWithQualifyIDs(member, ids, hash)) - groupPubShares = append(groupPubShares, member.pubShares) - } - sigs[0] = psig - recoverSig, err := RecoverSignature(sigs, ids) - s.Require().NoError(err) - - pubKey := RecoverGroupPublicKey(groupPubShares) - s.False(pubKey.VerifySignature(hash, recoverSig)) -} - -func (s *DKGTestSuite) TestDKGProtocol() { - k := 5 - members := []member{} - ids := s.genID((k + 1) * 2) - for _, id := range ids { - members = append(members, member{ - id: id, - receivedPubShares: make(map[ID]*PublicKeyShares), - }) - } - - for idx := range members { - members[idx].prvShares, members[idx].pubShares = NewPrivateKeyShares(k) - members[idx].prvShares.SetParticipants(ids) - members[idx].receivedPrvShares = NewEmptyPrivateKeyShares() - } - // Randomly select non-disqualified members. - nums := make([]int, len(members)) - for i := range nums { - nums[i] = i - } - rand.Shuffle(len(nums), func(i, j int) { - nums[i], nums[j] = nums[j], nums[i] - }) - nums = nums[:rand.Intn(len(members))] - sort.Ints(nums) - qualify := make([]member, 0, len(nums)) - for _, idx := range nums { - qualify = append(qualify, members[idx]) - } - // TODO(jimmy-dexon): Remove below line after finishing test of random select. - qualify = members - // Members are partitioned into two groups. - grp1, grp2 := members[:k+1], members[k+1:] - collectIDs := func(members []member) IDs { - IDs := make(IDs, 0, len(members)) - for _, member := range members { - IDs = append(IDs, member.id) - } - return IDs - } - signMsg := func( - members []member, qualify []member, hash common.Hash) []PartialSignature { - ids := collectIDs(qualify) - sigs := make([]PartialSignature, 0, len(members)) - for _, member := range members { - sig := s.signWithQualifyIDs(member, ids, hash) - sigs = append(sigs, sig) - } - return sigs - } - verifySig := func( - members []member, - signer []ID, sig []PartialSignature, qualify []member, hash common.Hash) bool { - ids := collectIDs(qualify) - for i := range sig { - if !s.verifySigWithQualifyIDs(members, ids, signer[i], hash, sig[i]) { - return false - } - } - return true - } - s.sendKey(qualify, grp1) - s.sendKey(qualify, grp2) - hash := crypto.Keccak256Hash([]byte("π«")) - sig1 := signMsg(grp1, qualify, hash) - sig2 := signMsg(grp2, qualify, hash) - s.True(verifySig(members, collectIDs(grp1), sig1, qualify, hash)) - s.True(verifySig(members, collectIDs(grp2), sig2, qualify, hash)) - recoverSig1, err := RecoverSignature(sig1, collectIDs(grp1)) - s.Require().NoError(err) - recoverSig2, err := RecoverSignature(sig2, collectIDs(grp2)) - s.Require().NoError(err) - s.Equal(recoverSig1, recoverSig2) - - pubShares := make([]*PublicKeyShares, 0, len(members)) - for _, member := range members { - pubShares = append(pubShares, member.pubShares) - } - groupPK := RecoverGroupPublicKey(pubShares) - s.True(groupPK.VerifySignature(hash, recoverSig1)) - 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)) -} - -func BenchmarkDKGProtocol(b *testing.B) { - t := 33 - n := 100 - s := new(DKGTestSuite) - - self := member{} - members := make([]*member, n-1) - ids := make(IDs, n) - - b.Run("DKG", func(b *testing.B) { - for i := 0; i < b.N; i++ { - b.StopTimer() - self.id = s.genID(1)[0] - self.receivedPubShares = make(map[ID]*PublicKeyShares, n) - for idx, id := range s.genID(n - 1) { - ids[idx] = id - } - for idx := range members { - members[idx] = &member{ - id: ids[idx], - receivedPubShares: make(map[ID]*PublicKeyShares), - receivedPrvShares: NewEmptyPrivateKeyShares(), - } - } - ids[n-1] = self.id - prvShares := make(map[ID]*PrivateKey, n) - for idx := range members { - members[idx].prvShares, members[idx].pubShares = NewPrivateKeyShares(t) - members[idx].prvShares.SetParticipants(ids) - prvShare, ok := members[idx].prvShares.Share(self.id) - if !ok { - b.FailNow() - } - prvShares[members[idx].id] = prvShare - } - - b.StartTimer() - self.prvShares, self.pubShares = NewPrivateKeyShares(t) - self.prvShares.SetParticipants(ids) - self.receivedPrvShares = NewEmptyPrivateKeyShares() - for _, member := range members { - self.receivedPubShares[member.id] = member.pubShares - } - self.receivedPubShares[self.id] = self.pubShares - prvShare, ok := self.prvShares.Share(self.id) - if !ok { - b.FailNow() - } - prvShares[self.id] = prvShare - for id, prvShare := range prvShares { - ok, err := self.receivedPubShares[id].VerifyPrvShare(self.id, prvShare) - if err != nil { - b.Fatalf("%v", err) - } - if !ok { - b.FailNow() - } - if err := self.receivedPrvShares.AddShare(id, prvShare); err != nil { - b.Fatalf("%v", err) - } - } - if _, err := self.receivedPrvShares.RecoverPrivateKey(ids); err != nil { - b.Fatalf("%v", err) - } - } - }) - - hash := crypto.Keccak256Hash([]byte("π")) - b.Run("Share-Sign", func(b *testing.B) { - for i := 0; i < b.N; i++ { - b.StopTimer() - prvKey, err := self.receivedPrvShares.RecoverPrivateKey(ids) - if err != nil { - b.Fatalf("%v", err) - } - b.StartTimer() - if _, err := prvKey.Sign(hash); err != nil { - b.Fatalf("%v", err) - } - } - }) - - sendKey := func(sender *member, receiver *member, b *testing.B) { - receiver.receivedPubShares[sender.id] = sender.pubShares - prvShare, ok := sender.prvShares.Share(receiver.id) - if !ok { - b.FailNow() - } - ok, err := receiver.receivedPubShares[sender.id].VerifyPrvShare( - receiver.id, prvShare) - if err != nil { - b.Fatalf("%v", err) - } - if !ok { - b.FailNow() - } - if err := receiver.receivedPrvShares.AddShare(sender.id, prvShare); err != nil { - b.Fatalf("%v", err) - } - } - - members = append(members, &self) - - for _, sender := range members { - wg := sync.WaitGroup{} - for _, receiver := range members { - if sender == receiver { - continue - } - wg.Add(1) - go func(receiver *member) { - sendKey(sender, receiver, b) - wg.Done() - }(receiver) - } - wg.Wait() - } - wg := sync.WaitGroup{} - for _, m := range members { - wg.Add(1) - go func(member *member) { - sendKey(member, member, b) - wg.Done() - }(m) - } - wg.Wait() - - sign := func(member *member) PartialSignature { - prvKey, err := member.receivedPrvShares.RecoverPrivateKey(ids) - if err != nil { - b.Fatalf("%v", err) - } - sig, err := prvKey.Sign(hash) - if err != nil { - b.Fatalf("%v", err) - } - return PartialSignature(sig) - } - - b.Run("Combine-Sign", func(b *testing.B) { - b.StopTimer() - sigs := make([]PartialSignature, n) - for idx, member := range members { - sigs[idx] = sign(member) - } - b.StartTimer() - for i := 0; i < b.N; i++ { - if _, err := RecoverSignature(sigs, ids); err != nil { - b.Fatalf("%v", err) - } - } - }) - - b.Run("Recover-GroupPK", func(b *testing.B) { - b.StopTimer() - pubShares := make([]*PublicKeyShares, 0, len(members)) - for _, member := range members { - pubShares = append(pubShares, member.pubShares) - } - b.StartTimer() - for i := 0; i < b.N; i++ { - RecoverGroupPublicKey(pubShares) - } - }) -} diff --git a/crypto/dkg/utils.go b/crypto/dkg/utils.go deleted file mode 100644 index 3684964..0000000 --- a/crypto/dkg/utils.go +++ /dev/null @@ -1,69 +0,0 @@ -// 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 ( - "fmt" - - "github.com/Spiderpowa/bls/ffi/go/bls" - - "github.com/dexon-foundation/dexon-consensus-core/crypto" -) - -// PartialSignature is a partial signature in DKG+TSIG protocol. -type PartialSignature crypto.Signature - -var ( - // ErrEmptySignature is reported if the signature is empty. - ErrEmptySignature = fmt.Errorf("invalid empty signature") -) - -// RecoverSignature recovers TSIG signature. -func RecoverSignature(sigs []PartialSignature, signerIDs IDs) ( - crypto.Signature, error) { - blsSigs := make([]bls.Sign, len(sigs)) - for i, sig := range sigs { - if len(sig) == 0 { - return nil, ErrEmptySignature - } - if err := blsSigs[i].Deserialize([]byte(sig)); err != nil { - return nil, err - } - } - var recoverSig bls.Sign - if err := recoverSig.Recover(blsSigs, []bls.ID(signerIDs)); err != nil { - return nil, err - } - return crypto.Signature(recoverSig.Serialize()), nil -} - -// RecoverGroupPublicKey recovers group public key. -func RecoverGroupPublicKey(pubShares []*PublicKeyShares) *PublicKey { - var pub *PublicKey - for _, pubShare := range pubShares { - pk0 := pubShare.masterPublicKey[0] - if pub == nil { - pub = &PublicKey{ - publicKey: pk0, - } - } else { - pub.publicKey.Add(&pk0) - } - } - return pub -} diff --git a/crypto/eth/eth.go b/crypto/eth/eth.go deleted file mode 100644 index c3c5a7c..0000000 --- a/crypto/eth/eth.go +++ /dev/null @@ -1,120 +0,0 @@ -// 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 eth - -import ( - "crypto/ecdsa" - - ethcrypto "github.com/ethereum/go-ethereum/crypto" - - "github.com/dexon-foundation/dexon-consensus-core/common" - "github.com/dexon-foundation/dexon-consensus-core/crypto" -) - -// PrivateKey represents a private key structure used in geth and implments -// Crypto.PrivateKey interface. -type PrivateKey struct { - privateKey ecdsa.PrivateKey - publicKey PublicKey -} - -// PublicKey represents a public key structure used in geth and implements -// Crypto.PublicKey interface. -type PublicKey struct { - publicKey []byte -} - -// NewPrivateKey creates a new PrivateKey structure. -func NewPrivateKey() (*PrivateKey, error) { - key, err := ethcrypto.GenerateKey() - if err != nil { - return nil, err - } - return &PrivateKey{ - privateKey: *key, - publicKey: *newPublicKey(key), - }, nil -} - -// newPublicKey creates a new PublicKey structure. -func newPublicKey(prvKey *ecdsa.PrivateKey) *PublicKey { - return &PublicKey{ - publicKey: ethcrypto.CompressPubkey(&prvKey.PublicKey), - } -} - -// DecompressPubkey parses a public key in the 33-byte compressed format. -func DecompressPubkey(pubkey []byte) (PublicKey, error) { - _, err := ethcrypto.DecompressPubkey(pubkey) - return PublicKey{ - publicKey: pubkey, - }, err -} - -// PublicKey returns the public key associate this private key. -func (prv *PrivateKey) PublicKey() crypto.PublicKey { - return prv.publicKey -} - -// Sign calculates an ECDSA signature. -// -// This function is susceptible to chosen plaintext attacks that can leak -// information about the private key that is used for signing. Callers must -// be aware that the given hash cannot be chosen by an adversery. Common -// solution is to hash any input before calculating the signature. -// -// The produced signature is in the [R || S || V] format where V is 0 or 1. -func (prv *PrivateKey) Sign(hash common.Hash) ( - sig crypto.Signature, err error) { - s, err := ethcrypto.Sign(hash[:], &prv.privateKey) - sig = crypto.Signature(s) - return -} - -// VerifySignature checks that the given public key created signature over hash. -// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) -// format. -// The signature should have the 64 byte [R || S] format. -func (pub PublicKey) VerifySignature( - hash common.Hash, signature crypto.Signature) bool { - if len(signature) == 65 { - // The last byte is for ecrecover. - signature = signature[:64] - } - return ethcrypto.VerifySignature(pub.publicKey, hash[:], signature) -} - -// Compress encodes a public key to the 33-byte compressed format. -func (pub PublicKey) Compress() []byte { - return pub.publicKey -} - -// Bytes returns the []byte representation of public key. -func (pub PublicKey) Bytes() []byte { - return pub.Compress() -} - -// SigToPub returns the PublicKey that created the given signature. -func SigToPub( - hash common.Hash, signature crypto.Signature) (crypto.PublicKey, error) { - key, err := ethcrypto.SigToPub(hash[:], signature[:]) - if err != nil { - return PublicKey{}, err - } - return PublicKey{publicKey: ethcrypto.CompressPubkey(key)}, nil -} diff --git a/crypto/eth/eth_test.go b/crypto/eth/eth_test.go deleted file mode 100644 index f6f48cb..0000000 --- a/crypto/eth/eth_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// 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 eth - -import ( - "testing" - - "github.com/dexon-foundation/dexon-consensus-core/common" - "github.com/dexon-foundation/dexon-consensus-core/crypto" - "github.com/stretchr/testify/suite" -) - -type ETHCryptoTestSuite struct { - suite.Suite -} - -func (s *ETHCryptoTestSuite) TestSignature() { - prv1, err := NewPrivateKey() - s.Require().Nil(err) - hash1 := common.NewRandomHash() - hash2 := common.NewRandomHash() - - // Test that same private key should produce same signature. - sig11, err := prv1.Sign(hash1) - s.Require().Nil(err) - sig112, err := prv1.Sign(hash1) - s.Require().Nil(err) - s.Equal(sig11, sig112) - - // Test that different private key should produce different signature. - prv2, err := NewPrivateKey() - s.Require().Nil(err) - sig21, err := prv2.Sign(hash1) - s.Require().Nil(err) - s.NotEqual(sig11, sig21) - - // Test that different hash should produce different signature. - sig12, err := prv1.Sign(hash2) - s.Require().Nil(err) - s.NotEqual(sig11, sig12) - - // Test VerifySignature with correct public key. - pub1, ok := prv1.PublicKey().(PublicKey) - s.Require().True(ok) - s.True(pub1.VerifySignature(hash1, sig11)) - - // Test VerifySignature with wrong hash. - s.False(pub1.VerifySignature(hash2, sig11)) - // Test VerifySignature with wrong signature. - s.False(pub1.VerifySignature(hash1, sig21)) - // Test VerifySignature with wrong public key. - pub2 := prv2.PublicKey() - s.False(pub2.VerifySignature(hash1, sig11)) - - // Test compress and decompress of public key. - compressPub1 := pub1.Compress() - decompressPub1, err := DecompressPubkey(compressPub1) - s.Require().Nil(err) - s.Equal(pub1, decompressPub1) - s.True(decompressPub1.VerifySignature(hash1, sig11)) -} - -func (s *ETHCryptoTestSuite) TestSigToPub() { - prv, err := NewPrivateKey() - s.Require().Nil(err) - data := "DEXON is infinitely scalable and low-latency." - hash := crypto.Keccak256Hash([]byte(data)) - sigmsg, err := prv.Sign(hash) - s.Require().Nil(err) - - pubkey, err := SigToPub(hash, sigmsg) - s.Require().Nil(err) - s.Equal(pubkey, prv.PublicKey()) -} - -func TestCrypto(t *testing.T) { - suite.Run(t, new(ETHCryptoTestSuite)) -} diff --git a/crypto/interfaces.go b/crypto/interfaces.go deleted file mode 100644 index 280082e..0000000 --- a/crypto/interfaces.go +++ /dev/null @@ -1,45 +0,0 @@ -// 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 crypto - -import ( - "github.com/dexon-foundation/dexon-consensus-core/common" -) - -// Signature is the basic signature type in DEXON. -type Signature []byte - -// PrivateKey describes the asymmetric cryptography interface that interacts -// with the private key. -type PrivateKey interface { - // PublicKey returns the public key associate this private key. - PublicKey() PublicKey - - // Sign calculates a signature. - Sign(hash common.Hash) (sig Signature, err error) -} - -// PublicKey describes the asymmetric cryptography interface that interacts -// with the public key. -type PublicKey interface { - // VerifySignature checks that the given public key created signature over hash. - VerifySignature(hash common.Hash, signature Signature) bool - - // Bytes returns the []byte representation of public key. - Bytes() []byte -} diff --git a/crypto/utils.go b/crypto/utils.go deleted file mode 100644 index 07a8b2b..0000000 --- a/crypto/utils.go +++ /dev/null @@ -1,41 +0,0 @@ -// 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 crypto - -import ( - "encoding/hex" - - "github.com/ethereum/go-ethereum/crypto" - - "github.com/dexon-foundation/dexon-consensus-core/common" -) - -// Keccak256Hash calculates and returns the Keccak256 hash of the input data, -// converting it to an internal Hash data structure. -func Keccak256Hash(data ...[]byte) (h common.Hash) { - return common.Hash(crypto.Keccak256Hash(data...)) -} - -// Clone returns a deep copy of a signature. -func (sig Signature) Clone() Signature { - return append(Signature{}, sig...) -} - -func (sig Signature) String() string { - return hex.EncodeToString([]byte(sig[:])) -} diff --git a/crypto/utils_test.go b/crypto/utils_test.go deleted file mode 100644 index 977027a..0000000 --- a/crypto/utils_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// 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 crypto - -import ( - "encoding/hex" - "testing" - - "github.com/stretchr/testify/suite" -) - -type CryptoTestSuite struct { - suite.Suite -} - -func (s *CryptoTestSuite) TestHash() { - cases := []struct { - input string - output string - }{ - {"DEXON ROCKS!", - "1a3f3a424aaa464e51b693585bba3a0c439d5f1ad3b5868e46d9f830225983bd"}, - {"Dexon Foundation", - "25ed4237aa978bfe706cc11c7a46a95de1a46302faea7ff6e900b03fa2b7b480"}, - {"INFINITELY SCALABLE AND LOW-LATENCY", - "ed3384c58a434fbc0bc887a85659eddf997e7da978ab66565ac865f995b77cf1"}, - } - for _, testcase := range cases { - hash := Keccak256Hash([]byte(testcase.input)) - output := hex.EncodeToString(hash[:]) - s.Equal(testcase.output, output) - } -} - -func TestCrypto(t *testing.T) { - suite.Run(t, new(CryptoTestSuite)) -} |