dc4bc/dkg/dkg.go

266 lines
5.8 KiB
Go
Raw Normal View History

2020-07-22 09:44:30 -07:00
package dkg
import (
"errors"
"fmt"
2020-07-26 10:46:39 -07:00
"math"
2020-07-23 08:39:56 -07:00
"sort"
2020-07-23 06:29:20 -07:00
"sync"
2020-08-30 09:23:48 -07:00
"github.com/corestario/kyber/share"
"github.com/corestario/kyber"
dkg "github.com/corestario/kyber/share/dkg/pedersen"
vss "github.com/corestario/kyber/share/vss/pedersen"
2020-07-22 09:44:30 -07:00
)
2020-08-18 11:52:04 -07:00
// TODO: dump necessary data on disk
2020-07-22 09:44:30 -07:00
type DKG struct {
2020-07-23 06:29:20 -07:00
sync.Mutex
2020-07-22 09:44:30 -07:00
instance *dkg.DistKeyGenerator
deals map[string]*dkg.Deal
2020-07-23 06:29:20 -07:00
commits map[string][]kyber.Point
2020-07-23 08:39:56 -07:00
responses *messageStore
2020-07-22 09:44:30 -07:00
pubkeys PKStore
pubKey kyber.Point
secKey kyber.Scalar
2020-08-19 06:47:37 -07:00
suite vss.Suite
2020-07-23 08:39:56 -07:00
ParticipantID int
2020-08-28 06:31:31 -07:00
N int
Threshold int
2020-07-22 09:44:30 -07:00
}
2020-08-19 06:47:37 -07:00
func Init(suite vss.Suite, pubKey kyber.Point, secKey kyber.Scalar) *DKG {
2020-07-22 09:44:30 -07:00
var (
d DKG
)
2020-08-13 08:27:28 -07:00
d.suite = suite
d.secKey = secKey
d.pubKey = pubKey
2020-07-22 09:44:30 -07:00
d.deals = make(map[string]*dkg.Deal)
2020-07-23 06:29:20 -07:00
d.commits = make(map[string][]kyber.Point)
2020-07-22 09:44:30 -07:00
return &d
}
func (d *DKG) GetPubKey() kyber.Point {
return d.pubKey
}
2020-08-11 06:42:32 -07:00
func (d *DKG) GetSecKey() kyber.Scalar {
return d.secKey
}
2020-08-13 08:27:28 -07:00
func (d *DKG) GetPubKeyByParticipant(participant string) (kyber.Point, error) {
pk, err := d.pubkeys.GetPKByParticipant(participant)
2020-08-11 06:42:32 -07:00
if err != nil {
2020-08-13 08:27:28 -07:00
return nil, fmt.Errorf("failed to get pk for participant %s: %w", participant, err)
2020-08-11 06:42:32 -07:00
}
return pk, nil
}
func (d *DKG) GetParticipantByIndex(index int) string {
return d.pubkeys.GetParticipantByIndex(index)
}
2020-08-13 09:34:38 -07:00
func (d *DKG) GetPKByIndex(index int) kyber.Point {
return d.pubkeys.GetPKByIndex(index)
}
func (d *DKG) StorePubKey(participant string, pid int, pk kyber.Point) bool {
2020-07-23 06:29:20 -07:00
d.Lock()
defer d.Unlock()
2020-07-22 09:44:30 -07:00
return d.pubkeys.Add(&PK2Participant{
2020-08-13 09:34:38 -07:00
Participant: participant,
PK: pk,
ParticipantID: pid,
2020-07-22 09:44:30 -07:00
})
}
2020-07-26 10:46:39 -07:00
func (d *DKG) calcParticipantID() int {
for idx, p := range d.pubkeys {
if p.PK.Equal(d.pubKey) {
return idx
}
}
return -1
}
2020-08-12 04:40:40 -07:00
func (d *DKG) InitDKGInstance() (err error) {
2020-07-23 08:39:56 -07:00
sort.Sort(d.pubkeys)
2020-07-26 10:46:39 -07:00
publicKeys := d.pubkeys.GetPKs()
participantsCount := len(publicKeys)
participantID := d.calcParticipantID()
if participantID < 0 {
return fmt.Errorf("failed to determine participant index")
}
d.ParticipantID = participantID
d.responses = newMessageStore(int(math.Pow(float64(participantsCount)-1, 2)))
2020-08-12 04:40:40 -07:00
d.instance, err = dkg.NewDistKeyGenerator(d.suite, d.secKey, publicKeys, d.Threshold)
2020-07-22 09:44:30 -07:00
if err != nil {
return err
}
return nil
}
func (d *DKG) GetCommits() []kyber.Point {
return d.instance.GetDealer().Commits()
}
2020-07-23 06:29:20 -07:00
func (d *DKG) StoreCommits(participant string, commits []kyber.Point) {
d.Lock()
defer d.Unlock()
d.commits[participant] = commits
2020-07-22 09:44:30 -07:00
}
func (d *DKG) GetDeals() (map[int]*dkg.Deal, error) {
deals, err := d.instance.Deals()
if err != nil {
return nil, err
}
return deals, nil
}
func (d *DKG) StoreDeal(participant string, deal *dkg.Deal) {
2020-07-23 08:39:56 -07:00
d.Lock()
defer d.Unlock()
2020-07-22 09:44:30 -07:00
d.deals[participant] = deal
}
2020-07-23 08:39:56 -07:00
func (d *DKG) ProcessDeals() ([]*dkg.Response, error) {
responses := make([]*dkg.Response, 0)
2020-07-22 09:44:30 -07:00
for _, deal := range d.deals {
2020-07-23 08:39:56 -07:00
if deal.Index == uint32(d.ParticipantID) {
2020-07-22 09:44:30 -07:00
continue
}
resp, err := d.instance.ProcessDeal(deal)
if err != nil {
2020-07-23 08:39:56 -07:00
return nil, err
2020-07-22 09:44:30 -07:00
}
// Commits verification.
allVerifiers := d.instance.Verifiers()
verifier := allVerifiers[deal.Index]
commitsOK, err := d.processDealCommits(verifier, deal)
if err != nil {
2020-07-23 08:39:56 -07:00
return nil, err
2020-07-22 09:44:30 -07:00
}
// If something goes wrong, party complains.
if !resp.Response.Status || !commitsOK {
2020-07-23 08:39:56 -07:00
return nil, fmt.Errorf("failed to process deals")
}
responses = append(responses, resp)
}
return responses, nil
}
func (d *DKG) StoreResponses(participant string, responses []*dkg.Response) {
d.Lock()
defer d.Unlock()
for _, resp := range responses {
d.responses.add(participant, int(resp.Response.Index), resp)
}
}
func (d *DKG) ProcessResponses() error {
for _, peerResponses := range d.responses.indexToData {
for _, response := range peerResponses {
resp := response.(*dkg.Response)
if int(resp.Response.Index) == d.ParticipantID {
continue
}
_, err := d.instance.ProcessResponse(resp)
if err != nil {
return fmt.Errorf("failed to ProcessResponse: %w", err)
}
2020-07-22 09:44:30 -07:00
}
}
2020-07-23 08:39:56 -07:00
if !d.instance.Certified() {
return fmt.Errorf("praticipant %v is not certified", d.ParticipantID)
}
2020-07-22 09:44:30 -07:00
return nil
}
func (d *DKG) processDealCommits(verifier *vss.Verifier, deal *dkg.Deal) (bool, error) {
decryptedDeal, err := verifier.DecryptDeal(deal.Deal)
if err != nil {
return false, err
}
participant := d.pubkeys.GetParticipantByIndex(int(deal.Index))
2020-07-23 08:39:56 -07:00
commitsData, ok := d.commits[participant]
2020-07-22 09:44:30 -07:00
if !ok {
return false, err
}
var originalCommits []kyber.Point
for _, commitData := range commitsData {
commit, ok := commitData.(kyber.Point)
if !ok {
return false, fmt.Errorf("failed to cast commit data to commit type")
}
originalCommits = append(originalCommits, commit)
}
if len(originalCommits) != len(decryptedDeal.Commitments) {
return false, errors.New("number of original commitments and number of commitments in the deal are not met")
}
for i := range originalCommits {
if !originalCommits[i].Equal(decryptedDeal.Commitments[i]) {
return false, errors.New("commits are different")
}
}
return true, nil
}
2020-08-14 07:38:58 -07:00
func (d *DKG) GetDistKeyShare() (*dkg.DistKeyShare, error) {
return d.instance.DistKeyShare()
}
func (d *DKG) GetDistributedPublicKey() (kyber.Point, error) {
distKeyShare, err := d.instance.DistKeyShare()
if err != nil {
return nil, fmt.Errorf("failed to get distKeyShare")
}
return distKeyShare.Public(), nil
}
2020-08-18 11:52:04 -07:00
func (d *DKG) GetBLSKeyring() (*BLSKeyring, error) {
2020-07-22 09:44:30 -07:00
if d.instance == nil || !d.instance.Certified() {
return nil, fmt.Errorf("dkg instance is not ready")
2020-07-22 09:44:30 -07:00
}
distKeyShare, err := d.instance.DistKeyShare()
if err != nil {
return nil, fmt.Errorf("failed to get DistKeyShare: %v", err)
2020-07-22 09:44:30 -07:00
}
masterPubKey := share.NewPubPoly(d.suite, nil, distKeyShare.Commitments())
2020-07-23 06:29:20 -07:00
2020-08-18 11:52:04 -07:00
return &BLSKeyring{
PubPoly: masterPubKey,
Share: distKeyShare.PriShare(),
}, nil
2020-07-22 09:44:30 -07:00
}