aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/dkg.go
blob: e43ebc80637f6a3340eafd3560e43f02b4b38995 (plain) (tree)














































                                                                                      


                                               





































































































































































































































                                                                                   
                      







                                                 
                      








































                                                                       
                              





















































































                                                                                   


                                                      

















































































































































                                                                                
// Copyright 2018 The dexon-consensus Authors
// This file is part of the dexon-consensus library.
//
// The dexon-consensus 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 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 library. If not, see
// <http://www.gnu.org/licenses/>.

package dkg

import (
    "encoding/json"
    "fmt"
    "io"

    "github.com/dexon-foundation/bls/ffi/go/bls"
    "github.com/dexon-foundation/dexon/rlp"

    "github.com/dexon-foundation/dexon-consensus/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")
)

const cryptoType = "bls"

var publicKeyLength int

func init() {
    if err := bls.Init(curve); err != nil {
        panic(err)
    }

    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
}

// EncodeRLP implements rlp.Encoder
func (prv *PrivateKey) EncodeRLP(w io.Writer) error {
    return rlp.Encode(w, prv.Bytes())
}

// DecodeRLP implements rlp.Decoder
func (prv *PrivateKey) DecodeRLP(s *rlp.Stream) error {
    var b []byte
    if err := s.Decode(&b); err != nil {
        return err
    }
    return prv.SetBytes(b)
}

// 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
}

// Equal check equality between two PrivateKeyShares instances.
func (prvs *PrivateKeyShares) Equal(other *PrivateKeyShares) bool {
    // Check shares.
    if len(prvs.shareIndex) != len(other.shareIndex) {
        return false
    }
    for dID, idx := range prvs.shareIndex {
        otherIdx, exists := other.shareIndex[dID]
        if !exists {
            return false
        }
        if !prvs.shares[idx].privateKey.IsEqual(
            &other.shares[otherIdx].privateKey) {
            return false
        }
    }
    // Check master private keys.
    if len(prvs.masterPrivateKey) != len(other.masterPrivateKey) {
        return false
    }
    for idx, m := range prvs.masterPrivateKey {
        if m.GetHexString() != other.masterPrivateKey[idx].GetHexString() {
            return false
        }
    }
    return true
}

// PublicKeyShares represents a public key shares for DKG protocol.
type PublicKeyShares struct {
    shareCaches     []PublicKey
    shareCacheIndex map[ID]int
    masterPublicKey []bls.PublicKey
}

type rlpPublicKeyShares struct {
    ShareCaches      [][]byte
    ShareCacheIndexK [][]byte
    ShareCacheIndexV []uint32
    MasterPublicKey  [][]byte
}

// Equal checks equality of two PublicKeyShares instance.
func (pubs *PublicKeyShares) Equal(other *PublicKeyShares) bool {
    // Check shares.
    for dID, idx := range pubs.shareCacheIndex {
        otherIdx, exists := other.shareCacheIndex[dID]
        if !exists {
            continue
        }
        if !pubs.shareCaches[idx].publicKey.IsEqual(
            &other.shareCaches[otherIdx].publicKey) {
            return false
        }
    }
    // Check master public keys.
    if len(pubs.masterPublicKey) != len(other.masterPublicKey) {
        return false
    }
    for idx, m := range pubs.masterPublicKey {
        if m.GetHexString() != other.masterPublicKey[idx].GetHexString() {
            return false
        }
    }
    return true
}

// EncodeRLP implements rlp.Encoder
func (pubs *PublicKeyShares) EncodeRLP(w io.Writer) error {
    var rps rlpPublicKeyShares
    for _, share := range pubs.shareCaches {
        rps.ShareCaches = append(rps.ShareCaches, share.Serialize())
    }

    for id, v := range pubs.shareCacheIndex {
        rps.ShareCacheIndexK = append(
            rps.ShareCacheIndexK, id.GetLittleEndian())
        rps.ShareCacheIndexV = append(rps.ShareCacheIndexV, uint32(v))
    }

    for _, m := range pubs.masterPublicKey {
        rps.MasterPublicKey = append(rps.MasterPublicKey, m.Serialize())
    }

    return rlp.Encode(w, rps)
}

// DecodeRLP implements rlp.Decoder
func (pubs *PublicKeyShares) DecodeRLP(s *rlp.Stream) error {
    var dec rlpPublicKeyShares
    if err := s.Decode(&dec); err != nil {
        return err
    }

    if len(dec.ShareCacheIndexK) != len(dec.ShareCacheIndexV) {
        return fmt.Errorf("invalid shareIndex")
    }

    ps := NewEmptyPublicKeyShares()
    for _, share := range dec.ShareCaches {
        var publicKey PublicKey
        if err := publicKey.Deserialize(share); err != nil {
            return err
        }
        ps.shareCaches = append(ps.shareCaches, publicKey)
    }

    for i, k := range dec.ShareCacheIndexK {
        id, err := BytesID(k)
        if err != nil {
            return err
        }
        ps.shareCacheIndex[id] = int(dec.ShareCacheIndexV[i])
    }

    for _, k := range dec.MasterPublicKey {
        var key bls.PublicKey
        if err := key.Deserialize(k); err != nil {
            return err
        }
        ps.masterPublicKey = append(ps.masterPublicKey, key)
    }

    *pubs = *ps
    return nil
}

// 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
}

// Clone clones every fields of PublicKeyShares. This method is mainly
// for testing purpose thus would panic when error.
func (pubs *PublicKeyShares) Clone() *PublicKeyShares {
    b, err := rlp.EncodeToBytes(pubs)
    if err != nil {
        panic(err)
    }
    pubsCopy := NewEmptyPublicKeyShares()
    if err := rlp.DecodeBytes(b, pubsCopy); err != nil {
        panic(err)
    }
    return pubsCopy
}

// NewID creates a ew ID structure.
func NewID(id []byte) ID {
    var blsID bls.ID
    // #nosec G104
    blsID.SetLittleEndian(id)
    return blsID
}

// BytesID creates a new ID structure,
// It returns err if the byte slice is not valid.
func BytesID(id []byte) (ID, error) {
    var blsID bls.ID
    // #nosec G104
    err := blsID.SetLittleEndian(id)
    return blsID, err
}

// 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{
            shareCacheIndex: 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 {
        // #nosec G104
        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{
        shareCacheIndex: make(map[ID]int),
    }
}

// Share returns the share for the ID.
func (pubs *PublicKeyShares) Share(ID ID) (*PublicKey, error) {
    idx, exist := pubs.shareCacheIndex[ID]
    if exist {
        return &pubs.shareCaches[idx], nil
    }
    var pk PublicKey
    if err := pk.publicKey.Set(pubs.masterPublicKey, &ID); err != nil {
        return nil, err
    }
    if err := pubs.AddShare(ID, &pk); err != nil {
        return nil, err
    }
    return &pk, nil
}

// AddShare adds a share.
func (pubs *PublicKeyShares) AddShare(ID ID, share *PublicKey) error {
    if idx, exist := pubs.shareCacheIndex[ID]; exist {
        if !share.publicKey.IsEqual(&pubs.shareCaches[idx].publicKey) {
            return ErrDuplicatedShare
        }
        return nil
    }
    pubs.shareCacheIndex[ID] = len(pubs.shareCaches)
    pubs.shareCaches = append(pubs.shareCaches, *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 {
        pk, err := pubs.Share(ID)
        if err != nil {
            return nil, err
        }
        if i == 0 {
            pub.publicKey = pk.publicKey
            continue
        }
        pub.publicKey.Add(&pk.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(),
    }
}

// newPublicKeyFromBytes create a new PublicKey structure
// from bytes representation of bls.PublicKey
func newPublicKeyFromBytes(b []byte) (*PublicKey, error) {
    var pub PublicKey
    err := pub.publicKey.Deserialize(b)
    return &pub, err
}

// 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{
        Type:      cryptoType,
        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.Signature) == 0 {
        return false
    }
    var sig bls.Sign
    if err := sig.Deserialize(signature.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 {
    return pub.publicKey.Serialize()
}

// Serialize return bytes representation of public key.
func (pub *PublicKey) Serialize() []byte {
    return pub.publicKey.Serialize()
}

// Deserialize parses bytes representation of public key.
func (pub *PublicKey) Deserialize(b []byte) error {
    return pub.publicKey.Deserialize(b)
}