From 0b480d4752210cb1fa7afe99fd61e753a12c0a3c Mon Sep 17 00:00:00 2001 From: jonathanMweiss Date: Sun, 8 Dec 2024 11:16:06 +0000 Subject: [PATCH 1/6] lkg init --- node/pkg/tss/implementation_test.go | 27 ++ node/pkg/tss/internal/cmd/README.md | 83 ++++++ node/pkg/tss/internal/cmd/cnfg.json | 38 +++ node/pkg/tss/internal/cmd/lkg.go | 379 ++++++++++++++++++++++++++++ node/pkg/tss/setup_test.go | 302 ---------------------- 5 files changed, 527 insertions(+), 302 deletions(-) create mode 100644 node/pkg/tss/internal/cmd/README.md create mode 100644 node/pkg/tss/internal/cmd/cnfg.json create mode 100644 node/pkg/tss/internal/cmd/lkg.go diff --git a/node/pkg/tss/implementation_test.go b/node/pkg/tss/implementation_test.go index c21a245828..5069a3e4d1 100644 --- a/node/pkg/tss/implementation_test.go +++ b/node/pkg/tss/implementation_test.go @@ -2,10 +2,14 @@ package tss import ( "context" + crand "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" "errors" "fmt" "math/big" "math/rand" + "net" "sync" "testing" "time" @@ -493,6 +497,29 @@ func TestBadInputs(t *testing.T) { }) } +func createX509Cert(dnsName string) *x509.Certificate { + // using random serial number + var serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128) + + serialNumber, err := crand.Int(crand.Reader, serialNumberLimit) + if err != nil { + panic(err) + } + + tmpl := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{Organization: []string{"tsscomm"}}, + SignatureAlgorithm: x509.ECDSAWithSHA256, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * 366 * 40), // valid for > 40 years used for tests... + BasicConstraintsValid: true, + + DNSNames: []string{"localhost", dnsName}, + IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1)}, + } + return &tmpl +} + func TestFetchPartyId(t *testing.T) { a := assert.New(t) engines := load5GuardiansSetupForBroadcastChecks(a) diff --git a/node/pkg/tss/internal/cmd/README.md b/node/pkg/tss/internal/cmd/README.md new file mode 100644 index 0000000000..c521768529 --- /dev/null +++ b/node/pkg/tss/internal/cmd/README.md @@ -0,0 +1,83 @@ +Please read the entire document before running the protocol. + + +# Running 'local' DKG + +The following binary runs the DKG protocol to +generate secrets for guardians to use by the threshold signing scheme (TSS). + +The script expects a config file (similar to the cnfg.json) provided +in this package. +The config file contains a few key fields: +``` +"NumParticipants": int, +"WantedThreshold": int, +"GuardianSpecifics" : array +``` + + + + +Where `NumParticipants` is the number of guardians in the system, +`WantedThreshold` is the wanted threshold (For instance, `NumParticipants=19` and `WantedThreshold=13`). + +The following is an example of the `GuardianSpecifics` array (for a working example, please see `cnfg.json`): + + +``` + "GuardianSpecifics": [ + { + "Identifier": { + "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JS + UgvVENDQmVXZ0F3SUJBZ0lRYUJZRTMvTTA4WEhZQ25OVm1jRkJja + kFOQmdrcWhraUc5dzBCQVFzRkFEQnkKTVFzd0NRWURWUVFHRXdKV + . + . + . + FlscWNPbWVYMXVGbUtiZGkvWG9yR2xrQ29NRjNURHg4cm1wOURCa + UIvCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=" + + }, + "WhereToSaveSecrets": "/Path/To/File/NameWithoutPrefix" + }, + { + "Identifier": {...}, + "WhereToSaveSecrets": "..." + }, + {...}, + . + . + . + ] +``` + +The DKG protocol is used to generate secrets to TSS, +and it assumes a public key infrastructure. +These public keys are x509 certificates (and stored inside `GuardianSpecifics[i].Identifier.TlsX509`), +and are used later by the TSS to establish TLS channels between the participants. +As a result, the x509 certificate provided by you should be self-signed root-level certificates. +In addition, you should safely store the signing key you've used to sign your certificate in a known location ([see after running the protocol](#after-running-the-local-dkg-protocol)) + + +When creating the X509 certificates, be aware that the DNS name you set +in the certificate will be used as the hostname of +servers participating in the TSS protocol. +As a result, please refrain from using hostnames that are +unreachable. + + +# After running the local DKG protocol. + +Once you run the protocol, expect numerous files containing secret keys and +additional configurations. +Each guardian operator should take the file saved by the given name they +provided in the config. + +The file each operator holds should be kept like other files containing secret keys. +This file contains the result og the DKG, before this file is usable, one should provide the signing key used to sign the x509 certificate used by the DKG protocol. + + + + + + diff --git a/node/pkg/tss/internal/cmd/cnfg.json b/node/pkg/tss/internal/cmd/cnfg.json new file mode 100644 index 0000000000..8c6c250e5d --- /dev/null +++ b/node/pkg/tss/internal/cmd/cnfg.json @@ -0,0 +1,38 @@ +{ + "NumParticipants": 5, + "WantedThreshold": 3, + + "GuardianSpecifics": [ + { + "Identifier": { + "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUgvVENDQmVXZ0F3SUJBZ0lRYUJZRTMvTTA4WEhZQ25OVm1jRkJjakFOQmdrcWhraUc5dzBCQVFzRkFEQnkKTVFzd0NRWURWUVFHRXdKVlV6RU9NQXdHQTFVRUNBd0ZWR1Y0WVhNeEVEQU9CZ05WQkFjTUIwaHZkWE4wYjI0eApFVEFQQmdOVkJBb01DRk5UVENCRGIzSndNUzR3TEFZRFZRUUREQ1ZUVTB3dVkyOXRJRVZXSUZOVFRDQkpiblJsCmNtMWxaR2xoZEdVZ1EwRWdVbE5CSUZJek1CNFhEVEl3TURRd01UQXdOVGd6TTFvWERUSXhNRGN4TmpBd05UZ3oKTTFvd2diMHhDekFKQmdOVkJBWVRBbFZUTVE0d0RBWURWUVFJREFWVVpYaGhjekVRTUE0R0ExVUVCd3dIU0c5MQpjM1J2YmpFUk1BOEdBMVVFQ2d3SVUxTk1JRU52Y25BeEZqQVVCZ05WQkFVVERVNVdNakF3T0RFMk1UUXlORE14CkZEQVNCZ05WQkFNTUMzZDNkeTV6YzJ3dVkyOXRNUjB3R3dZRFZRUVBEQlJRY21sMllYUmxJRTl5WjJGdWFYcGgKZEdsdmJqRVhNQlVHQ3lzR0FRUUJnamM4QWdFQ0RBWk9aWFpoWkdFeEV6QVJCZ3NyQmdFRUFZSTNQQUlCQXhNQwpWVk13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRREhoZVJrYmIxRkNjN3hSS3N0CndLMEpJR2FLWTh0N0piUzJiUTJiNllJSkRnbkh1SVlIcUJyQ1VWNzlvZWxpa2tva1JrRnZjdnBhS2luRkhEUUgKVXBXRUk2UlVFUlltU0NnM084V2k0MnVPY1YyQjVaYWJtWENrd2R4WTVFY2w1MUJiTThVbkdkb0FHYmRObWlSbQpTbVRqY3MrbGhNeGc0ZkZZNmxCcGlFVkZpR1VqR1JSKzYxUjY3THo2VTRLSmVMTmNDbTA3UXdGWUtCbXBpMDhnCmR5Z1N2UmRVdzU1Sm9wcmVkaitWR3RqVWtCNGhGVDRHUVgvZ2h0NjlSbHF6Lys4dTBkRVFraHVVdXVjcnFhbG0KU0d5NDNIUndCZkRLRndZZVdNN0NQTWQ1ZS9kTyt0MDh0OFBianpWVFR2NWhRRENzRVlJVjJUN0FGSTlTY054TQpraDcvQWdNQkFBR2pnZ05CTUlJRFBUQWZCZ05WSFNNRUdEQVdnQlMvd1ZxSC95ajZRVDM5dDAva0hhK2dZVmdwCnZUQi9CZ2dyQmdFRkJRY0JBUVJ6TUhFd1RRWUlLd1lCQlFVSE1BS0dRV2gwZEhBNkx5OTNkM2N1YzNOc0xtTnYKYlM5eVpYQnZjMmwwYjNKNUwxTlRUR052YlMxVGRXSkRRUzFGVmkxVFUwd3RVbE5CTFRRd09UWXRVak11WTNKMApNQ0FHQ0NzR0FRVUZCekFCaGhSb2RIUndPaTh2YjJOemNITXVjM05zTG1OdmJUQWZCZ05WSFJFRUdEQVdnZ3QzCmQzY3VjM05zTG1OdmJZSUhjM05zTG1OdmJUQmZCZ05WSFNBRVdEQldNQWNHQldlQkRBRUJNQTBHQ3lxRWFBR0cKOW5jQ0JRRUJNRHdHRENzR0FRUUJncWt3QVFNQkJEQXNNQ29HQ0NzR0FRVUZCd0lCRmg1b2RIUndjem92TDNkMwpkeTV6YzJ3dVkyOXRMM0psY0c5emFYUnZjbmt3SFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdJR0NDc0dBUVVGCkJ3TUJNRWdHQTFVZEh3UkJNRDh3UGFBN29EbUdOMmgwZEhBNkx5OWpjbXh6TG5OemJDNWpiMjB2VTFOTVkyOXQKTFZOMVlrTkJMVVZXTFZOVFRDMVNVMEV0TkRBNU5pMVNNeTVqY213d0hRWURWUjBPQkJZRUZBREFGVUlhenc1cgpaSUhhcG5SeElVbnB3K0dMTUE0R0ExVWREd0VCL3dRRUF3SUZvRENDQVgwR0Npc0dBUVFCMW5rQ0JBSUVnZ0Z0CkJJSUJhUUZuQUhjQTlseVVMOUYzTUNJVVZCZ0lNSlJXanVOTkV4a3p2OThNTHlBTHpFN3haT01BQUFGeE0waG8KYndBQUJBTUFTREJHQWlFQTZ4ZWxpTlI4R2svNjNwWWRuUy92T3gvQ2pwdEVNRXY4OVdXaDEvdXJXSUVDSVFEeQpCcmVIVTI1RHp3dWtRYVJRandXNjU1WkxrcUNueGJ4UVdSaU9lbWo5SkFCMUFKUWd2QjZPMVkxc2lITWZnb3NpCkxBM1IyazFlYkUrVVBXSGJUaTlZVGFMQ0FBQUJjVE5JYU53QUFBUURBRVl3UkFJZ0dSRTR3emFiTlJkRDhrcS8KdkZQM3RRZTJobTB4NW5YdWxvd2g0SWJ3M2xrQ0lGWWIvM2xTRHBsUzdBY1I0citYcFd0RUtTVEZXSm1OQ1JiYwpYSnVyMlJHQkFIVUE3c0NWN28xeVpBK1M0OE81RzhjU28ybHFDWHRMYWhvVU9PWkhzc3Z0eGZrQUFBRnhNMGhvCjh3QUFCQU1BUmpCRUFpQjZJdmJvV3NzM1I0SXRWd2plYmw3RDN5b0ZhWDBORGgyZFdoaGd3Q3hySHdJZ0NmcTcKb2NNQzV0KzFqaTVNNXhhTG1QQzRJK1dYM0kvQVJrV1N5aU83SVFjd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQgpBQ2V1dXI0UW51anFtZ3VTckhVM21oZitjSm9kelRRTnFvNHRkZStQRDEvZUZkWUFFTHU4eEYrMEF0N3hKaVBZCmk1Ukt3aWx5UDU2diszaVkyVDlsdzdTOFRKMDQxVkxoYUlLcDE0TXpTVXpSeWVvT0FzSjdRQURNQ2xIS1VEbEgKVVUycE51bzg4WTZpZ292VDNic253Sk5pRVFOcXltU1NZaGt0dzB0YWR1b3FqcVhuMDZnc1Zpb1dUVkRYeXNkNQpxRXg0dDZzSWdJY01tMjZZSDF2SnBDUUVoS3BjMnkwN2dSa2tsQlpSdE1qVGh2NGNYeXlNWDd1VGNkVDdBSkJQCnVlaWZDb1YyNUp4WHVvOGQ1MTM5Z3dQMUJBZTdJQlZQeDJ1N0tOL1V5T1hkWm13TWYvVG1GR3dEZENmc3lIZi8KWnNCMndMSG96VFlvQVZtUTlGb1UxSkxnY1ZpdnFKK3ZObEJoSFhobHhNZE4wajgwUjlOejZFSWdsUWplSzNPOApJL2NGR20vQjgrNDJoT2xDSWQ5WmR0bmRKY1JKVmppMHdEMHF3ZXZDYWZBOWpKbEh2L2pzRStJOVV6NmNwQ3loCnN3K2xyRmR4VWdxVTU4YXhxZUs4OUZSK05vNHEwSUlPK0ppMXJKS3I5bmtTQjBCcVhvelZuRTFZQi9LTHZkSXMKdVlaSnVxYjJwS2t1K3p6VDZnVXdIVVRadkJpTk90WEw0Tnh3Yy9LVDdXek9TZDJ3UDEwUUk4REtnNHZmaU5EcwpIV21CMWM0S2ppNmdPZ0E1dVNVemFHbXEvdjRWbmNLNVVyK245TGJmbmZMYzI4SjVmdC9Hb3Rpbk15RGszaWFyCkYxMFlscWNPbWVYMXVGbUtiZGkvWG9yR2xrQ29NRjNURHg4cm1wOURCaUIvCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=" + }, + "WhereToSaveSecrets": "Alex" + }, + { + "Identifier": { + "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJvVENDQVVlZ0F3SUJBZ0lRVkNTcndsY1hnWnJrTWRzbFYwamk1VEFLQmdncWhrak9QUVFEQWpBU01SQXcKRGdZRFZRUUtFd2QwYzNOamIyMXRNQ0FYRFRJME1Ea3lNakEzTVRjeU1sb1lEekl3TmpReE1ESXlNRGN4TnpJeQpXakFTTVJBd0RnWURWUVFLRXdkMGMzTmpiMjF0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFCkhXd3B0YWk2WGRidW5JSmR2cUc2QTZMU3pTSFZRSkNoYWU3ZkNLNnR3ZlhvSFdMVE1jeklaa2RzMTZHZnh3Sy8KY1JFbUM4Y2JsYytsREFFcVIzR0UzcU45TUhzd0RnWURWUjBQQVFIL0JBUURBZ0tFTUIwR0ExVWRKUVFXTUJRRwpDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVdCQlRMCmtJSU95R2p4bGNIaHRnbWFxNm9PZS92WmhEQWFCZ05WSFJFRUV6QVJnZ2xzYjJOaGJHaHZjM1NIQkg4QUFBRXcKQ2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnUkVUSEhyZXNhRndoOW1udm9UZWNlNGFoWGJBWnFnSmFwVWdDSTF0YgovTXNDSVFDTVM4M25hRGNTL2lNVkc2Y3pqT3JiQnkyT3ZITnc5YUhDSm04V29MUWhDZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + }, + "WhereToSaveSecrets": "Sierra" + }, + { + "Identifier": { + "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJvVENDQVVpZ0F3SUJBZ0lSQUlxZ2NqN29zeWg3Y0VZb1RtdTB4cTB3Q2dZSUtvWkl6ajBFQXdJd0VqRVEKTUE0R0ExVUVDaE1IZEhOelkyOXRiVEFnRncweU5EQTVNakl3TnpFM01qSmFHQTh5TURZME1UQXlNakEzTVRjeQpNbG93RWpFUU1BNEdBMVVFQ2hNSGRITnpZMjl0YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBCkJFOFQvanhieEVHZHFDQnFDNUQ4RDBPa0NXeSthMHJqQVUxRHJaYmxyWVFlUktYbHdLWXdGa2pOVjZNVlBROUIKbjFtcG9hNitIMmhJRnZudnNEdjAyVFdqZlRCN01BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVQpCZ2dyQmdFRkJRY0RBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVCkpya1E4ZzA4WDVFcGI4T1JsalUyb2l0WTJMd3dHZ1lEVlIwUkJCTXdFWUlKYkc5allXeG9iM04waHdSL0FBQUIKTUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJ1VnA3VE9xZXBlOEpvSnZxQTk2bnFIYzVHME9ucHZQa0t6dzJucgo2d3ExQWlCSXlJaHlpL0xVK1RWUDd3Z2JJVXpjMlJXeXZpSklDL0h0YW1ua3FxYWQ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + }, + "WhereToSaveSecrets": "Veronica" + + }, + { + "Identifier": { + "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJvakNDQVVpZ0F3SUJBZ0lSQUxieVduSHQ2aHpRaDZMb2Q5bzBQemt3Q2dZSUtvWkl6ajBFQXdJd0VqRVEKTUE0R0ExVUVDaE1IZEhOelkyOXRiVEFnRncweU5EQTVNakl3TnpFM01qSmFHQTh5TURZME1UQXlNakEzTVRjeQpNbG93RWpFUU1BNEdBMVVFQ2hNSGRITnpZMjl0YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBCkJGTk9sRHkvRS8wOERtRHdzMVVwaVh5TGV3UkJBUEYvUXRQbm5GR0dvcS9aeFNtZDM2U08vNGs0TnRkWFFKdkEKS05SOVpZNklmclRYUDloNTZOWVlLSTJqZlRCN01BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVQpCZ2dyQmdFRkJRY0RBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVClF4R3ZBOHVNTjF5NUFRRGMweTc2QjMrQ256OHdHZ1lEVlIwUkJCTXdFWUlKYkc5allXeG9iM04waHdSL0FBQUIKTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSUdSUS9UdTRFQWtZRFhtWW5LeHRnR0JlQjhYT2ZIa2dOWGhGM1NXTApyRzQ2QWlFQXpHTzJlWklmenVlQytFQ05XWXBzdkFwK2F0emxXQlNkNmVUdDdKZGMwczQ9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + }, + "WhereToSaveSecrets": "Jameson" + }, + { + "Identifier": { + "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJvakNDQVVlZ0F3SUJBZ0lRUXg2NUhRRjB0Q3I2VmxVWXo2VWEzekFLQmdncWhrak9QUVFEQWpBU01SQXcKRGdZRFZRUUtFd2QwYzNOamIyMXRNQ0FYRFRJME1Ea3lNakEzTVRjeU1sb1lEekl3TmpReE1ESXlNRGN4TnpJeQpXakFTTVJBd0RnWURWUVFLRXdkMGMzTmpiMjF0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFCit5ZlV2ZVBvMG1zZGxLS0FwcDM4TzR4ckJzRGN2cEFRblhmSUFDQk1ycjIzU056QnhFWVYwOGZYZ1Z2dXVGSkQKRTRRc29CRzdSb2lBZ3ZGWk5Rb055cU45TUhzd0RnWURWUjBQQVFIL0JBUURBZ0tFTUIwR0ExVWRKUVFXTUJRRwpDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVdCQlJMCnByNHdWZ0FEeVVNZXNiVVJFWWJ3N215bDB6QWFCZ05WSFJFRUV6QVJnZ2xzYjJOaGJHaHZjM1NIQkg4QUFBRXcKQ2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQVBVejY3Q3lKb0lLclNDSlJQcCtNQktFWkkvUTFtK3JlS0RqYzNBVQpXZkhBQWlFQWxIOXpJZjNoZ2hBS3dCcCt1MlB6L05TLzZYSm96UGQ5ZFpnR1dqeHdSM2c9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + }, + "WhereToSaveSecrets": "Riad" + } + ] +} \ No newline at end of file diff --git a/node/pkg/tss/internal/cmd/lkg.go b/node/pkg/tss/internal/cmd/lkg.go new file mode 100644 index 0000000000..95f01ed62c --- /dev/null +++ b/node/pkg/tss/internal/cmd/lkg.go @@ -0,0 +1,379 @@ +package main + +import ( + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "flag" + "fmt" + "math/big" + "net" + "os" + "time" + + engine "github.com/certusone/wormhole/node/pkg/tss" + "github.com/certusone/wormhole/node/pkg/tss/internal" + + "github.com/yossigi/tss-lib/v2/ecdsa/keygen" + "github.com/yossigi/tss-lib/v2/tss" +) + +var dkgLocation = flag.String("cnfg", "", "path to the dkg config file in json format") + +func main() { + flag.Parse() + + if *dkgLocation == "" { + flag.PrintDefaults() + + return + } + + f, err := os.ReadFile(*dkgLocation) + if err != nil { + fmt.Println("failed to read file, err: ", err) + + return + } + + cnfg := &DKGConfig{} + err = json.Unmarshal(f, cnfg) + if err != nil { + fmt.Println("failed to unmarshal config, err: ", err) + + return + } + + Run(cnfg) +} + +// make a json file with the following content: +type DKGConfig struct { + NumParticipants int + WantedThreshold int // should be non inclusive. That is, if you have n=19,f=6, then threshold=12 (13 guardians needed to sign). + + GuardianSpecifics []GuardianSpecifics +} + +type GuardianSpecifics struct { + Identifier Identifier + WhereToSaveSecrets string // where to save the secrets of this guardian. +} +type Identifier struct { + // Self Signed, CA level cert. + TlsX509 engine.PEM // PEM Encoded (see certs.go). Note, you must have the private key of this cert later. +} + +type dkgPlayer struct { + *tss.PartyID + + whereToStore string + + //generated from the secretKey. + + // sorted according to theIdToPIDMapping. + peerCerts []engine.PEM + selfCert []byte + + // same for all guardians // generated here. + loadDistributionKey []byte + + *tss.PeerContext + *tss.Parameters + idToPidMapping map[string]*tss.PartyID + + localParty tss.Party + + // communication channels + out <-chan tss.Message + protocolEndOutput <-chan *keygen.LocalPartySaveData +} + +func Run(cnfg *DKGConfig) { + if cnfg == nil { + panic("config is nil") + } + + // ensuring the threshold matches what the library expects. + // (if n=5,f=1 and we want 2f+1 committees, then WantedThreshold should be equal to 2) + cnfg.WantedThreshold -= 1 + + fmt.Println("Setting up player secrets. This might take a while...") + all, err := setupPlayers(cnfg) + if err != nil { + panic(err) + } + + for _, p := range all { + if err := p.localParty.Start(); err != nil && err.Cause() != nil { + panic("keygen failed to start: " + err.Cause().Error()) + } + } + + fmt.Println("all players generated their secrets. Starting the protocol. This might take several minutes.") + simulateDKG(all) +} + +func mustPassMessage(newMsg tss.Message, keyToParty map[string]tss.Party) { + bz, routing, err := newMsg.WireBytes() + if err != nil { + panic("Couldn't pass message to party. err: " + err.Error()) + } + + // parsedMsg doesn't contain routing, since it assumes this message arrive for this participant from outside. + // as a result we'll use the routing of the wireByte msgs. + parsedMsg, err := tss.ParseWireMessage(bz, routing.From, routing.IsBroadcast) + if err != nil { + panic("Couldn't pass message to party. err: " + err.Error()) + } + + if routing.IsBroadcast || routing.To == nil { + for pID, p := range keyToParty { + if string(routing.From.GetKey()) == pID { + continue + } + + mustFeedParty(p, parsedMsg) + } + + return + } + + for _, id := range routing.To { + p := keyToParty[string(id.GetKey())] + mustFeedParty(p, parsedMsg) + } +} + +func mustFeedParty(p tss.Party, parsedMsg tss.ParsedMessage) { + if p == nil { + panic("party is nil") + } + if parsedMsg == nil { + panic("parsedMsg is nil") + } + + ok, err := p.Update(parsedMsg) + if err != nil { + panic("Couldn't pass message to party. err: " + err.Error()) + } + + if !ok { + panic("Couldn't update party with message") + } +} + +func simulateDKG(all []*dkgPlayer) { + done := 0 + + keyToParty := map[string]tss.Party{} + for _, player := range all { + keyToParty[string(player.PartyID.GetKey())] = player.localParty + } + + guardians := make([]*engine.GuardianStorage, len(all)) +keygenLoop: + for { + bagOfMessages := make([]tss.Message, 0, len(all)) + for _, player := range all { + select { + case newMsg := <-player.out: + bagOfMessages = append(bagOfMessages, newMsg) + + case m := <-player.protocolEndOutput: + player.handleKeygenEndMessage(m, guardians) + done += 1 + fmt.Println(done) + + default: // avoid blockage. + } + + if done >= len(all) { + break keygenLoop + } + } + + if len(bagOfMessages) > 0 { + fmt.Println("passing messages to guardians", len(bagOfMessages)) + } + for _, msg := range bagOfMessages { + mustPassMessage(msg, keyToParty) + } + } + + fmt.Println("All guardians have finished the protocol. Saving the secrets to disk.") + + for i, guardian := range guardians { + if guardian == nil { + panic(fmt.Sprintf("error in script. Guardian[%d] is nil", i)) + } + + bts, err := json.MarshalIndent(guardian, "", " ") + if err != nil { + panic("") + } + + fname := fmt.Sprintf("%s.json", all[i].whereToStore) + + err = os.WriteFile(fname, bts, 0777) + if err != nil { + panic("Failed to write to disk") + } + } + +} + +func (cnfg *DKGConfig) find(tlsX509 []byte) *GuardianSpecifics { + for _, g := range cnfg.GuardianSpecifics { + if string(g.Identifier.TlsX509) == string(tlsX509) { + return &g + } + } + + return nil +} + +func (cnfg *DKGConfig) validate() error { + if cnfg.NumParticipants < 1 { + return fmt.Errorf("number of participants should be at least 1") + } + + if len(cnfg.GuardianSpecifics) != cnfg.NumParticipants { + return fmt.Errorf("number of guardian identifiers should be equal to number of participants") + } + + if cnfg.WantedThreshold >= cnfg.NumParticipants-1 { + return fmt.Errorf("threshold should be less than number of participants") + } + + return nil +} + +func setupPlayers(cnfg *DKGConfig) ([]*dkgPlayer, error) { + if err := cnfg.validate(); err != nil { + return nil, err + } + + loadBalancingKey := make([]byte, 32) + _, err := rand.Read(loadBalancingKey) + if err != nil { + return nil, err + } + + partyIDS := make(tss.UnSortedPartyIDs, cnfg.NumParticipants) + + for i, dt := range cnfg.GuardianSpecifics { + crt, err := internal.PemToCert(dt.Identifier.TlsX509) + if err != nil { + return nil, err + } + + if len(crt.DNSNames) == 0 { + return nil, fmt.Errorf("expected DNS names in the cert") + } + + partyIDS[i] = &tss.PartyID{ + MessageWrapper_PartyID: &tss.MessageWrapper_PartyID{ + Id: string(crt.DNSNames[0]), + Moniker: "", + Key: dt.Identifier.TlsX509, + }, + Index: -1, // not known until sorted + } + } + + sortedPIDs := tss.SortPartyIDs(partyIDS) + idToPID := map[string]*tss.PartyID{} + for _, pid := range sortedPIDs { + idToPID[pid.Id] = pid + } + + all := make([]*dkgPlayer, cnfg.NumParticipants) + + peerCerts := make([]engine.PEM, cnfg.NumParticipants) + + for _, pid := range sortedPIDs { + peerCerts[pid.Index] = pid.Key + + tmp := make([]byte, 32) + copy(tmp, loadBalancingKey) + + peerContext := tss.NewPeerContext(sortedPIDs) + + all[pid.Index] = &dkgPlayer{ + PartyID: pid, + peerCerts: peerCerts, + loadDistributionKey: tmp, + PeerContext: peerContext, + Parameters: tss.NewParameters(tss.S256(), peerContext, pid, cnfg.NumParticipants, cnfg.WantedThreshold), + idToPidMapping: idToPID, + + out: make(<-chan tss.Message), + protocolEndOutput: make(<-chan *keygen.LocalPartySaveData), + + whereToStore: cnfg.find(pid.Key).WhereToSaveSecrets, + + localParty: nil, + } + + all[pid.Index].setNewKeygenHandler() + } + + return all, nil +} + +func createX509Cert(dnsName string) *x509.Certificate { + // using random serial number + var serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128) + + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + panic(err) + } + + tmpl := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{Organization: []string{"tsscomm"}}, + SignatureAlgorithm: x509.ECDSAWithSHA256, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * 366 * 40), // valid for > 40 years used for tests... + BasicConstraintsValid: true, + + DNSNames: []string{"localhost", dnsName}, + IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1)}, + } + return &tmpl +} + +func (player *dkgPlayer) setNewKeygenHandler() { + n := len(player.peerCerts) + out := make(chan tss.Message, n*n*2) // ready for at least n^2 messages. + endOut := make(chan *keygen.LocalPartySaveData, 1) // ready for at least a single message. + + player.localParty = keygen.NewLocalParty(player.Parameters, out, endOut) + player.out = out + player.protocolEndOutput = endOut +} + +func (player *dkgPlayer) handleKeygenEndMessage(m *keygen.LocalPartySaveData, guardians []*engine.GuardianStorage) { + i, err := m.OriginalIndex() + if err != nil { + panic(err) + } + + guardians[i] = &engine.GuardianStorage{ + Self: player.PartyID, + + Guardians: player.PeerContext.IDs(), + + TlsX509: engine.PEM(player.Id), + PrivateKey: nil, // each guardian should load this by themselves. + + GuardianCerts: player.peerCerts, + + Threshold: player.Threshold(), + SavedSecretParameters: m, + LoadDistributionKey: player.loadDistributionKey, + } +} diff --git a/node/pkg/tss/setup_test.go b/node/pkg/tss/setup_test.go index f319e58371..329378cc08 100644 --- a/node/pkg/tss/setup_test.go +++ b/node/pkg/tss/setup_test.go @@ -1,27 +1,9 @@ package tss import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/x509" - "crypto/x509/pkix" - "encoding/json" - "fmt" - "math/big" - "net" - "os" - "sort" - "strconv" - "strings" "testing" - "time" "github.com/certusone/wormhole/node/pkg/internal/testutils" - "github.com/certusone/wormhole/node/pkg/tss/internal" - "github.com/stretchr/testify/assert" - "github.com/yossigi/tss-lib/v2/ecdsa/keygen" - "github.com/yossigi/tss-lib/v2/tss" ) const ( @@ -29,31 +11,6 @@ const ( Threshold = 2 // not including, meaning 3 guardians are needed to sign. ) -type dkgSetupPlayer struct { - secretKey *ecdsa.PrivateKey - *tss.PartyID - - //generated from the secretKey. - - // sorted according to theIdToPIDMapping. - peerCerts []PEM - tlsPEM PEM - tlsPrivateKey PEM - - //same for all guardians - LoadDistributionKey []byte - - *tss.PeerContext - *tss.Parameters - IdToPIDmapping map[string]*tss.PartyID - - LocalParty tss.Party - - // communication channels - Out <-chan tss.Message - ProtocolEndOutput <-chan *keygen.LocalPartySaveData -} - func TestGuardianStorageUnmarshal(t *testing.T) { var st GuardianStorage err := st.load(testutils.MustGetMockGuardianTssStorage()) @@ -61,262 +18,3 @@ func TestGuardianStorageUnmarshal(t *testing.T) { t.Error(err) } } - -func TestSetUpGroup(t *testing.T) { - t.SkipNow() // manual test only. - a := assert.New(t) - - all := setupPlayers(a) - - for _, player := range all { - p := player - if err := p.LocalParty.Start(); err != nil && err.Cause() != nil { - a.Fail("keygen failed to start: " + err.Cause().Error()) - } - } - - fmt.Println("Setup done. Staring DKG") - runDKG(a, all) -} - -func passMsg(a *assert.Assertions, newMsg tss.Message, idToParty map[string]tss.Party) { - bz, routing, err := newMsg.WireBytes() - a.NoError(err) - // parsedMsg doesn't contain routing, since it assumes this message arrive for this participant from outside. - // as a result we'll use the routing of the wireByte msgs. - parsedMsg, err := tss.ParseWireMessage(bz, routing.From, routing.IsBroadcast) - a.NoError(err) - - if routing.IsBroadcast || routing.To == nil { - for pID, p := range idToParty { - if routing.From.GetId() == pID { - continue - } - ok, err := p.Update(parsedMsg) - a.True(ok, err.Error()) - - } - - return - } - - for _, id := range routing.To { - p := idToParty[id.Id] - ok, err := p.Update(parsedMsg) - a.True(ok, err.Error()) - } -} - -func runDKG(a *assert.Assertions, all []*dkgSetupPlayer) { - done := 0 - - idToFullPlayer := map[string]tss.Party{} - for _, player := range all { - idToFullPlayer[player.PartyID.Id] = player.LocalParty - } - - guardians := make([]*GuardianStorage, Participants) -keygenLoop: - for { - bagOfMessages := make([]tss.Message, 0, Participants) - for _, player := range all { - select { - case newMsg := <-player.Out: - bagOfMessages = append(bagOfMessages, newMsg) - - case m := <-player.ProtocolEndOutput: - player.handleKeygenEndMessage(m, guardians) - done += 1 - - case <-time.Tick(time.Millisecond * 500): - fmt.Println("ticked") - } - - if done >= Participants { - break keygenLoop - } - } - - for _, msg := range bagOfMessages { - passMsg(a, msg, idToFullPlayer) - } - } - - for i, guardian := range guardians { - a.NotNil(guardian) - - bts, err := json.MarshalIndent(guardian, "", " ") - a.NoError(err) - fmt.Println(string(bts)) - - fname, err := testutils.GetMockGuardianTssStorage(i) - a.NoError(err) - - // fname := fmt.Sprintf("%s.json", strings.Split(guardian.Self.Id, ":")[0]) - err = os.WriteFile(fname, bts, 0777) - a.NoError(err) - } - -} - -func setupPlayers(a *assert.Assertions) []*dkgSetupPlayer { - - orderedKeysByPublicKey := getOrderedKeys(a) - - return genPlayers(orderedKeysByPublicKey) -} - -// var listOfGuardians = []string{ -// "t-gcp-threshsignnet-asia-01.gcp.testnet.xlabs.xyz", -// "t-gcp-threshsignnet-usw-01.gcp.testnet.xlabs.xyz", -// "t-gcp-threshsignnet-use-01.gcp.testnet.xlabs.xyz", -// "t-gcp-threshsignnet-euc-01.gcp.testnet.xlabs.xyz", -// "t-gcp-threshsignnet-euw-01.gcp.testnet.xlabs.xyz", -// } - -func genPlayers(orderedKeysByPublicKey []*ecdsa.PrivateKey) []*dkgSetupPlayer { - all := make([]*dkgSetupPlayer, Participants) - partyIDS := make(tss.UnSortedPartyIDs, Participants) - for i := 0; i < Participants; i++ { - pnm := strconv.Itoa(i) - pk, err := internal.PublicKeyToPem(&orderedKeysByPublicKey[i].PublicKey) - if err != nil { - panic(err) - } - partyIDS[i] = &tss.PartyID{ - MessageWrapper_PartyID: &tss.MessageWrapper_PartyID{ - // Id: fmt.Sprintf("%s:%v", listOfGuardians[i], 8998), - Id: pnm, - Moniker: pnm, - Key: pk, - }, - Index: -1, // not known until sorted - } - - all[i] = &dkgSetupPlayer{ - secretKey: orderedKeysByPublicKey[i], - PartyID: partyIDS[i], - PeerContext: nil, // known only all player IDs are known. - Parameters: nil, - IdToPIDmapping: nil, - } - } - - sortedPartyIDS := tss.SortPartyIDs(partyIDS) - IdToPIDmapping := map[string]*tss.PartyID{} - - for _, player := range all { - IdToPIDmapping[player.PartyID.Id] = player.PartyID - } - - loadBalancingKey := make([]byte, 32) - _, err := rand.Read(loadBalancingKey) - if err != nil { - panic(err) - } - - x509Certs := make([]PEM, len(sortedPartyIDS)) - for i, player := range all { - player.PeerContext = tss.NewPeerContext(sortedPartyIDS) - player.Parameters = tss.NewParameters(tss.S256(), player.PeerContext, player.PartyID, Participants, Threshold) - player.IdToPIDmapping = IdToPIDmapping - - tmpl := createX509Cert(strings.Split(player.Id, ":")[0]) - - x509 := internal.NewTLSCredentials(player.secretKey, tmpl) - x509Certs[i] = internal.CertToPem(x509) - - player.peerCerts = x509Certs - player.tlsPEM = internal.CertToPem(x509) - player.tlsPrivateKey = internal.PrivateKeyToPem(player.secretKey) - - tmp := make([]byte, 32) - copy(tmp, loadBalancingKey) - player.LoadDistributionKey = tmp - - player.setNewKeygenHandler() - } - return all -} - -func createX509Cert(dnsName string) *x509.Certificate { - // using random serial number - var serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128) - - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - panic(err) - } - - tmpl := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{Organization: []string{"tsscomm"}}, - SignatureAlgorithm: x509.ECDSAWithSHA256, - NotBefore: time.Now(), - NotAfter: time.Now().Add(time.Hour * 24 * 366 * 40), // valid for > 40 years used for tests... - BasicConstraintsValid: true, - - DNSNames: []string{"localhost", dnsName}, - IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1)}, - } - return &tmpl -} - -func getOrderedKeys(a *assert.Assertions) []*ecdsa.PrivateKey { - orderedKeysByPublicKey := make([]*ecdsa.PrivateKey, Participants) - for i := range orderedKeysByPublicKey { - sk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - a.NoError(err) - - orderedKeysByPublicKey[i] = sk - - } - sort.Slice(orderedKeysByPublicKey, func(i, j int) bool { - pk1, err := internal.PublicKeyToPem(&orderedKeysByPublicKey[i].PublicKey) - a.NoError(err) - pk2, err := internal.PublicKeyToPem(&orderedKeysByPublicKey[j].PublicKey) - a.NoError(err) - - ibts := string(pk1) - jbts := string(pk2) - return ibts < jbts - }) - return orderedKeysByPublicKey -} - -func (player *dkgSetupPlayer) setNewKeygenHandler() { - out := make(chan tss.Message, Participants) - endOut := make(chan *keygen.LocalPartySaveData, 1) // ready for at least a single message. - - player.LocalParty = keygen.NewLocalParty(player.Parameters, out, endOut) - player.Out = out - player.ProtocolEndOutput = endOut -} - -func (player *dkgSetupPlayer) handleKeygenEndMessage(m *keygen.LocalPartySaveData, guardians []*GuardianStorage) { - i, err := m.OriginalIndex() - if err != nil { - panic(err) - } - - guardians[i] = &GuardianStorage{ - Self: player.PartyID, - - Guardians: player.PeerContext.IDs(), - - TlsX509: player.tlsPEM, - PrivateKey: player.tlsPrivateKey, - - GuardianCerts: player.peerCerts, - - Threshold: Threshold, - SavedSecretParameters: m, - LoadDistributionKey: player.LoadDistributionKey, - signingKey: &ecdsa.PrivateKey{}, - - Configurations: Configurations{ - MaxSignerTTL: defaultMaxSignerTTL, - DelayGraceTime: defaultDelayGraceTime, - }, - } -} From f029e55e28767e3afe280443c9387d461642bf1c Mon Sep 17 00:00:00 2001 From: jonathanMweiss Date: Mon, 16 Dec 2024 07:46:43 +0000 Subject: [PATCH 2/6] fx: names --- .../tss/internal/cmd/{cnfg.json => cnfg.example.json} | 10 +++++----- node/pkg/tss/internal/cmd/lkg.go | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) rename node/pkg/tss/internal/cmd/{cnfg.json => cnfg.example.json} (97%) diff --git a/node/pkg/tss/internal/cmd/cnfg.json b/node/pkg/tss/internal/cmd/cnfg.example.json similarity index 97% rename from node/pkg/tss/internal/cmd/cnfg.json rename to node/pkg/tss/internal/cmd/cnfg.example.json index 8c6c250e5d..e7b21bf25f 100644 --- a/node/pkg/tss/internal/cmd/cnfg.json +++ b/node/pkg/tss/internal/cmd/cnfg.example.json @@ -7,32 +7,32 @@ "Identifier": { "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUgvVENDQmVXZ0F3SUJBZ0lRYUJZRTMvTTA4WEhZQ25OVm1jRkJjakFOQmdrcWhraUc5dzBCQVFzRkFEQnkKTVFzd0NRWURWUVFHRXdKVlV6RU9NQXdHQTFVRUNBd0ZWR1Y0WVhNeEVEQU9CZ05WQkFjTUIwaHZkWE4wYjI0eApFVEFQQmdOVkJBb01DRk5UVENCRGIzSndNUzR3TEFZRFZRUUREQ1ZUVTB3dVkyOXRJRVZXSUZOVFRDQkpiblJsCmNtMWxaR2xoZEdVZ1EwRWdVbE5CSUZJek1CNFhEVEl3TURRd01UQXdOVGd6TTFvWERUSXhNRGN4TmpBd05UZ3oKTTFvd2diMHhDekFKQmdOVkJBWVRBbFZUTVE0d0RBWURWUVFJREFWVVpYaGhjekVRTUE0R0ExVUVCd3dIU0c5MQpjM1J2YmpFUk1BOEdBMVVFQ2d3SVUxTk1JRU52Y25BeEZqQVVCZ05WQkFVVERVNVdNakF3T0RFMk1UUXlORE14CkZEQVNCZ05WQkFNTUMzZDNkeTV6YzJ3dVkyOXRNUjB3R3dZRFZRUVBEQlJRY21sMllYUmxJRTl5WjJGdWFYcGgKZEdsdmJqRVhNQlVHQ3lzR0FRUUJnamM4QWdFQ0RBWk9aWFpoWkdFeEV6QVJCZ3NyQmdFRUFZSTNQQUlCQXhNQwpWVk13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRREhoZVJrYmIxRkNjN3hSS3N0CndLMEpJR2FLWTh0N0piUzJiUTJiNllJSkRnbkh1SVlIcUJyQ1VWNzlvZWxpa2tva1JrRnZjdnBhS2luRkhEUUgKVXBXRUk2UlVFUlltU0NnM084V2k0MnVPY1YyQjVaYWJtWENrd2R4WTVFY2w1MUJiTThVbkdkb0FHYmRObWlSbQpTbVRqY3MrbGhNeGc0ZkZZNmxCcGlFVkZpR1VqR1JSKzYxUjY3THo2VTRLSmVMTmNDbTA3UXdGWUtCbXBpMDhnCmR5Z1N2UmRVdzU1Sm9wcmVkaitWR3RqVWtCNGhGVDRHUVgvZ2h0NjlSbHF6Lys4dTBkRVFraHVVdXVjcnFhbG0KU0d5NDNIUndCZkRLRndZZVdNN0NQTWQ1ZS9kTyt0MDh0OFBianpWVFR2NWhRRENzRVlJVjJUN0FGSTlTY054TQpraDcvQWdNQkFBR2pnZ05CTUlJRFBUQWZCZ05WSFNNRUdEQVdnQlMvd1ZxSC95ajZRVDM5dDAva0hhK2dZVmdwCnZUQi9CZ2dyQmdFRkJRY0JBUVJ6TUhFd1RRWUlLd1lCQlFVSE1BS0dRV2gwZEhBNkx5OTNkM2N1YzNOc0xtTnYKYlM5eVpYQnZjMmwwYjNKNUwxTlRUR052YlMxVGRXSkRRUzFGVmkxVFUwd3RVbE5CTFRRd09UWXRVak11WTNKMApNQ0FHQ0NzR0FRVUZCekFCaGhSb2RIUndPaTh2YjJOemNITXVjM05zTG1OdmJUQWZCZ05WSFJFRUdEQVdnZ3QzCmQzY3VjM05zTG1OdmJZSUhjM05zTG1OdmJUQmZCZ05WSFNBRVdEQldNQWNHQldlQkRBRUJNQTBHQ3lxRWFBR0cKOW5jQ0JRRUJNRHdHRENzR0FRUUJncWt3QVFNQkJEQXNNQ29HQ0NzR0FRVUZCd0lCRmg1b2RIUndjem92TDNkMwpkeTV6YzJ3dVkyOXRMM0psY0c5emFYUnZjbmt3SFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdJR0NDc0dBUVVGCkJ3TUJNRWdHQTFVZEh3UkJNRDh3UGFBN29EbUdOMmgwZEhBNkx5OWpjbXh6TG5OemJDNWpiMjB2VTFOTVkyOXQKTFZOMVlrTkJMVVZXTFZOVFRDMVNVMEV0TkRBNU5pMVNNeTVqY213d0hRWURWUjBPQkJZRUZBREFGVUlhenc1cgpaSUhhcG5SeElVbnB3K0dMTUE0R0ExVWREd0VCL3dRRUF3SUZvRENDQVgwR0Npc0dBUVFCMW5rQ0JBSUVnZ0Z0CkJJSUJhUUZuQUhjQTlseVVMOUYzTUNJVVZCZ0lNSlJXanVOTkV4a3p2OThNTHlBTHpFN3haT01BQUFGeE0waG8KYndBQUJBTUFTREJHQWlFQTZ4ZWxpTlI4R2svNjNwWWRuUy92T3gvQ2pwdEVNRXY4OVdXaDEvdXJXSUVDSVFEeQpCcmVIVTI1RHp3dWtRYVJRandXNjU1WkxrcUNueGJ4UVdSaU9lbWo5SkFCMUFKUWd2QjZPMVkxc2lITWZnb3NpCkxBM1IyazFlYkUrVVBXSGJUaTlZVGFMQ0FBQUJjVE5JYU53QUFBUURBRVl3UkFJZ0dSRTR3emFiTlJkRDhrcS8KdkZQM3RRZTJobTB4NW5YdWxvd2g0SWJ3M2xrQ0lGWWIvM2xTRHBsUzdBY1I0citYcFd0RUtTVEZXSm1OQ1JiYwpYSnVyMlJHQkFIVUE3c0NWN28xeVpBK1M0OE81RzhjU28ybHFDWHRMYWhvVU9PWkhzc3Z0eGZrQUFBRnhNMGhvCjh3QUFCQU1BUmpCRUFpQjZJdmJvV3NzM1I0SXRWd2plYmw3RDN5b0ZhWDBORGgyZFdoaGd3Q3hySHdJZ0NmcTcKb2NNQzV0KzFqaTVNNXhhTG1QQzRJK1dYM0kvQVJrV1N5aU83SVFjd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQgpBQ2V1dXI0UW51anFtZ3VTckhVM21oZitjSm9kelRRTnFvNHRkZStQRDEvZUZkWUFFTHU4eEYrMEF0N3hKaVBZCmk1Ukt3aWx5UDU2diszaVkyVDlsdzdTOFRKMDQxVkxoYUlLcDE0TXpTVXpSeWVvT0FzSjdRQURNQ2xIS1VEbEgKVVUycE51bzg4WTZpZ292VDNic253Sk5pRVFOcXltU1NZaGt0dzB0YWR1b3FqcVhuMDZnc1Zpb1dUVkRYeXNkNQpxRXg0dDZzSWdJY01tMjZZSDF2SnBDUUVoS3BjMnkwN2dSa2tsQlpSdE1qVGh2NGNYeXlNWDd1VGNkVDdBSkJQCnVlaWZDb1YyNUp4WHVvOGQ1MTM5Z3dQMUJBZTdJQlZQeDJ1N0tOL1V5T1hkWm13TWYvVG1GR3dEZENmc3lIZi8KWnNCMndMSG96VFlvQVZtUTlGb1UxSkxnY1ZpdnFKK3ZObEJoSFhobHhNZE4wajgwUjlOejZFSWdsUWplSzNPOApJL2NGR20vQjgrNDJoT2xDSWQ5WmR0bmRKY1JKVmppMHdEMHF3ZXZDYWZBOWpKbEh2L2pzRStJOVV6NmNwQ3loCnN3K2xyRmR4VWdxVTU4YXhxZUs4OUZSK05vNHEwSUlPK0ppMXJKS3I5bmtTQjBCcVhvelZuRTFZQi9LTHZkSXMKdVlaSnVxYjJwS2t1K3p6VDZnVXdIVVRadkJpTk90WEw0Tnh3Yy9LVDdXek9TZDJ3UDEwUUk4REtnNHZmaU5EcwpIV21CMWM0S2ppNmdPZ0E1dVNVemFHbXEvdjRWbmNLNVVyK245TGJmbmZMYzI4SjVmdC9Hb3Rpbk15RGszaWFyCkYxMFlscWNPbWVYMXVGbUtiZGkvWG9yR2xrQ29NRjNURHg4cm1wOURCaUIvCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=" }, - "WhereToSaveSecrets": "Alex" + "WhereToSaveSecrets": "./save1" }, { "Identifier": { "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJvVENDQVVlZ0F3SUJBZ0lRVkNTcndsY1hnWnJrTWRzbFYwamk1VEFLQmdncWhrak9QUVFEQWpBU01SQXcKRGdZRFZRUUtFd2QwYzNOamIyMXRNQ0FYRFRJME1Ea3lNakEzTVRjeU1sb1lEekl3TmpReE1ESXlNRGN4TnpJeQpXakFTTVJBd0RnWURWUVFLRXdkMGMzTmpiMjF0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFCkhXd3B0YWk2WGRidW5JSmR2cUc2QTZMU3pTSFZRSkNoYWU3ZkNLNnR3ZlhvSFdMVE1jeklaa2RzMTZHZnh3Sy8KY1JFbUM4Y2JsYytsREFFcVIzR0UzcU45TUhzd0RnWURWUjBQQVFIL0JBUURBZ0tFTUIwR0ExVWRKUVFXTUJRRwpDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVdCQlRMCmtJSU95R2p4bGNIaHRnbWFxNm9PZS92WmhEQWFCZ05WSFJFRUV6QVJnZ2xzYjJOaGJHaHZjM1NIQkg4QUFBRXcKQ2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnUkVUSEhyZXNhRndoOW1udm9UZWNlNGFoWGJBWnFnSmFwVWdDSTF0YgovTXNDSVFDTVM4M25hRGNTL2lNVkc2Y3pqT3JiQnkyT3ZITnc5YUhDSm04V29MUWhDZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" }, - "WhereToSaveSecrets": "Sierra" + "WhereToSaveSecrets": "./save2" }, { "Identifier": { "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJvVENDQVVpZ0F3SUJBZ0lSQUlxZ2NqN29zeWg3Y0VZb1RtdTB4cTB3Q2dZSUtvWkl6ajBFQXdJd0VqRVEKTUE0R0ExVUVDaE1IZEhOelkyOXRiVEFnRncweU5EQTVNakl3TnpFM01qSmFHQTh5TURZME1UQXlNakEzTVRjeQpNbG93RWpFUU1BNEdBMVVFQ2hNSGRITnpZMjl0YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBCkJFOFQvanhieEVHZHFDQnFDNUQ4RDBPa0NXeSthMHJqQVUxRHJaYmxyWVFlUktYbHdLWXdGa2pOVjZNVlBROUIKbjFtcG9hNitIMmhJRnZudnNEdjAyVFdqZlRCN01BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVQpCZ2dyQmdFRkJRY0RBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVCkpya1E4ZzA4WDVFcGI4T1JsalUyb2l0WTJMd3dHZ1lEVlIwUkJCTXdFWUlKYkc5allXeG9iM04waHdSL0FBQUIKTUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJ1VnA3VE9xZXBlOEpvSnZxQTk2bnFIYzVHME9ucHZQa0t6dzJucgo2d3ExQWlCSXlJaHlpL0xVK1RWUDd3Z2JJVXpjMlJXeXZpSklDL0h0YW1ua3FxYWQ2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" }, - "WhereToSaveSecrets": "Veronica" + "WhereToSaveSecrets": "./save3" }, { "Identifier": { "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJvakNDQVVpZ0F3SUJBZ0lSQUxieVduSHQ2aHpRaDZMb2Q5bzBQemt3Q2dZSUtvWkl6ajBFQXdJd0VqRVEKTUE0R0ExVUVDaE1IZEhOelkyOXRiVEFnRncweU5EQTVNakl3TnpFM01qSmFHQTh5TURZME1UQXlNakEzTVRjeQpNbG93RWpFUU1BNEdBMVVFQ2hNSGRITnpZMjl0YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBCkJGTk9sRHkvRS8wOERtRHdzMVVwaVh5TGV3UkJBUEYvUXRQbm5GR0dvcS9aeFNtZDM2U08vNGs0TnRkWFFKdkEKS05SOVpZNklmclRYUDloNTZOWVlLSTJqZlRCN01BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVQpCZ2dyQmdFRkJRY0RBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVClF4R3ZBOHVNTjF5NUFRRGMweTc2QjMrQ256OHdHZ1lEVlIwUkJCTXdFWUlKYkc5allXeG9iM04waHdSL0FBQUIKTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSUdSUS9UdTRFQWtZRFhtWW5LeHRnR0JlQjhYT2ZIa2dOWGhGM1NXTApyRzQ2QWlFQXpHTzJlWklmenVlQytFQ05XWXBzdkFwK2F0emxXQlNkNmVUdDdKZGMwczQ9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" }, - "WhereToSaveSecrets": "Jameson" + "WhereToSaveSecrets": "./save4" }, { "Identifier": { "TlsX509":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJvakNDQVVlZ0F3SUJBZ0lRUXg2NUhRRjB0Q3I2VmxVWXo2VWEzekFLQmdncWhrak9QUVFEQWpBU01SQXcKRGdZRFZRUUtFd2QwYzNOamIyMXRNQ0FYRFRJME1Ea3lNakEzTVRjeU1sb1lEekl3TmpReE1ESXlNRGN4TnpJeQpXakFTTVJBd0RnWURWUVFLRXdkMGMzTmpiMjF0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFCit5ZlV2ZVBvMG1zZGxLS0FwcDM4TzR4ckJzRGN2cEFRblhmSUFDQk1ycjIzU056QnhFWVYwOGZYZ1Z2dXVGSkQKRTRRc29CRzdSb2lBZ3ZGWk5Rb055cU45TUhzd0RnWURWUjBQQVFIL0JBUURBZ0tFTUIwR0ExVWRKUVFXTUJRRwpDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVdCQlJMCnByNHdWZ0FEeVVNZXNiVVJFWWJ3N215bDB6QWFCZ05WSFJFRUV6QVJnZ2xzYjJOaGJHaHZjM1NIQkg4QUFBRXcKQ2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQVBVejY3Q3lKb0lLclNDSlJQcCtNQktFWkkvUTFtK3JlS0RqYzNBVQpXZkhBQWlFQWxIOXpJZjNoZ2hBS3dCcCt1MlB6L05TLzZYSm96UGQ5ZFpnR1dqeHdSM2c9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" }, - "WhereToSaveSecrets": "Riad" + "WhereToSaveSecrets": "./save5" } ] } \ No newline at end of file diff --git a/node/pkg/tss/internal/cmd/lkg.go b/node/pkg/tss/internal/cmd/lkg.go index 95f01ed62c..ad529f1490 100644 --- a/node/pkg/tss/internal/cmd/lkg.go +++ b/node/pkg/tss/internal/cmd/lkg.go @@ -19,18 +19,18 @@ import ( "github.com/yossigi/tss-lib/v2/tss" ) -var dkgLocation = flag.String("cnfg", "", "path to the dkg config file in json format") +var cnfgPath = flag.String("cnfg", "cnfg.example.json", "path to config file in json format used to run the protocol") func main() { flag.Parse() - if *dkgLocation == "" { + if *cnfgPath == "" { flag.PrintDefaults() return } - f, err := os.ReadFile(*dkgLocation) + f, err := os.ReadFile(*cnfgPath) if err != nil { fmt.Println("failed to read file, err: ", err) From 70d84ba4e12f7a11fc2aad0317fb13add64e0010 Mon Sep 17 00:00:00 2001 From: jonathanMweiss Date: Mon, 16 Dec 2024 07:53:38 +0000 Subject: [PATCH 3/6] added comment to the main file --- node/pkg/tss/internal/cmd/lkg.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/node/pkg/tss/internal/cmd/lkg.go b/node/pkg/tss/internal/cmd/lkg.go index ad529f1490..2059b1df9b 100644 --- a/node/pkg/tss/internal/cmd/lkg.go +++ b/node/pkg/tss/internal/cmd/lkg.go @@ -1,3 +1,7 @@ +// This file runs Distrubted Key Generation (DKG) protocol in local setting. +// That is, a gorotuine orchestrator simulates the network communication between the parties +// by collecting the outputs of the parties and feeding these output messages to the correct parties (using the `Update` method). + package main import ( From fa5123dfc1acb26339e70d6aaddc1d25cd010206 Mon Sep 17 00:00:00 2001 From: jonathanMweiss Date: Mon, 16 Dec 2024 08:00:08 +0000 Subject: [PATCH 4/6] commenting about simulateDKG method --- node/pkg/tss/internal/cmd/lkg.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/node/pkg/tss/internal/cmd/lkg.go b/node/pkg/tss/internal/cmd/lkg.go index 2059b1df9b..9362a9bdd4 100644 --- a/node/pkg/tss/internal/cmd/lkg.go +++ b/node/pkg/tss/internal/cmd/lkg.go @@ -168,6 +168,19 @@ func mustFeedParty(p tss.Party, parsedMsg tss.ParsedMessage) { } } +// In high level, this function simulates the network communication between the parties. +// It listens on the output channel of each party and puts it into a bag of messages. +// Once it has gone through all the parties, it empties the bag of messages and feeds +// each party with all messages that were addressed to it (some messages are broadcast messages too). +// It repeats this process until every party outputs a `secrets` file. +// Then it stores these secrets. +// +// In a network setting, each guardian would need to listen for messages from all other guardians, and feed the message to the tss.Party.Update method. +// In addition to that, to ensure the protocol's correctness, one would need to ensure no equivocation on broadcasts. +// As a result, one would need to create a broadcast channel: +// Either by using reliable broadcast protocol, or some variant protocol (e.g., a variant on the reliable-broadcast +// protocol that rebroadcast the hash of a message and not duplicate the message itself). +// Thus ensuring that all parties feed the tss.Party.Update method with the same message. func simulateDKG(all []*dkgPlayer) { done := 0 From f5a3d78333a46c552b9dcdcc1a68b6397df76e69 Mon Sep 17 00:00:00 2001 From: jonathanMweiss Date: Mon, 16 Dec 2024 08:09:08 +0000 Subject: [PATCH 5/6] fx: renamed file --- node/pkg/tss/internal/cmd/{lkg.go => local_key_generation.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename node/pkg/tss/internal/cmd/{lkg.go => local_key_generation.go} (100%) diff --git a/node/pkg/tss/internal/cmd/lkg.go b/node/pkg/tss/internal/cmd/local_key_generation.go similarity index 100% rename from node/pkg/tss/internal/cmd/lkg.go rename to node/pkg/tss/internal/cmd/local_key_generation.go From 1b5ed5a8874b1fe8fcd165b1ebd9a0eb6e6030b5 Mon Sep 17 00:00:00 2001 From: jonathanMweiss Date: Mon, 16 Dec 2024 08:23:36 +0000 Subject: [PATCH 6/6] fx: where-to-save correct usage --- node/pkg/tss/internal/cmd/local_key_generation.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/node/pkg/tss/internal/cmd/local_key_generation.go b/node/pkg/tss/internal/cmd/local_key_generation.go index 9362a9bdd4..93bbdb08d3 100644 --- a/node/pkg/tss/internal/cmd/local_key_generation.go +++ b/node/pkg/tss/internal/cmd/local_key_generation.go @@ -14,6 +14,7 @@ import ( "math/big" "net" "os" + "path" "time" engine "github.com/certusone/wormhole/node/pkg/tss" @@ -231,11 +232,14 @@ keygenLoop: panic("") } - fname := fmt.Sprintf("%s.json", all[i].whereToStore) + if err := os.MkdirAll(all[i].whereToStore, 0777); err != nil { + panic("Failed to create directory: " + err.Error()) + } - err = os.WriteFile(fname, bts, 0777) - if err != nil { - panic("Failed to write to disk") + fname := path.Join(all[i].whereToStore, "secrets.json") + + if err := os.WriteFile(fname, bts, 0777); err != nil { + panic("Failed to write to disk: " + err.Error()) } }