diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2018-09-13 10:49:09 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-13 10:49:09 +0800 |
commit | e9e0793a7191fb422e5458174d97c84a1f02f26a (patch) | |
tree | 14103163bd7ba06ffdfd4dc93b7df1cf4f5a30d9 /crypto/dkg/dkg.go | |
parent | b4af97dd8cfd5bbd7032fb5e1aff240625df06cb (diff) | |
download | tangerine-consensus-e9e0793a7191fb422e5458174d97c84a1f02f26a.tar tangerine-consensus-e9e0793a7191fb422e5458174d97c84a1f02f26a.tar.gz tangerine-consensus-e9e0793a7191fb422e5458174d97c84a1f02f26a.tar.bz2 tangerine-consensus-e9e0793a7191fb422e5458174d97c84a1f02f26a.tar.lz tangerine-consensus-e9e0793a7191fb422e5458174d97c84a1f02f26a.tar.xz tangerine-consensus-e9e0793a7191fb422e5458174d97c84a1f02f26a.tar.zst tangerine-consensus-e9e0793a7191fb422e5458174d97c84a1f02f26a.zip |
crypto: dkg implementation and test. (#96)
* DKG API and test.
* Change naming
* Broadcast pubShares
Diffstat (limited to 'crypto/dkg/dkg.go')
-rw-r--r-- | crypto/dkg/dkg.go | 273 |
1 files changed, 272 insertions, 1 deletions
diff --git a/crypto/dkg/dkg.go b/crypto/dkg/dkg.go index b5e8d03..d3596e6 100644 --- a/crypto/dkg/dkg.go +++ b/crypto/dkg/dkg.go @@ -18,9 +18,280 @@ package dkg import ( + "fmt" + "github.com/herumi/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") ) func init() { - bls.Init(0) + bls.Init(curve) +} + +// PrivateKey represents a private key structure implments +// Crypto.PrivateKey interface. +type PrivateKey struct { + privateKey bls.SecretKey + id bls.ID + publicKey PublicKey +} + +// 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 +} + +// PublicKeyShares represents a public key shares for DKG protocol. +type PublicKeyShares struct { + shares []PublicKey + shareIndex map[ID]int + masterPublicKey []bls.PublicKey +} + +// 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 private key shares for k-of-n TSIG. +func NewPrivateKeyShares(k int, IDs IDs) (*PrivateKeyShares, *PublicKeyShares) { + var prv bls.SecretKey + prv.SetByCSPRNG() + msk := prv.GetMasterSecretKey(k) + mpk := bls.GetMasterPublicKey(msk) + shares := make([]PrivateKey, len(IDs)) + shareMap := make(map[ID]int) + for idx, ID := range IDs { + shares[idx].privateKey.Set(msk, &ID) + shareMap[ID] = idx + } + return &PrivateKeyShares{ + shares: shares, + shareIndex: shareMap, + }, &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), + } +} + +// 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 +} + +// 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 +} + +// VerifySignature checks that the given public key created signature over hash. +func (pub PublicKey) VerifySignature( + hash common.Hash, signature crypto.Signature) bool { + 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 the []byte representation of public key. +func (pub PublicKey) Bytes() []byte { + var bytes []byte + pub.publicKey.Deserialize(bytes) + return bytes } |