mirror of
https://github.com/luxfi/tss.git
synced 2026-10-30 15:14:51 +00:00
191 lines
5.6 KiB
Go
191 lines
5.6 KiB
Go
// Copyright © 2019 Binance
|
|
//
|
|
// This file is part of Binance. The full Binance copyright notice, including
|
|
// terms governing use, modification, and redistribution, is contained in the
|
|
// file LICENSE at the root of the source code distribution tree.
|
|
|
|
package keygen
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"errors"
|
|
"math/big"
|
|
"sync"
|
|
|
|
"github.com/luxfi/tss/v2/crypto/facproof"
|
|
"github.com/luxfi/tss/v2/crypto/modproof"
|
|
|
|
"github.com/luxfi/tss/v2/common"
|
|
"github.com/luxfi/tss/v2/tss"
|
|
)
|
|
|
|
const (
|
|
paillierBitsLen = 2048
|
|
)
|
|
|
|
func (round *round2) Start() *tss.Error {
|
|
if round.started {
|
|
return round.WrapError(errors.New("round already started"))
|
|
}
|
|
round.number = 2
|
|
round.started = true
|
|
round.resetOK()
|
|
|
|
common.Logger.Debugf(
|
|
"%s Setting up DLN verification with concurrency level of %d",
|
|
round.PartyID(),
|
|
round.Concurrency(),
|
|
)
|
|
dlnVerifier := NewDlnProofVerifier(round.Concurrency())
|
|
|
|
i := round.PartyID().Index
|
|
|
|
// 6. verify dln proofs, store r1 message pieces, ensure uniqueness of h1j, h2j
|
|
h1H2Map := make(map[string]struct{}, len(round.temp.kgRound1Messages)*2)
|
|
dlnProof1FailCulprits := make([]*tss.PartyID, len(round.temp.kgRound1Messages))
|
|
dlnProof2FailCulprits := make([]*tss.PartyID, len(round.temp.kgRound1Messages))
|
|
wg := new(sync.WaitGroup)
|
|
for j, msg := range round.temp.kgRound1Messages {
|
|
r1msg := msg.Content().(*KGRound1Message)
|
|
H1j, H2j, NTildej, paillierPKj := r1msg.UnmarshalH1(),
|
|
r1msg.UnmarshalH2(),
|
|
r1msg.UnmarshalNTilde(),
|
|
r1msg.UnmarshalPaillierPK()
|
|
if paillierPKj.N.BitLen() != paillierBitsLen {
|
|
return round.WrapError(errors.New("got paillier modulus with insufficient bits for this party"), msg.GetFrom())
|
|
}
|
|
if H1j.Cmp(H2j) == 0 {
|
|
return round.WrapError(errors.New("h1j and h2j were equal for this party"), msg.GetFrom())
|
|
}
|
|
if NTildej.BitLen() != paillierBitsLen {
|
|
return round.WrapError(errors.New("got NTildej with insufficient bits for this party"), msg.GetFrom())
|
|
}
|
|
h1JHex, h2JHex := hex.EncodeToString(H1j.Bytes()), hex.EncodeToString(H2j.Bytes())
|
|
if _, found := h1H2Map[h1JHex]; found {
|
|
return round.WrapError(errors.New("this h1j was already used by another party"), msg.GetFrom())
|
|
}
|
|
if _, found := h1H2Map[h2JHex]; found {
|
|
return round.WrapError(errors.New("this h2j was already used by another party"), msg.GetFrom())
|
|
}
|
|
h1H2Map[h1JHex], h1H2Map[h2JHex] = struct{}{}, struct{}{}
|
|
|
|
wg.Add(2)
|
|
_j := j
|
|
_msg := msg
|
|
|
|
dlnVerifier.VerifyDLNProof1(r1msg, H1j, H2j, NTildej, func(isValid bool) {
|
|
if !isValid {
|
|
dlnProof1FailCulprits[_j] = _msg.GetFrom()
|
|
}
|
|
wg.Done()
|
|
})
|
|
dlnVerifier.VerifyDLNProof2(r1msg, H2j, H1j, NTildej, func(isValid bool) {
|
|
if !isValid {
|
|
dlnProof2FailCulprits[_j] = _msg.GetFrom()
|
|
}
|
|
wg.Done()
|
|
})
|
|
}
|
|
wg.Wait()
|
|
for _, culprit := range append(dlnProof1FailCulprits, dlnProof2FailCulprits...) {
|
|
if culprit != nil {
|
|
return round.WrapError(errors.New("dln proof verification failed"), culprit)
|
|
}
|
|
}
|
|
// save NTilde_j, h1_j, h2_j, ...
|
|
for j, msg := range round.temp.kgRound1Messages {
|
|
if j == i {
|
|
continue
|
|
}
|
|
r1msg := msg.Content().(*KGRound1Message)
|
|
paillierPK, H1j, H2j, NTildej, KGC := r1msg.UnmarshalPaillierPK(),
|
|
r1msg.UnmarshalH1(),
|
|
r1msg.UnmarshalH2(),
|
|
r1msg.UnmarshalNTilde(),
|
|
r1msg.UnmarshalCommitment()
|
|
round.save.PaillierPKs[j] = paillierPK // used in round 4
|
|
round.save.NTildej[j] = NTildej
|
|
round.save.H1j[j], round.save.H2j[j] = H1j, H2j
|
|
round.temp.KGCs[j] = KGC
|
|
}
|
|
|
|
// 5. p2p send share ij to Pj
|
|
shares := round.temp.shares
|
|
ContextI := append(round.temp.ssid, big.NewInt(int64(i)).Bytes()...)
|
|
for j, Pj := range round.Parties().IDs() {
|
|
|
|
facProof := &facproof.ProofFac{
|
|
P: zero, Q: zero, A: zero, B: zero, T: zero, Sigma: zero,
|
|
Z1: zero, Z2: zero, W1: zero, W2: zero, V: zero,
|
|
}
|
|
if !round.Params().NoProofFac() {
|
|
var err error
|
|
facProof, err = facproof.NewProof(ContextI, round.EC(), round.save.PaillierSK.N, round.save.NTildej[j],
|
|
round.save.H1j[j], round.save.H2j[j], round.save.PaillierSK.P, round.save.PaillierSK.Q, round.Rand())
|
|
if err != nil {
|
|
return round.WrapError(err, round.PartyID())
|
|
}
|
|
|
|
}
|
|
r2msg1 := NewKGRound2Message1(Pj, round.PartyID(), shares[j], facProof)
|
|
// do not send to this Pj, but store for round 3
|
|
if j == i {
|
|
round.temp.kgRound2Message1s[j] = r2msg1
|
|
continue
|
|
}
|
|
round.out <- r2msg1
|
|
}
|
|
|
|
// 7. BROADCAST de-commitments of Shamir poly*G
|
|
modProof := &modproof.ProofMod{W: zero, X: *new([80]*big.Int), A: zero, B: zero, Z: *new([80]*big.Int)}
|
|
if !round.Parameters.NoProofMod() {
|
|
var err error
|
|
modProof, err = modproof.NewProof(ContextI, round.save.PaillierSK.N,
|
|
round.save.PaillierSK.P, round.save.PaillierSK.Q, round.Rand())
|
|
if err != nil {
|
|
return round.WrapError(err, round.PartyID())
|
|
}
|
|
}
|
|
r2msg2 := NewKGRound2Message2(round.PartyID(), round.temp.deCommitPolyG, modProof)
|
|
round.temp.kgRound2Message2s[i] = r2msg2
|
|
round.out <- r2msg2
|
|
|
|
return nil
|
|
}
|
|
|
|
func (round *round2) CanAccept(msg tss.ParsedMessage) bool {
|
|
if _, ok := msg.Content().(*KGRound2Message1); ok {
|
|
return !msg.IsBroadcast()
|
|
}
|
|
if _, ok := msg.Content().(*KGRound2Message2); ok {
|
|
return msg.IsBroadcast()
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (round *round2) Update() (bool, *tss.Error) {
|
|
// guard - VERIFY de-commit for all Pj
|
|
ret := true
|
|
for j, msg := range round.temp.kgRound2Message1s {
|
|
if round.ok[j] {
|
|
continue
|
|
}
|
|
if msg == nil || !round.CanAccept(msg) {
|
|
ret = false
|
|
continue
|
|
}
|
|
msg2 := round.temp.kgRound2Message2s[j]
|
|
if msg2 == nil || !round.CanAccept(msg2) {
|
|
ret = false
|
|
continue
|
|
}
|
|
round.ok[j] = true
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func (round *round2) NextRound() tss.Round {
|
|
round.started = false
|
|
return &round3{round}
|
|
}
|