mirror of https://github.com/certusone/dc4bc.git
263 lines
5.8 KiB
Go
263 lines
5.8 KiB
Go
package dkg
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"go.dedis.ch/kyber/v3/share"
|
|
"math"
|
|
"sort"
|
|
"sync"
|
|
|
|
"go.dedis.ch/kyber/v3"
|
|
dkg "go.dedis.ch/kyber/v3/share/dkg/pedersen"
|
|
vss "go.dedis.ch/kyber/v3/share/vss/pedersen"
|
|
)
|
|
|
|
// TODO: dump necessary data on disk
|
|
type DKG struct {
|
|
sync.Mutex
|
|
instance *dkg.DistKeyGenerator
|
|
deals map[string]*dkg.Deal
|
|
commits map[string][]kyber.Point
|
|
responses *messageStore
|
|
pubkeys PKStore
|
|
pubKey kyber.Point
|
|
secKey kyber.Scalar
|
|
suite vss.Suite
|
|
ParticipantID int
|
|
Threshold int
|
|
}
|
|
|
|
func Init(suite vss.Suite, pubKey kyber.Point, secKey kyber.Scalar) *DKG {
|
|
var (
|
|
d DKG
|
|
)
|
|
|
|
d.suite = suite
|
|
d.secKey = secKey
|
|
d.pubKey = pubKey
|
|
|
|
d.deals = make(map[string]*dkg.Deal)
|
|
d.commits = make(map[string][]kyber.Point)
|
|
|
|
return &d
|
|
}
|
|
|
|
func (d *DKG) GetPubKey() kyber.Point {
|
|
return d.pubKey
|
|
}
|
|
|
|
func (d *DKG) GetSecKey() kyber.Scalar {
|
|
return d.secKey
|
|
}
|
|
|
|
func (d *DKG) GetPubKeyByParticipant(participant string) (kyber.Point, error) {
|
|
pk, err := d.pubkeys.GetPKByParticipant(participant)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get pk for participant %s: %w", participant, err)
|
|
}
|
|
return pk, nil
|
|
}
|
|
|
|
func (d *DKG) GetParticipantByIndex(index int) string {
|
|
return d.pubkeys.GetParticipantByIndex(index)
|
|
}
|
|
|
|
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 {
|
|
d.Lock()
|
|
defer d.Unlock()
|
|
|
|
return d.pubkeys.Add(&PK2Participant{
|
|
Participant: participant,
|
|
PK: pk,
|
|
ParticipantID: pid,
|
|
})
|
|
}
|
|
|
|
func (d *DKG) calcParticipantID() int {
|
|
for idx, p := range d.pubkeys {
|
|
if p.PK.Equal(d.pubKey) {
|
|
return idx
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func (d *DKG) InitDKGInstance() (err error) {
|
|
sort.Sort(d.pubkeys)
|
|
|
|
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)))
|
|
|
|
d.instance, err = dkg.NewDistKeyGenerator(d.suite, d.secKey, publicKeys, d.Threshold)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *DKG) GetCommits() []kyber.Point {
|
|
return d.instance.GetDealer().Commits()
|
|
}
|
|
|
|
func (d *DKG) StoreCommits(participant string, commits []kyber.Point) {
|
|
d.Lock()
|
|
defer d.Unlock()
|
|
|
|
d.commits[participant] = commits
|
|
}
|
|
|
|
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) {
|
|
d.Lock()
|
|
defer d.Unlock()
|
|
|
|
d.deals[participant] = deal
|
|
}
|
|
|
|
func (d *DKG) ProcessDeals() ([]*dkg.Response, error) {
|
|
responses := make([]*dkg.Response, 0)
|
|
for _, deal := range d.deals {
|
|
if deal.Index == uint32(d.ParticipantID) {
|
|
continue
|
|
}
|
|
resp, err := d.instance.ProcessDeal(deal)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Commits verification.
|
|
allVerifiers := d.instance.Verifiers()
|
|
verifier := allVerifiers[deal.Index]
|
|
commitsOK, err := d.processDealCommits(verifier, deal)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// If something goes wrong, party complains.
|
|
if !resp.Response.Status || !commitsOK {
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
if !d.instance.Certified() {
|
|
return fmt.Errorf("praticipant %v is not certified", d.ParticipantID)
|
|
}
|
|
|
|
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))
|
|
|
|
commitsData, ok := d.commits[participant]
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (d *DKG) GetBLSKeyring() (*BLSKeyring, error) {
|
|
if d.instance == nil || !d.instance.Certified() {
|
|
return nil, fmt.Errorf("dkg instance is not ready")
|
|
}
|
|
|
|
distKeyShare, err := d.instance.DistKeyShare()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get DistKeyShare: %v", err)
|
|
}
|
|
|
|
masterPubKey := share.NewPubPoly(d.suite, nil, distKeyShare.Commitments())
|
|
|
|
return &BLSKeyring{
|
|
PubPoly: masterPubKey,
|
|
Share: distKeyShare.PriShare(),
|
|
}, nil
|
|
}
|