Closed r4881t closed 2 years ago
Lower-case symbols are not exported in Go modules as far as I remember (temp, data). So it may work as part of module unit-tests, but not when you imported github.com/bnb-chain/tss-lib into your app
I believe you are correct. I am new to Go. How should I proceed in this case then? What's the way to generate shares? The README mentions to simply do below for each party with proper communications setup. But the tests make it seem like there's a lot more to be done.
party := keygen.NewLocalParty(params, outCh, endCh, preParams) // Omit the last arg to compute the pre-params in round 1
go func() {
err := party.Start()
// handle err ...
}()
You only have to read (for each party) from endCh
data of type keygen.LocalPartySaveData
.
This data you can just serialize to the disk via json.Marshal
.
Same if your app restart, you just loads saved "share" from disk by json.Unmarshal
.
This "share" of type keygen.LocalPartySaveData
you use later for signing routines (for example)
This is kind of "key" of one party.
Hi @yshurik Thanks for being patient. I tried what you recommended, and it seems to make me move forward. But not complete. Now I can see messages passing around between the parties, but I don't get anything on the endCh
to save. This is a 2 Party setup and the value of threshold is 1
main.go
func SharedPartyUpdater(party tss.Party, msg tss.Message, errCh chan<- *tss.Error) {
// do not send a message from this party back to itself
log.Printf("Got a message from %s for %s",
msg.GetFrom().GetMoniker(),
party.PartyID().GetMoniker())
if party.PartyID() == msg.GetFrom() {
log.Print("Ignored...")
return
}
// Returns the encoded message bytes to send over the wire along with routing information
bz, _, err := msg.WireBytes()
if err != nil {
errCh <- party.WrapError(err)
return
}
pMsg, err := tss.ParseWireMessage(bz, msg.GetFrom(), msg.IsBroadcast())
if err != nil {
errCh <- party.WrapError(err)
return
}
// Will only work in local setup
if _, err := party.Update(pMsg); err != nil {
errCh <- err
}
}
func keyGen(userId big.Int, threshold int) {
server_id := big.NewInt(1)
if userId.Cmp(server_id) == 0 {
panic("Invalid user id. Must != " + server_id.String())
}
log.Printf("Received request to generate keypair for user: %s", userId.String())
preParamsUser, _ := keygen.GeneratePreParams(1 * time.Minute)
log.Print(("Generated pre params for User"))
preParamsServer, _ := keygen.GeneratePreParams(1 * time.Minute)
log.Printf("Generated pre-params for Server")
userPartyName := userId.String()
userParty := tss.NewPartyID(userPartyName, userPartyName, &userId)
serverPartyName := userPartyName + "_server"
serverParty := tss.NewPartyID(serverPartyName, serverPartyName, server_id)
_pIDs := []*tss.PartyID{userParty, serverParty}
pIDs := tss.SortPartyIDs(_pIDs)
ctx := tss.NewPeerContext(pIDs)
partiesCount := len(pIDs)
errCh := make(chan *tss.Error, partiesCount)
outCh := make(chan tss.Message, partiesCount)
endCh := make(chan keygen.LocalPartySaveData)
parties := make([]*keygen.LocalParty, 0, partiesCount)
curve := tss.S256()
userParams := tss.NewParameters(curve, ctx, userParty, len(pIDs), threshold)
userLocalParty := keygen.NewLocalParty(
userParams,
outCh,
endCh,
*preParamsUser).(*keygen.LocalParty)
parties = append(parties, userLocalParty)
serverParams := tss.NewParameters(curve, ctx, serverParty, len(pIDs), threshold)
serverLocalParty := keygen.NewLocalParty(
serverParams,
outCh,
endCh,
*preParamsServer).(*keygen.LocalParty)
parties = append(parties, serverLocalParty)
log.Printf("Starting goroutines")
go func(P *keygen.LocalParty) {
if err := P.Start(); err != nil {
errCh <- err
}
log.Print("local party finished")
}(userLocalParty)
go func(P *keygen.LocalParty) {
if err := P.Start(); err != nil {
errCh <- err
}
log.Print("server party finished")
}(serverLocalParty)
var ended int32
keygen:
for {
select {
case err := <-errCh:
log.Printf("Error: %s", err.Error())
break keygen
case msg := <-outCh:
dest := msg.GetTo()
if dest == nil { // broadcast!
log.Print("Broadcasting...")
for _, P := range parties {
if P.PartyID().Index == msg.GetFrom().Index {
continue
}
go SharedPartyUpdater(P, msg, errCh)
}
} else { // point-to-point!
log.Print("Point-to-point...")
if dest[0].Index == msg.GetFrom().Index {
log.Printf("party %d tried to send a message to itself (%d)", dest[0].Index, msg.GetFrom().Index)
panic("Party Sending Msg to Itself")
}
go SharedPartyUpdater(parties[dest[0].Index], msg, errCh)
}
case save := <-endCh:
log.Printf("Got save data from party %d", save.ShareID)
_, err := save.OriginalIndex()
if err != nil {
panic("Unknown Error while saving party's data: " + err.Error())
}
fmt.Print(save)
log.Print("Got save data from party")
atomic.AddInt32(&ended, 1)
if atomic.LoadInt32(&ended) == int32(partiesCount) {
log.Printf("Done. Received save data from %d participants", ended)
log.Print(save.ShareID.String())
json.Marshal(save)
break keygen
}
}
}
}
Upon executing I get the following
bitpack-tss-lib % ./mpc-app-tsslib
2022/08/27 13:22:17 Received request to generate keypair for user: 3
2022/08/27 13:22:30 Generated pre params for User
2022/08/27 13:22:44 Generated pre-params for Server
2022/08/27 13:22:44 Starting goroutines
2022/08/27 13:22:45 Broadcasting...
2022/08/27 13:22:45 local party finished
2022/08/27 13:22:45 Got a message from 3 for 3_bitpack
2022/08/27 13:22:45 Broadcasting...
2022/08/27 13:22:45 Got a message from 3_bitpack for 3
2022/08/27 13:22:45 server party finished
2022/08/27 13:22:46 Point-to-point...
2022/08/27 13:22:46 Broadcasting...
2022/08/27 13:22:46 Got a message from 3_bitpack for 3_bitpack
2022/08/27 13:22:46 Ignored...
2022/08/27 13:22:46 Got a message from 3_bitpack for 3
2022/08/27 13:22:46 Point-to-point...
2022/08/27 13:22:46 Broadcasting...
2022/08/27 13:22:46 Got a message from 3 for 3_bitpack
2022/08/27 13:22:46 Got a message from 3 for 3
2022/08/27 13:22:46 Ignored...
It is hard to say why stalled.
I would recommend to switch on the logging in tss lib.
It uses "github.com/ipfs/go-log"
, so add import like:
import (
logging "github.com/ipfs/go-log"
)
// before start keygen:
logging.SetDebugLogging()
You will see what parties are talking to each other
@yshurik I added the following timeout condition apart from the logger, and it seems like one of the parties is waiting for a message from itself in round 2.
case <-time.After(1 * time.Minute):
for _, P := range parties {
common.Logger.Debug(P.PartyID().String()+" waiting for %s", P.WaitingFor())
}
common.Logger.Debug("timeout")
break keygen
}
The log output is as follows: This is for a user with ID 3
and a server with ID 1
./mpc-api-tsslib
17:44:55.241 INFO tss-lib: Received request to generate keypair for user: %s 3 main.go:72
17:44:55.242 INFO tss-lib: generating the Paillier modulus, please wait... prepare.go:63
17:44:55.242 INFO tss-lib: generating the safe primes for the signing proofs, please wait... prepare.go:78
17:45:00.242 INFO tss-lib: paillier modulus generated. took 4.999475958s
prepare.go:71
17:45:03.243 INFO tss-lib: still generating primes... prepare.go:99
17:45:03.306 INFO tss-lib: safe primes generated. took 8.064205959s
prepare.go:85
17:45:03.431 INFO tss-lib: Generated pre params for User main.go:75
17:45:03.431 INFO tss-lib: generating the safe primes for the signing proofs, please wait... prepare.go:78
17:45:03.431 INFO tss-lib: generating the Paillier modulus, please wait... prepare.go:63
17:45:11.431 INFO tss-lib: still generating primes... prepare.go:99
17:45:14.912 INFO tss-lib: paillier modulus generated. took 11.481392666s
prepare.go:71
17:45:18.910 INFO tss-lib: safe primes generated. took 15.478908959s
prepare.go:85
17:45:19.031 INFO tss-lib: Generated pre-params for Server main.go:77
17:45:19.031 INFO tss-lib: party {0,3_server}: ecdsa-keygen round 1 starting party.go:135
17:45:19.031 INFO tss-lib: party {1,3}: ecdsa-keygen round 1 starting party.go:135
17:45:20.546 DEBUG tss-lib: party {0,3_server}: ecdsa-keygen round 1 finished party.go:137
17:45:20.546 DEBUG tss-lib: Broadcasting... main.go:139
17:45:20.547 DEBUG tss-lib: Got a message from %s for %s 3_server 3 main.go:38
17:45:20.612 DEBUG tss-lib: party {1,3}: ecdsa-keygen round 1 finished party.go:137
17:45:20.612 DEBUG tss-lib: Broadcasting... main.go:139
17:45:20.612 DEBUG tss-lib: Got a message from %s for %s 3 3_server main.go:38
17:45:20.612 DEBUG tss-lib: party {1,3} received message: Type: binance.tsslib.ecdsa.keygen.KGRound1Message, From: {0,3_server}, To: all party.go:154
17:45:20.612 DEBUG tss-lib: party {1,3} round 1 update: Type: binance.tsslib.ecdsa.keygen.KGRound1Message, From: {0,3_server}, To: all party.go:156
17:45:20.612 DEBUG tss-lib: party {1,3}: ecdsa-keygen round 1 update party.go:162
17:45:20.612 DEBUG tss-lib: party {0,3_server} received message: Type: binance.tsslib.ecdsa.keygen.KGRound1Message, From: {1,3}, To: all party.go:154
17:45:20.613 DEBUG tss-lib: party {0,3_server} round 1 update: Type: binance.tsslib.ecdsa.keygen.KGRound1Message, From: {1,3}, To: all party.go:156
17:45:20.613 DEBUG tss-lib: party {0,3_server}: ecdsa-keygen round 1 update party.go:162
17:45:21.852 DEBUG tss-lib: Point-to-point... main.go:147
17:45:21.852 DEBUG tss-lib: Got a message from %s for %s 3_server 3_server main.go:38
17:45:21.852 DEBUG tss-lib: Ignored... main.go:42
17:45:21.852 DEBUG tss-lib: Broadcasting... main.go:139
17:45:21.852 DEBUG tss-lib: Got a message from %s for %s 3_server 3 main.go:38
17:45:21.853 INFO tss-lib: party {0,3_server}: ecdsa-keygen round 2 started party.go:172
17:45:21.853 DEBUG tss-lib: party {0,3_server} received message: Type: binance.tsslib.ecdsa.keygen.KGRound1Message, From: {1,3}, To: all party.go:154
17:45:21.853 DEBUG tss-lib: party {0,3_server} round 2 update: Type: binance.tsslib.ecdsa.keygen.KGRound1Message, From: {1,3}, To: all party.go:156
17:45:21.853 DEBUG tss-lib: party {0,3_server}: ecdsa-keygen round 2 update party.go:162
17:45:21.853 DEBUG tss-lib: Point-to-point... main.go:147
17:45:21.853 DEBUG tss-lib: Broadcasting... main.go:139
17:45:21.853 DEBUG tss-lib: Got a message from %s for %s 3 3_server main.go:38
17:45:21.853 DEBUG tss-lib: Got a message from %s for %s 3 3 main.go:38
17:45:21.853 DEBUG tss-lib: Ignored... main.go:42
17:45:21.853 INFO tss-lib: party {1,3}: ecdsa-keygen round 2 started party.go:172
17:45:21.854 DEBUG tss-lib: party {0,3_server} received message: Type: binance.tsslib.ecdsa.keygen.KGRound2Message2, From: {1,3}, To: all party.go:154
17:45:21.854 DEBUG tss-lib: party {0,3_server} round 2 update: Type: binance.tsslib.ecdsa.keygen.KGRound2Message2, From: {1,3}, To: all party.go:156
17:45:21.854 DEBUG tss-lib: party {1,3} received message: Type: binance.tsslib.ecdsa.keygen.KGRound1Message, From: {0,3_server}, To: all party.go:154
17:45:21.854 DEBUG tss-lib: party {1,3} round 2 update: Type: binance.tsslib.ecdsa.keygen.KGRound1Message, From: {0,3_server}, To: all party.go:156
17:45:21.854 DEBUG tss-lib: party {1,3}: ecdsa-keygen round 2 update party.go:162
17:45:21.854 DEBUG tss-lib: party {0,3_server}: ecdsa-keygen round 2 update party.go:162
17:45:21.854 DEBUG tss-lib: party {1,3} received message: Type: binance.tsslib.ecdsa.keygen.KGRound2Message2, From: {0,3_server}, To: all party.go:154
17:45:21.854 DEBUG tss-lib: party {1,3} round 2 update: Type: binance.tsslib.ecdsa.keygen.KGRound2Message2, From: {0,3_server}, To: all party.go:156
17:45:21.854 DEBUG tss-lib: party {1,3}: ecdsa-keygen round 2 update party.go:162
17:46:21.852 DEBUG tss-lib: {1,3} waiting for %s [{0,3_server} {1,3}] main.go:174
17:46:21.853 DEBUG tss-lib: {0,3_server} waiting for %s [{1,3}] main.go:174
17:46:21.853 DEBUG tss-lib: timeout main.go:176
I tried out this example with multiple userIDs and get the similar output
tail
19:49:09.001 DEBUG tss-lib: party {1,3} round 2 update: Type: binance.tsslib.ecdsa.keygen.KGRound2Message2, From: {3,5}, To: all party.go:156
19:49:09.001 DEBUG tss-lib: party {1,3}: ecdsa-keygen round 2 update party.go:162
19:49:09.001 DEBUG tss-lib: party {2,4} received message: Type: binance.tsslib.ecdsa.keygen.KGRound2Message2, From: {3,5}, To: all party.go:154
19:49:09.001 DEBUG tss-lib: party {2,4} round 2 update: Type: binance.tsslib.ecdsa.keygen.KGRound2Message2, From: {3,5}, To: all party.go:156
19:49:09.001 DEBUG tss-lib: party {2,4}: ecdsa-keygen round 2 update party.go:162
19:50:09.001 DEBUG tss-lib: {1,3} waiting for [{0,server} {1,3} {2,4} {3,5}] main.go:193
19:50:09.003 DEBUG tss-lib: {2,4} waiting for [{1,3} {2,4} {3,5}] main.go:193
19:50:09.003 DEBUG tss-lib: {3,5} waiting for [{2,4} {3,5}] main.go:193
19:50:09.003 DEBUG tss-lib: {0,server} waiting for [{3,5}] main.go:193
19:50:09.003 DEBUG tss-lib: timeout main.go:195
Message for itself - in your code you are skipping broadcasts to itself, is that a cause?
Not necessarily. I removed that part and it still was stuck. I copied that part from the test code itself. Did you manage to get this working? Any code sample that you can share?
Yes, I have it working fine. I can not separate some working part from my codes to give an example. But I can recommend these unittests: https://github.com/Kava-Labs/kava-bridge/blob/main/relayer/mp_tss/keygen_test.go / https://github.com/Kava-Labs/kava-bridge/tree/main/relayer/mp_tss which helped me
Closing this as the original question got answered.
I am trying to write a local keygen function for ECDSA. This is based on the test code. I am encountering a (probably stupid) error. The issue seems to arise from the fact that somehow
keygen.NewLocalParty
returns a*keygen.LocalParty
whosetemp
anddata
fields are not available. This is weird because I can see that they are defined. They work correctly on the test case, but not on my code.Any help is appreciated.
go.mod
main.go