From e4d9bcdbf022b83eceb3b2b1ce0dce36cf660416 Mon Sep 17 00:00:00 2001 From: Cassandra Heart Date: Sun, 24 Sep 2023 21:43:35 -0500 Subject: [PATCH] =?UTF-8?q?1.0.0=20=E2=80=93=20Dawn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nekryptology/go.mod | 3 +- nekryptology/go.sum | 23 - .../pkg/core/curves/bls48581_curve.go | 18 +- .../pkg/tecdsa/dkls/v1/sign/multiply.go | 12 +- .../pkg/tecdsa/dkls/v1/sign/multiply_test.go | 8 +- nekryptology/pkg/tecdsa/dkls/v1/sign/sign.go | 16 +- node/app/node.go | 8 +- node/app/wire.go | 18 +- node/app/wire_gen.go | 25 +- node/config/config.go | 47 +- .../consensus/ceremony/broadcast_messaging.go | 808 ++++++++++ .../ceremony_data_clock_consensus_engine.go | 280 ++++ node/consensus/ceremony/consensus_frames.go | 940 ++++++++++++ .../ceremony/execution_registration.go | 78 + .../ceremony/handle_pending_commit_worker.go | 85 ++ node/consensus/ceremony/peer_messaging.go | 655 ++++++++ node/consensus/ceremony/prover_lookup.go | 61 + node/consensus/consensus_engine.go | 21 + node/consensus/master/broadcast_messaging.go | 51 +- node/consensus/master/consensus_frames.go | 5 - .../master/master_clock_consensus_engine.go | 4 + node/consensus/master/peer_messaging.go | 45 +- node/crypto/doubleratchet.go | 15 +- node/crypto/doubleratchet_test.go | 4 +- node/crypto/fft.go | 8 +- node/crypto/kzg.go | 4 +- node/crypto/kzg_test.go | 11 +- .../application/ceremony_application.go | 1056 +++++++++++++ .../ceremony_application_finalizing.go | 262 ++++ .../ceremony_application_in_progress.go | 252 +++ .../application/ceremony_application_open.go | 100 ++ .../application/ceremony_application_test.go | 284 ++++ .../ceremony_application_validating.go | 210 +++ .../ceremony_application_validating_test.go | 326 ++++ .../ceremony/application/multiply.go | 583 +++++++ .../application/oblivious_powers_of_tau.go | 169 ++ .../oblivious_powers_of_tau_test.go | 439 ++++++ .../ceremony/ceremony_execution_engine.go | 1016 ++++++++++++ node/execution/nop/nop_execution_engine.go | 95 -- node/go.mod | 2 + node/go.sum | 4 + node/keys/file.go | 2 +- node/main.go | 40 +- node/p2p/blossomsub.go | 79 +- node/p2p/public_channel.go | 194 +++ node/p2p/pubsub.go | 1 + node/protobufs/ceremony.go | 91 ++ node/protobufs/ceremony.pb.go | 1356 ++++++++++++++++- node/protobufs/ceremony.proto | 87 ++ node/protobufs/clock.go | 203 ++- node/protobufs/keys.pb.go | 92 +- node/protobufs/keys.proto | 6 + node/protobufs/protobufs.go | 81 +- node/store/clock.go | 93 +- node/tries/reward_critbit_trie.go | 301 ++++ 55 files changed, 10326 insertions(+), 351 deletions(-) create mode 100644 node/consensus/ceremony/broadcast_messaging.go create mode 100644 node/consensus/ceremony/ceremony_data_clock_consensus_engine.go create mode 100644 node/consensus/ceremony/consensus_frames.go create mode 100644 node/consensus/ceremony/execution_registration.go create mode 100644 node/consensus/ceremony/handle_pending_commit_worker.go create mode 100644 node/consensus/ceremony/peer_messaging.go create mode 100644 node/consensus/ceremony/prover_lookup.go create mode 100644 node/execution/ceremony/application/ceremony_application.go create mode 100644 node/execution/ceremony/application/ceremony_application_finalizing.go create mode 100644 node/execution/ceremony/application/ceremony_application_in_progress.go create mode 100644 node/execution/ceremony/application/ceremony_application_open.go create mode 100644 node/execution/ceremony/application/ceremony_application_test.go create mode 100644 node/execution/ceremony/application/ceremony_application_validating.go create mode 100644 node/execution/ceremony/application/ceremony_application_validating_test.go create mode 100644 node/execution/ceremony/application/multiply.go create mode 100644 node/execution/ceremony/application/oblivious_powers_of_tau.go create mode 100644 node/execution/ceremony/application/oblivious_powers_of_tau_test.go create mode 100644 node/execution/ceremony/ceremony_execution_engine.go delete mode 100644 node/execution/nop/nop_execution_engine.go create mode 100644 node/p2p/public_channel.go create mode 100644 node/protobufs/ceremony.go create mode 100644 node/tries/reward_critbit_trie.go diff --git a/nekryptology/go.mod b/nekryptology/go.mod index b5e601e..6ef8053 100644 --- a/nekryptology/go.mod +++ b/nekryptology/go.mod @@ -13,10 +13,11 @@ require ( github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.7.0 golang.org/x/crypto v0.9.0 - golang.org/x/sys v0.8.0 golang.org/x/tools v0.1.5 ) +require golang.org/x/sys v0.8.0 // indirect + require ( github.com/cloudflare/circl v1.3.3 github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/nekryptology/go.sum b/nekryptology/go.sum index a920233..6fdbc71 100644 --- a/nekryptology/go.sum +++ b/nekryptology/go.sum @@ -18,8 +18,6 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/bwesterb/go-ristretto v1.2.0 h1:xxWOVbN5m8NNKiSDZXE1jtZvZnC6JSJ9cYFADiZcWtw= -github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= @@ -65,52 +63,31 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/nekryptology/pkg/core/curves/bls48581_curve.go b/nekryptology/pkg/core/curves/bls48581_curve.go index c4e4978..6326408 100644 --- a/nekryptology/pkg/core/curves/bls48581_curve.go +++ b/nekryptology/pkg/core/curves/bls48581_curve.go @@ -14,7 +14,6 @@ import ( "golang.org/x/crypto/sha3" - "source.quilibrium.com/quilibrium/monorepo/nekryptology/internal" "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves/native/bls48581" "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves/native/bls48581/ext" ) @@ -240,7 +239,11 @@ func (s *ScalarBls48581) SetBigInt(v *big.Int) (Scalar, error) { if v == nil { return nil, fmt.Errorf("invalid value") } - i := bls48581.FromBytes(internal.ReverseScalarBytes(v.Bytes())) + t := make([]byte, bls48581.MODBYTES) + b := v.Bytes() + copy(t[bls48581.MODBYTES-uint(len(b)):], b) + + i := bls48581.FromBytes(t) i.Mod(bls48581.NewBIGints(bls48581.CURVE_Order)) return &ScalarBls48581{ Value: i, @@ -251,19 +254,22 @@ func (s *ScalarBls48581) SetBigInt(v *big.Int) (Scalar, error) { func (s *ScalarBls48581) BigInt() *big.Int { bytes := make([]byte, bls48581.MODBYTES) s.Value.ToBytes(bytes) - return new(big.Int).SetBytes(internal.ReverseScalarBytes(bytes)) + + return new(big.Int).SetBytes(bytes) } func (s *ScalarBls48581) Bytes() []byte { t := make([]byte, bls48581.MODBYTES) s.Value.ToBytes(t) - return internal.ReverseScalarBytes(t) + + return t } func (s *ScalarBls48581) SetBytes(bytes []byte) (Scalar, error) { var seq [bls48581.MODBYTES]byte - copy(seq[:], internal.ReverseScalarBytes(bytes)) + copy(seq[bls48581.MODBYTES-uint(len(bytes)):], bytes) value := bls48581.FromBytes(seq[:]) + if value == nil { return nil, errors.New("could not deserialize") } @@ -277,7 +283,7 @@ func (s *ScalarBls48581) SetBytesWide(bytes []byte) (Scalar, error) { return nil, fmt.Errorf("invalid length") } var seq [bls48581.MODBYTES]byte - copy(seq[:], internal.ReverseScalarBytes(bytes)) + copy(seq[:], bytes) value := bls48581.FromBytes(seq[:]) if value == nil { return nil, errors.New("could not deserialize") diff --git a/nekryptology/pkg/tecdsa/dkls/v1/sign/multiply.go b/nekryptology/pkg/tecdsa/dkls/v1/sign/multiply.go index b6cb245..8cad300 100644 --- a/nekryptology/pkg/tecdsa/dkls/v1/sign/multiply.go +++ b/nekryptology/pkg/tecdsa/dkls/v1/sign/multiply.go @@ -31,7 +31,7 @@ import ( // MultiplySender is the party that plays the role of Sender in the multiplication protocol (protocol 5 of the paper). type MultiplySender struct { cOtSender *kos.Sender // underlying cOT sender struct, used by mult. - outputAdditiveShare curves.Scalar // ultimate output share of mult. + OutputAdditiveShare curves.Scalar // ultimate output share of mult. gadget []curves.Scalar curve *curves.Curve transcript *merlin.Transcript @@ -41,7 +41,7 @@ type MultiplySender struct { // MultiplyReceiver is the party that plays the role of Sender in the multiplication protocol (protocol 5 of the paper). type MultiplyReceiver struct { cOtReceiver *kos.Receiver // underlying cOT receiver struct, used by mult. - outputAdditiveShare curves.Scalar // ultimate output share of mult. + OutputAdditiveShare curves.Scalar // ultimate output share of mult. omega []byte // this is used as an intermediate result during the course of mult. gadget []curves.Scalar curve *curves.Curve @@ -212,13 +212,13 @@ func (sender *MultiplySender) Round2Multiply(alpha curves.Scalar, round1Output * return nil, errors.Wrap(err, "setting chi scalar from bytes") } } - sender.outputAdditiveShare = sender.curve.Scalar.Zero() + sender.OutputAdditiveShare = sender.curve.Scalar.Zero() for j := uint(0); j < sender.cOtSender.L; j++ { round2Output.R[j] = sender.curve.Scalar.Zero() for k := 0; k < chiWidth; k++ { round2Output.R[j] = round2Output.R[j].Add(chi[k].Mul(sender.cOtSender.OutputAdditiveShares[j][k])) } - sender.outputAdditiveShare = sender.outputAdditiveShare.Add(sender.gadget[j].Mul(sender.cOtSender.OutputAdditiveShares[j][0])) + sender.OutputAdditiveShare = sender.OutputAdditiveShare.Add(sender.gadget[j].Mul(sender.cOtSender.OutputAdditiveShares[j][0])) } round2Output.U = chi[0].Mul(alpha).Add(chi[1].Mul(alphaHat)) return round2Output, nil @@ -250,7 +250,7 @@ func (receiver *MultiplyReceiver) Round3Multiply(round2Output *MultiplyRound2Out } } - receiver.outputAdditiveShare = receiver.curve.Scalar.Zero() + receiver.OutputAdditiveShare = receiver.curve.Scalar.Zero() for j := uint(0); j < receiver.cOtReceiver.L; j++ { // compute the LHS of bob's step 6) for j. note that we're "adding r_j" to both sides"; so this LHS includes r_j. // the reason to do this is so that the constant-time (i.e., independent of w_j) calculation of w_j * u can proceed more cleanly. @@ -265,7 +265,7 @@ func (receiver *MultiplyReceiver) Round3Multiply(round2Output *MultiplyRound2Out if subtle.ConstantTimeCompare(rightHandSideOfCheck[:], leftHandSideOfCheck.Bytes()) != 1 { return fmt.Errorf("alice's values R and U failed to check in round 3 multiply") } - receiver.outputAdditiveShare = receiver.outputAdditiveShare.Add(receiver.gadget[j].Mul(receiver.cOtReceiver.OutputAdditiveShares[j][0])) + receiver.OutputAdditiveShare = receiver.OutputAdditiveShare.Add(receiver.gadget[j].Mul(receiver.cOtReceiver.OutputAdditiveShares[j][0])) } return nil } diff --git a/nekryptology/pkg/tecdsa/dkls/v1/sign/multiply_test.go b/nekryptology/pkg/tecdsa/dkls/v1/sign/multiply_test.go index a033576..4fa46c2 100644 --- a/nekryptology/pkg/tecdsa/dkls/v1/sign/multiply_test.go +++ b/nekryptology/pkg/tecdsa/dkls/v1/sign/multiply_test.go @@ -44,7 +44,7 @@ func TestMultiply(t *testing.T) { require.Nil(t, err) product := alpha.Mul(beta) - sum := sender.outputAdditiveShare.Add(receiver.outputAdditiveShare) + sum := sender.OutputAdditiveShare.Add(receiver.OutputAdditiveShare) require.Equal(t, product, sum) } @@ -88,14 +88,14 @@ func TestMultiplyBLS48(t *testing.T) { generator := alpha.Point().Generator() product := generator.Mul(alpha).Mul(beta) - sum := generator.Mul(sender.outputAdditiveShare).Add(generator.Mul(receiver.outputAdditiveShare)) + sum := generator.Mul(sender.OutputAdditiveShare).Add(generator.Mul(receiver.OutputAdditiveShare)) g2generator := curves.BLS48581G2().NewGeneratorPoint() g2product := g2generator.Mul(alpha).Mul(beta) - g2sum := g2generator.Mul(sender.outputAdditiveShare).Add(g2generator.Mul(receiver.outputAdditiveShare)) + g2sum := g2generator.Mul(sender.OutputAdditiveShare).Add(g2generator.Mul(receiver.OutputAdditiveShare)) product2 := generator.Mul(alpha2).Mul(beta2) - sum2 := generator.Mul(sender2.outputAdditiveShare).Add(generator.Mul(receiver2.outputAdditiveShare)) + sum2 := generator.Mul(sender2.OutputAdditiveShare).Add(generator.Mul(receiver2.OutputAdditiveShare)) sum2Neg := sum2.Neg() result := product.(*curves.PointBls48581G1).MultiPairing( diff --git a/nekryptology/pkg/tecdsa/dkls/v1/sign/sign.go b/nekryptology/pkg/tecdsa/dkls/v1/sign/sign.go index bbd4a5d..3502cd3 100644 --- a/nekryptology/pkg/tecdsa/dkls/v1/sign/sign.go +++ b/nekryptology/pkg/tecdsa/dkls/v1/sign/sign.go @@ -234,7 +234,7 @@ func (alice *Alice) Round3Sign(message []byte, round2Output *SignRound2Output) ( one := alice.curve.Scalar.One() gamma1 := alice.curve.ScalarBaseMult(kA.Mul(phi).Add(one)) - other := r.Mul(multiplySenders[0].outputAdditiveShare.Neg()) + other := r.Mul(multiplySenders[0].OutputAdditiveShare.Neg()) gamma1 = gamma1.Add(other) hashGamma1Bytes := sha3.Sum256(gamma1.ToAffineCompressed()) hashGamma1, err := alice.curve.Scalar.SetBytes(hashGamma1Bytes[:]) @@ -260,9 +260,9 @@ func (alice *Alice) Round3Sign(message []byte, round2Output *SignRound2Output) ( return nil, errors.Wrap(err, "setting rX scalar from bytes") } - sigA := hOfMAsInteger.Mul(multiplySenders[0].outputAdditiveShare).Add(rX.Mul(multiplySenders[1].outputAdditiveShare)) - gamma2 := alice.publicKey.Mul(multiplySenders[0].outputAdditiveShare) - other = alice.curve.ScalarBaseMult(multiplySenders[1].outputAdditiveShare.Neg()) + sigA := hOfMAsInteger.Mul(multiplySenders[0].OutputAdditiveShare).Add(rX.Mul(multiplySenders[1].OutputAdditiveShare)) + gamma2 := alice.publicKey.Mul(multiplySenders[0].OutputAdditiveShare) + other = alice.curve.ScalarBaseMult(multiplySenders[1].OutputAdditiveShare.Neg()) gamma2 = gamma2.Add(other) hashGamma2Bytes := sha3.Sum256(gamma2.ToAffineCompressed()) hashGamma2, err := alice.curve.Scalar.SetBytes(hashGamma2Bytes[:]) @@ -314,14 +314,14 @@ func (bob *Bob) Round4Final(message []byte, round3Output *SignRound3Output) erro R: rX.Add(zero).BigInt(), // slight trick here; add it to 0 just to mod it by q (now it's mod p!) V: int(rY), } - gamma1 := r.Mul(bob.multiplyReceivers[0].outputAdditiveShare) + gamma1 := r.Mul(bob.multiplyReceivers[0].OutputAdditiveShare) gamma1HashedBytes := sha3.Sum256(gamma1.ToAffineCompressed()) gamma1Hashed, err := bob.curve.Scalar.SetBytes(gamma1HashedBytes[:]) if err != nil { return errors.Wrap(err, "setting gamma1Hashed scalar from bytes") } phi := round3Output.EtaPhi.Sub(gamma1Hashed) - theta := bob.multiplyReceivers[0].outputAdditiveShare.Sub(phi.Div(bob.kB)) + theta := bob.multiplyReceivers[0].OutputAdditiveShare.Sub(phi.Div(bob.kB)) if _, err = bob.hash.Write(message); err != nil { return errors.Wrap(err, "writing message to hash in Bob sign round 5 final") } @@ -334,8 +334,8 @@ func (bob *Bob) Round4Final(message []byte, round3Output *SignRound3Output) erro if err != nil { return errors.Wrap(err, "setting capitalR scalar from big int") } - sigB := digest.Mul(theta).Add(capitalR.Mul(bob.multiplyReceivers[1].outputAdditiveShare)) - gamma2 := bob.curve.ScalarBaseMult(bob.multiplyReceivers[1].outputAdditiveShare) + sigB := digest.Mul(theta).Add(capitalR.Mul(bob.multiplyReceivers[1].OutputAdditiveShare)) + gamma2 := bob.curve.ScalarBaseMult(bob.multiplyReceivers[1].OutputAdditiveShare) other := bob.publicKey.Mul(theta.Neg()) gamma2 = gamma2.Add(other) gamma2HashedBytes := sha3.Sum256(gamma2.ToAffineCompressed()) diff --git a/node/app/node.go b/node/app/node.go index 1e0bb78..72c4604 100644 --- a/node/app/node.go +++ b/node/app/node.go @@ -5,7 +5,7 @@ import ( "source.quilibrium.com/quilibrium/monorepo/node/consensus" "source.quilibrium.com/quilibrium/monorepo/node/execution" - "source.quilibrium.com/quilibrium/monorepo/node/execution/nop" + "source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony" ) type Node struct { @@ -14,7 +14,7 @@ type Node struct { } func newNode( - nopExecutionEngine *nop.NopExecutionEngine, + ceremonyExecutionEngine *ceremony.CeremonyExecutionEngine, engine consensus.ConsensusEngine, ) (*Node, error) { if engine == nil { @@ -22,8 +22,8 @@ func newNode( } execEngines := make(map[string]execution.ExecutionEngine) - if nopExecutionEngine != nil { - execEngines[nopExecutionEngine.GetName()] = nopExecutionEngine + if ceremonyExecutionEngine != nil { + execEngines[ceremonyExecutionEngine.GetName()] = ceremonyExecutionEngine } return &Node{ diff --git a/node/app/wire.go b/node/app/wire.go index dbe798f..5c26a74 100644 --- a/node/app/wire.go +++ b/node/app/wire.go @@ -8,8 +8,9 @@ import ( "go.uber.org/zap" "source.quilibrium.com/quilibrium/monorepo/node/config" "source.quilibrium.com/quilibrium/monorepo/node/consensus" + ceremonyConsensus "source.quilibrium.com/quilibrium/monorepo/node/consensus/ceremony" "source.quilibrium.com/quilibrium/monorepo/node/consensus/master" - "source.quilibrium.com/quilibrium/monorepo/node/execution/nop" + "source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony" "source.quilibrium.com/quilibrium/monorepo/node/keys" "source.quilibrium.com/quilibrium/monorepo/node/p2p" "source.quilibrium.com/quilibrium/monorepo/node/store" @@ -38,7 +39,9 @@ var storeSet = wire.NewSet( wire.FieldsOf(new(*config.Config), "DB"), store.NewPebbleDB, store.NewPebbleClockStore, + store.NewPebbleKeyStore, wire.Bind(new(store.ClockStore), new(*store.PebbleClockStore)), + wire.Bind(new(store.KeyStore), new(*store.PebbleKeyStore)), ) var pubSubSet = wire.NewSet( @@ -47,12 +50,20 @@ var pubSubSet = wire.NewSet( wire.Bind(new(p2p.PubSub), new(*p2p.BlossomSub)), ) +var dataConsensusSet = wire.NewSet( + wire.FieldsOf(new(*config.Config), "Engine"), + ceremonyConsensus.NewCeremonyDataClockConsensusEngine, + wire.Bind( + new(consensus.DataConsensusEngine), + new(*ceremonyConsensus.CeremonyDataClockConsensusEngine), + ), +) + var engineSet = wire.NewSet( - nop.NewNopExecutionEngine, + ceremony.NewCeremonyExecutionEngine, ) var consensusSet = wire.NewSet( - wire.FieldsOf(new(*config.Config), "Engine"), master.NewMasterClockConsensusEngine, wire.Bind( new(consensus.ConsensusEngine), @@ -67,6 +78,7 @@ func NewNode(*config.Config) (*Node, error) { storeSet, pubSubSet, engineSet, + dataConsensusSet, consensusSet, newNode, )) diff --git a/node/app/wire_gen.go b/node/app/wire_gen.go index 22da60c..7511892 100644 --- a/node/app/wire_gen.go +++ b/node/app/wire_gen.go @@ -11,8 +11,9 @@ import ( "go.uber.org/zap" "source.quilibrium.com/quilibrium/monorepo/node/config" "source.quilibrium.com/quilibrium/monorepo/node/consensus" + "source.quilibrium.com/quilibrium/monorepo/node/consensus/ceremony" "source.quilibrium.com/quilibrium/monorepo/node/consensus/master" - "source.quilibrium.com/quilibrium/monorepo/node/execution/nop" + ceremony2 "source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony" "source.quilibrium.com/quilibrium/monorepo/node/keys" "source.quilibrium.com/quilibrium/monorepo/node/p2p" "source.quilibrium.com/quilibrium/monorepo/node/store" @@ -22,17 +23,19 @@ import ( func NewNode(configConfig *config.Config) (*Node, error) { zapLogger := logger() - nopExecutionEngine := nop.NewNopExecutionEngine(zapLogger) engineConfig := configConfig.Engine + keyConfig := configConfig.Key + fileKeyManager := keys.NewFileKeyManager(keyConfig, zapLogger) dbConfig := configConfig.DB db := store.NewPebbleDB(dbConfig) pebbleClockStore := store.NewPebbleClockStore(db, zapLogger) - keyConfig := configConfig.Key - fileKeyManager := keys.NewFileKeyManager(keyConfig, zapLogger) + pebbleKeyStore := store.NewPebbleKeyStore(db, zapLogger) p2PConfig := configConfig.P2P blossomSub := p2p.NewBlossomSub(p2PConfig, zapLogger) + ceremonyDataClockConsensusEngine := ceremony.NewCeremonyDataClockConsensusEngine(engineConfig, zapLogger, fileKeyManager, pebbleClockStore, pebbleKeyStore, blossomSub) + ceremonyExecutionEngine := ceremony2.NewCeremonyExecutionEngine(zapLogger, ceremonyDataClockConsensusEngine, engineConfig, fileKeyManager, blossomSub, pebbleClockStore, pebbleKeyStore) masterClockConsensusEngine := master.NewMasterClockConsensusEngine(engineConfig, zapLogger, pebbleClockStore, fileKeyManager, blossomSub) - node, err := newNode(nopExecutionEngine, masterClockConsensusEngine) + node, err := newNode(ceremonyExecutionEngine, masterClockConsensusEngine) if err != nil { return nil, err } @@ -68,13 +71,19 @@ var loggerSet = wire.NewSet( var keyManagerSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "Key"), keys.NewFileKeyManager, wire.Bind(new(keys.KeyManager), new(*keys.FileKeyManager))) -var storeSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "DB"), store.NewPebbleDB, store.NewPebbleClockStore, wire.Bind(new(store.ClockStore), new(*store.PebbleClockStore))) +var storeSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "DB"), store.NewPebbleDB, store.NewPebbleClockStore, store.NewPebbleKeyStore, wire.Bind(new(store.ClockStore), new(*store.PebbleClockStore)), wire.Bind(new(store.KeyStore), new(*store.PebbleKeyStore))) var pubSubSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "P2P"), p2p.NewBlossomSub, wire.Bind(new(p2p.PubSub), new(*p2p.BlossomSub))) -var engineSet = wire.NewSet(nop.NewNopExecutionEngine) +var dataConsensusSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "Engine"), ceremony.NewCeremonyDataClockConsensusEngine, wire.Bind( + new(consensus.DataConsensusEngine), + new(*ceremony.CeremonyDataClockConsensusEngine), +), +) -var consensusSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "Engine"), master.NewMasterClockConsensusEngine, wire.Bind( +var engineSet = wire.NewSet(ceremony2.NewCeremonyExecutionEngine) + +var consensusSet = wire.NewSet(master.NewMasterClockConsensusEngine, wire.Bind( new(consensus.ConsensusEngine), new(*master.MasterClockConsensusEngine), ), diff --git a/node/config/config.go b/node/config/config.go index cf88012..dafe261 100644 --- a/node/config/config.go +++ b/node/config/config.go @@ -69,6 +69,24 @@ func LoadConfig(configPath string, proverKey string) (*Config, error) { } } + bootstrapPeers := []string{ + "/dns/bootstrap.quilibrium.com/udp/8336/quic/p2p/QmUhm9iZVruSxyavjoPLCfuoRG94SGQEkfxEEoukEZmD5B", + "/ip4/204.186.74.47/udp/8317/quic/p2p/Qmd233pLUDvcDW3ama27usfbG1HxKNh1V9dmWVW1SXp1pd", + "/ip4/13.237.250.230/udp/8317/quic/p2p/QmazMeSUA9HPLuj53w56k6GUq3xVny3pHtosUZndejJeai", + "/ip4/13.236.219.103/udp/8317/quic/p2p/QmcJqNsJLNfxkAxeJijfLppiNQERaeFuwsbg3BGScKqrfh", + "/ip4/204.186.74.46/udp/8316/quic/p2p/QmeqBjm3iX7sdTieyto1gys5ruQrQNPKfaTGcVQQWJPYDV", + "/ip4/186.233.184.181/udp/8336/quic/p2p/QmW6QDvKuYqJYYMP5tMZSp12X3nexywK28tZNgqtqNpEDL", + "/dns/quil.zanshindojo.org/udp/8336/quic/p2p/QmXbbmtS5D12rEc4HWiHWr6e83SCE4jeThPP4VJpAQPvXq", + "/ip4/195.15.213.171/udp/8336/quic/p2p/Qme5PeqPSNRAvgWYbKoW9yy8S9tUwx1RBGaJ4ByE1a4rnu", + "/ip4/144.76.104.93/udp/8336/quic/p2p/QmZejZ8DBGQ6foX9recW73GA6TqL6hCMX9ETWWW1Fb8xtx", + "/ip4/86.106.89.131/udp/8336/quic/p2p/QmU6kHqghuZbLGDivFh2TQw73vQzsNtYoegwhKTRw77R5p", + "/ip4/103.79.113.68/udp/8336/quic/p2p/QmSheQ43HuLhVYxdAByUV5pskihWRFpADnivuPf4cShZKq", + "/ip4/207.246.81.38/udp/8336/quic/p2p/QmPBYgDy7snHon7PAn8nv1shApQBQz1iHb2sBBS8QSgQwW", + "/dns/abyssia.fr/udp/8336/quic/p2p/QmS7C1UhN8nvzLJgFFf1uspMRrXjJqThHNN6AyEXp6oVUB", + "/ip4/51.15.18.247/udp/8336/quic/p2p/QmYVaHXdFmHFeTa6oPixgjMVag6Ex7gLjE559ejJddwqzu", + } + genesisSeed := "5768656e20696e2074686520436f75727365206f6620746563686e6f6c6f676963616c206576656e74732c206974206265636f6d6573206e656365737361727920666f72206f6e65206e6574776f726b0a746f20646973736f6c766520746865202070726f746f636f6c2062616e647320776869636820206861766520636f6e6e6563746564207468656d20207769746820616e6f746865722c20616e6420746f0a617373756d6520616d6f6e672074686520706f77657273206f6620746865207765622c202074686520736570617261746520616e6420657175616c2073746174696f6e20746f207768696368207468650a4c617773206f6620546563686e6f6c6f677920616e6420206f6620546563686e6f6c6f6779277320537465776172647320656e7469746c65207468656d2c20206120646563656e7420726573706563740a746f20746865206f70696e696f6e73206f6620416c6c20726571756972657320207468617420746865792073686f756c64206465636c617265207468652063617573657320776869636820696d70656c0a7468656d20746f207468652073657061726174696f6e2e0a0a576520686f6c642074686573652074727574687320746f2062652073656c662d65766964656e742c207468617420616c6c20636f676e697469766520656e7469746965732061726520637265617465640a657175616c2c2074686174202074686579206172652020656e646f7765642062792020746865206f7264657220206f66206c696665202077697468206365727461696e2020756e616c69656e61626c650a5269676874732c2020746861742020616d6f6e6720207468657365202061726520204c6966652c20204c6962657274792c2020507269766163792020616e64202050726f70657274792e2020546861740a686973746f726963616c6c7920746f20207365637572652020746865736520207269676874732c202050726f746f636f6c7320206861766520206265656e2020696e737469747574656420616d6f6e670a656e7469746965732c2020617320476f7665726e6d656e74732068617665206265656e2020696e737469747574656420616d6f6e67204d656e2c2020686176696e6720646572697665642074686569720a6a75737420706f776572732066726f6d2074686520636f6e73656e74206f662074686520676f7665726e65642c2054686174207768656e6576657220616e7920466f726d206f662050726f746f636f6c0a6265636f6d6573206465737472756374697665206f6620746865736520656e64732c20697420697320746865205269676874206f6620416c6c20746f20616c746572206f7220746f2061626f6c6973680a69742c20616e6420746f20696e73746974757465206e65772050726f746f636f6c732c206c6179696e672069747320666f756e646174696f6e206f6e2073756368207072696e6369706c657320616e640a6f7267616e697a696e672069747320706f7765727320696e207375636820666f726d2c2020617320746f207468656d207368616c6c207365656d206d6f7374206c696b656c7920746f206566666563740a74686569722053616665747920616e642048617070696e6573732e2050727564656e63652c2020696e646565642c202077696c6c206469637461746520746861742050726f746f636f6c73206c6f6e670a65737461626c6973686564202073686f756c6420206e6f742020626520206368616e6765642020666f7220206c696768742020616e6420207472616e7369656e7420206361757365733b202020616e640a6163636f7264696e676c7920616c6c20657870657269656e6365206861746820736865776e2c2074686174206d616e6b696e6420617265206d6f726520646973706f73656420746f207375666665722c0a7768696c65206576696c73206172652073756666657261626c652c207468616e20746f20207269676874207468656d73656c7665732062792061626f6c697368696e672074686520666f726d7320746f0a776869636820746865792020617265206163637573746f6d65642e2020427574207768656e202061206c6f6e6720747261696e20206f66206162757365732020616e642075737572706174696f6e732c0a7075727375696e672020696e7661726961626c7920207468652073616d6520204f626a656374206576696e6365732020612064657369676e2020746f2072656475636520207468656d2020756e6465720a6162736f6c7574652020446573706f7469736d2c20206974206973202074686569722072696768742c202069742069732020746865697220647574792c2020746f207468726f77206f666620737563680a50726f746f636f6c732c2020616e6420746f2070726f76696465206e6577204775617264732020666f72207468656972206675747572652073656375726974792e20205375636820686173206265656e0a746865202070617469656e742020737566666572616e636520206f66202074686520207765623b2020616e6420207375636820697320206e6f772074686520206e6563657373697479202077686963680a636f6e73747261696e73207468656d20746f20616c74657220746865697220666f726d65722053797374656d73206f66204e6574776f726b696e672e202054686520686973746f7279206f66207468650a70726573656e7420496e7465726e6574206973206120686973746f727920206f6620726570656174656420696e6a757269657320616e642075737572706174696f6e732c2020616c6c20686176696e670a696e2064697265637420206f626a65637420746865202065737461626c6973686d656e74206f662020616e20206162736f6c7574652020547972616e6e79206f7665722020746865204e6574776f726b0a53746174652e20546f2070726f766520746869732c206c6574204661637473206265207375626d697474656420746f20612063616e64696420776f726c642e0a0a41742074686520506879736963616c206c617965722c20496e7465726e657420536572766963652050726f7669646572732068617665207265667573656420746865697220417373656e7420746f0a46726565205370656563682c20746865206d6f73742077686f6c65736f6d6520616e64206e656365737361727920666f7220746865207075626c696320676f6f643a0a202020202020202068747470733a2f2f7777772e74686576657267652e636f6d2f32333732373233382f6e65742d6e65757472616c6974792d686973746f72792d6663632d6c656769736c6174696f6e0a0a4174207468652044617461204c696e6b206c617965722c20496e667275737472756374757265206173206120536572766963652050726f766964657273206861766520666f7262696464656e0a746865697220557365727320746f20667265656c792061646865726520746f20746865204c6177732c20756e6c6573732073757370656e64656420696e207468656972206f7065726174696f6e0a74696c6c20746865697220417373656e742073686f756c64206265206f627461696e65643b20616e64207768656e20736f2073757370656e6465642c207468657920686176652075747465726c790a6e65676c656374656420746f20617474656e6420746f207468656d2e0a2020202068747470733a2f2f7777772e636e62632e636f6d2f323032312f30312f31362f686f772d7061726c65722d6465706c6174666f726d696e672d73686f77732d706f7765722d6f662d636c6f750a20202020642d70726f7669646572732e68746d6c0a0a417420746865204e6574776f726b206c617965722c20476f7665726e6d656e74732068617665207265667573656420746f2070617373206f74686572204c61777320666f72207468650a6163636f6d6d6f646174696f6e206f66207365637572696e672074686520526967687473206f66207468652050656f706c65206f6e6c696e652c20696e2069747320737465616420616374696e670a636f6e747261727920746f20746865204c617773207375636820746861742074686f73652070656f706c6520776f756c642072656c696e717569736820746865207269676874206f660a526570726573656e746174696f6e20696e2074686520546f706963206f66205072697661637920616e642053656375726974792c206120726967687420696e657374696d61626c6520746f0a7468656d20616e6420666f726d696461626c6520746f20747972616e7473206f6e6c792e0a2020202068747470733a2f2f7777772e6566662e6f72672f646565706c696e6b732f323032332f30392f746f6461792d756b2d7061726c69616d656e742d756e6465726d696e65642d707269766163790a202020202d73656375726974792d616e642d66726565646f6d2d616c6c2d696e7465726e65742d75736572730a0a417420746865205472616e73706f7274206c617965722c20556e6163636f756e7461626c6520456e7472656e6368656420506f7765727320686176652063616c6c656420746f6765746865720a617373656d626c696573206f6620696e74657264696374696f6e20617420706c6163657320756e757375616c2c20756e636f6d666f727461626c652c20616e642064697374616e742066726f6d0a746865206465706f7369746f7279206f66207468656972207075626c6963205265636f726473206f7220696e206120666f726d2061636365737369626c6520746f206163636f756e7461626c650a696e717569736974696f6e2c20666f722074686520736f6c6520707572706f7365206f6620696e7661736976656c79207363727574696e697a696e6720746865206c69766573206f66207468650a50656f706c652e0a202020202020202020202020202020202020202020202020202020202020202020202020202020202068747470733a2f2f656e2e77696b6970656469612e6f72672f77696b692f526f6f6d5f363431410a0a4174207468652053657373696f6e206c617965722c204f7264657273206861766520646973736f6c7665642074686520726967687473206f66207468652070656f706c652072657065617465646c792c0a666f72206f70706f73696e6720616e6420636f6e737472756374696e6720636f756e7465726d65617375726573206f6e207468697320696e64657264696374696f6e2e0a2020202068747470733a2f2f7777772e6566662e6f72672f646565706c696e6b732f323030372f31302f71776573742d63656f2d6e73612d70756e69736865642d71776573742d7265667573696e672d0a2020202070617274696369706174652d696c6c6567616c2d7375727665696c6c616e63652d7072652d392d31310a0a4174207468652050726573656e746174696f6e206c617965722c2074686520537061726b73206f66206e657720436f6e7363696f75736e6573732061726520756e6465722064656261746520746f0a6265207375726d697365642064616e6765726f757320616e6420696e6a7572696f757320746f204d616e2c20616e642066726f6d2074686973206465626174652061726775656420746861742069740a73686f756c64206265207375626a65637420746f2063656e736f727368697020616e64207365636f6e6420636c617373656420746f206120736c6176652073746174757320756e6465720a636f72706f72617465206d6173746572732e0a2020202068747470733a2f2f76656e74757265626561742e636f6d2f61692f776974682d612d776176652d6f662d6e65772d6c6c6d732d6f70656e2d736f757263652d61692d69732d686176696e672d0a20202020612d6d6f6d656e742d616e642d612d7265642d686f742d6465626174652f0a0a496e206576657279207374616765206f6620207468657365204f707072657373696f6e732057652068617665205065746974696f6e65642020666f72205265647265737320696e20746865206d6f73740a68756d626c65207465726d733a204f7572207265706561746564205065746974696f6e732068617665206265656e20616e737765726564206f6e6c7920627920726570656174656420696e6a7572792e0a41205072696e63652077686f7365206368617261637465722069732074687573206d61726b65642020627920657665727920616374207768696368206d617920646566696e65206120547972616e742c0a697320756e66697420746f206265207468652072756c6572206f6620612066726565206e6574776f726b2e0a0a4e6f722068617665205765206265656e2077616e74696e672020696e20617474656e74696f6e7320746f206f7572204c7564646974652020627265746872656e2e2057652068617665207761726e65640a7468656d2066726f6d202074696d6520746f2074696d65206f6620617474656d7074732020627920746865697220766172696f7573206c656769736c6174757265732020746f20657874656e6420616e0a756e77617272616e7461626c65206a7572697364696374696f6e206f7665722075732e202020576520686176652072656d696e646564207468656d206f66207468652063697263756d7374616e6365730a6f66206f75722020646576656c6f706d656e7420616e6420656e6c69676874656e6d656e742020686572652e202057652068617665202061707065616c656420746f20207468656972206e61746976650a6a75737469636520616e64206d61676e616e696d6974792c2020616e6420776520686176652020636f6e6a7572656420207468656d20627920746865207469657320206f66206f757220636f6d6d6f6e0a6b696e647265642020746f2064697361766f77202074686573652075737572706174696f6e732c202077686963682c2020776f756c6420696e6576697461626c792020696e74657272757074206f75720a636f6e6e656374696f6e7320616e6420636f72726573706f6e64656e63652e20205468657920746f6f2068617665206265656e206465616620746f2074686520766f696365206f66206a7573746963650a616e6420206f6620636f6e73616e6775696e6974792e20205765206d7573742c207468657265666f72652c202061637175696573636520696e2020746865206e65636573736974792c202077686963680a64656e6f756e63657320206f7572202053657061726174696f6e2c2020616e642020686f6c6420207468656d2c2020617320776520686f6c6420207468652072657374206f6620206d616e6b696e642c0a446973636f6e6e656374656420696e204f70706f736974696f6e2c20696e2050656163652050656572732e0a0a57652c20207468657265666f72652c202074686520526570726573656e74617469766573206f6620746865206e657720496e7465726e65742c2020696e20746865206669727374207068617365206f660a74686520477265617420436572656d6f6e792c2020417373656d626c65642c202061707065616c696e6720746f207468652053757072656d65204a75646765206f662074686520776f726c6420666f720a74686520726563746974756465206f66206f757220696e74656e74696f6e732c2020646f2c2020696e20746865204e616d652c20616e6420627920417574686f72697479206f662074686520676f6f640a5374657761726473206f6620746865205765622c20736f6c656d6e6c79207075626c69736820616e64206465636c6172652c20205468617420746865205175696c69627269756d2050726f746f636f6c0a69732c20616e64206f66205269676874206f7567687420746f206265204672656520616e6420496e646570656e64656e743b202074686174206974206973204162736f6c7665642066726f6d207468650a64656d616e6473206f6620756e656c65637465642c20756e2d436f6e737469747574696f6e616c20666f72636573206f6e20746865207765622c20616e64207468617420746865206f6e6c79204c61770a77686963682020676f7665726e73202069742069732020746865204c617720207768696368207765202068617665207072657365727665642020666f722074686520206265747465726d656e74206f660a736f6369657479207468726f7567682074686520726570656174656420656e666f7263656d656e74206f662074686520436f6e737469747574696f6e3b20616e642074686174206173206120467265650a616e642020496e646570656e64656e742050726f746f636f6c2c2020697420686173202066756c6c20506f77657220746f2020446973636f6e6e6563742c20206a6f696e20696e2050656572696e672c0a636f6e747261637420436f6d7075746174696f6e2c2020656e6761676520696e20436f6d6d657263652c2020616e6420746f20646f20616c6c206f7468657220204163747320616e64205468696e67730a77686963682020496e646570656e64656e7420204e6574776f726b7320206d6179206f662020726967687420646f2e2020416e6420666f7220207468652020737570706f727420206f662020746869730a4465636c61726174696f6e2c2020776974682061206669726d2072656c69616e6365206f6e20207468652070726f74656374696f6e206f6620436f6e737469747574696f6e616c204c61772c202077650a6d757475616c6c792020706c656467652020746f20206561636820206f7468657220206f757220204d696e64732c206f757220204d616368696e65732020616e6420206f7572207374726f6e676573740a43727970746f6772617068792e" + config := &Config{ DB: &DBConfig{ Path: configPath + "/store", @@ -81,28 +99,13 @@ func LoadConfig(configPath string, proverKey string) (*Config, error) { }, P2P: &P2PConfig{ ListenMultiaddr: "/ip4/0.0.0.0/udp/8336/quic", - BootstrapPeers: []string{ - "/dns/bootstrap.quilibrium.com/udp/8336/quic/p2p/QmUhm9iZVruSxyavjoPLCfuoRG94SGQEkfxEEoukEZmD5B", - "/ip4/204.186.74.47/udp/8317/quic/p2p/Qmd233pLUDvcDW3ama27usfbG1HxKNh1V9dmWVW1SXp1pd", - "/ip4/13.237.250.230/udp/8317/quic/p2p/QmazMeSUA9HPLuj53w56k6GUq3xVny3pHtosUZndejJeai", - "/ip4/13.236.219.103/udp/8317/quic/p2p/QmcJqNsJLNfxkAxeJijfLppiNQERaeFuwsbg3BGScKqrfh", - "/ip4/204.186.74.46/udp/8316/quic/p2p/QmeqBjm3iX7sdTieyto1gys5ruQrQNPKfaTGcVQQWJPYDV", - "/ip4/186.233.184.181/udp/8336/quic/p2p/QmW6QDvKuYqJYYMP5tMZSp12X3nexywK28tZNgqtqNpEDL", - "/dns/quil.zanshindojo.org/udp/8336/quic/p2p/QmXbbmtS5D12rEc4HWiHWr6e83SCE4jeThPP4VJpAQPvXq", - "/ip4/195.15.213.171/udp/8336/quic/p2p/Qme5PeqPSNRAvgWYbKoW9yy8S9tUwx1RBGaJ4ByE1a4rnu", - "/ip4/144.76.104.93/udp/8336/quic/p2p/QmZejZ8DBGQ6foX9recW73GA6TqL6hCMX9ETWWW1Fb8xtx", - "/ip4/86.106.89.131/udp/8336/quic/p2p/QmU6kHqghuZbLGDivFh2TQw73vQzsNtYoegwhKTRw77R5p", - "/ip4/103.79.113.68/udp/8336/quic/p2p/QmSheQ43HuLhVYxdAByUV5pskihWRFpADnivuPf4cShZKq", - "/ip4/207.246.81.38/udp/8336/quic/p2p/QmPBYgDy7snHon7PAn8nv1shApQBQz1iHb2sBBS8QSgQwW", - "/dns/abyssia.fr/udp/8336/quic/p2p/QmS7C1UhN8nvzLJgFFf1uspMRrXjJqThHNN6AyEXp6oVUB", - "/ip4/51.15.18.247/udp/8336/quic/p2p/QmYVaHXdFmHFeTa6oPixgjMVag6Ex7gLjE559ejJddwqzu", - }, - PeerPrivKey: "", + BootstrapPeers: bootstrapPeers, + PeerPrivKey: "", }, Engine: &EngineConfig{ ProvingKeyId: "default-proving-key", Filter: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - GenesisSeed: "00", + GenesisSeed: genesisSeed, MaxFrames: -1, PendingCommitWorkers: 4, }, @@ -191,6 +194,14 @@ func LoadConfig(configPath string, proverKey string) (*Config, error) { return nil, err } + if config.Engine.GenesisSeed == "00" { + config.Engine.GenesisSeed = genesisSeed + } + + if len(config.P2P.BootstrapPeers) == 0 { + config.P2P.BootstrapPeers = bootstrapPeers + } + return config, nil } diff --git a/node/consensus/ceremony/broadcast_messaging.go b/node/consensus/ceremony/broadcast_messaging.go new file mode 100644 index 0000000..1ae04d0 --- /dev/null +++ b/node/consensus/ceremony/broadcast_messaging.go @@ -0,0 +1,808 @@ +package ceremony + +import ( + "bytes" + "crypto" + "crypto/rand" + "strings" + "time" + + "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/pkg/errors" + "go.uber.org/zap" + "golang.org/x/crypto/sha3" + "golang.org/x/sync/errgroup" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/zkp/schnorr" + "source.quilibrium.com/quilibrium/monorepo/node/consensus" + qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/keys" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/store" +) + +func (e *CeremonyDataClockConsensusEngine) handleMessage( + message *pb.Message, +) error { + e.logger.Debug( + "received message", + zap.Binary("data", message.Data), + zap.Binary("from", message.From), + zap.Binary("signature", message.Signature), + ) + msg := &protobufs.Message{} + + if err := proto.Unmarshal(message.Data, msg); err != nil { + return errors.Wrap(err, "handle message") + } + + eg := errgroup.Group{} + eg.SetLimit(len(e.executionEngines)) + + for name := range e.executionEngines { + name := name + eg.Go(func() error { + messages, err := e.executionEngines[name].ProcessMessage( + msg.Address, + msg, + ) + if err != nil { + e.logger.Error( + "could not process message for engine", + zap.Error(err), + zap.String("engine_name", name), + ) + return errors.Wrap(err, "handle message") + } + + for _, appMessage := range messages { + appMsg := &anypb.Any{} + err := proto.Unmarshal(appMessage.Payload, appMsg) + if err != nil { + e.logger.Error( + "could not unmarshal app message", + zap.Error(err), + zap.String("engine_name", name), + ) + return errors.Wrap(err, "handle message") + } + + switch appMsg.TypeUrl { + case protobufs.CeremonyLobbyStateTransitionType: + t := &protobufs.CeremonyLobbyStateTransition{} + err := proto.Unmarshal(appMsg.Value, t) + if err != nil { + return errors.Wrap(err, "handle message") + } + + if err := e.handleCeremonyLobbyStateTransition(t); err != nil { + return errors.Wrap(err, "handle message") + } + } + } + + return nil + }) + } + + if err := eg.Wait(); err != nil { + e.logger.Error("rejecting invalid message", zap.Error(err)) + return errors.Wrap(err, "execution failed") + } + + any := &anypb.Any{} + if err := proto.Unmarshal(msg.Payload, any); err != nil { + return errors.Wrap(err, "handle message") + } + + switch any.TypeUrl { + case protobufs.ClockFrameType: + if err := e.handleClockFrameData( + message.From, + msg.Address, + any, + ); err != nil { + return errors.Wrap(err, "handle message") + } + case protobufs.ProvingKeyRequestType: + if err := e.handleProvingKeyRequest( + message.From, + msg.Address, + any, + ); err != nil { + return errors.Wrap(err, "handle message") + } + case protobufs.ProvingKeyAnnouncementType: + if err := e.handleProvingKey(message.From, msg.Address, any); err != nil { + return errors.Wrap(err, "handle message") + } + case protobufs.KeyBundleAnnouncementType: + if err := e.handleKeyBundle(message.From, msg.Address, any); err != nil { + return errors.Wrap(err, "handle message") + } + } + + return nil +} + +func (e *CeremonyDataClockConsensusEngine) handleCeremonyLobbyStateTransition( + transition *protobufs.CeremonyLobbyStateTransition, +) error { + if len(transition.TransitionInputs) != len(transition.TypeUrls) { + return errors.Wrap( + errors.New("invalid state transition"), + "handle ceremony lobby state transition", + ) + } + + e.stagedLobbyStateTransitionsMx.Lock() + if e.stagedLobbyStateTransitions == nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + } + + found := false + for _, ti := range e.stagedLobbyStateTransitions.TransitionInputs { + for _, nti := range transition.TransitionInputs { + if bytes.Equal(ti, nti) { + found = true + } + } + } + + if !found { + for i := range transition.TransitionInputs { + e.stagedLobbyStateTransitions.TypeUrls = append( + e.stagedLobbyStateTransitions.TypeUrls, + transition.TypeUrls[i], + ) + e.stagedLobbyStateTransitions.TransitionInputs = append( + e.stagedLobbyStateTransitions.TransitionInputs, + transition.TransitionInputs[i], + ) + } + } + e.stagedLobbyStateTransitionsMx.Unlock() + return nil +} + +func (e *CeremonyDataClockConsensusEngine) handleKeyBundle( + peerID []byte, + address []byte, + any *anypb.Any, +) error { + e.logger.Info("received key bundle") + keyBundleAnnouncement := &protobufs.KeyBundleAnnouncement{} + if err := any.UnmarshalTo(keyBundleAnnouncement); err != nil { + return errors.Wrap(err, "handle key bundle") + } + + if len(keyBundleAnnouncement.ProvingKeyBytes) == 0 { + return errors.Wrap(errors.New("proving key is nil"), "handle key bundle") + } + + k, err := e.keyStore.GetLatestKeyBundle(keyBundleAnnouncement.ProvingKeyBytes) + if err != nil && !errors.Is(err, store.ErrNotFound) { + return errors.Wrap(err, "handle key bundle") + } + + if k != nil { + latestAnnouncement := &protobufs.KeyBundleAnnouncement{} + err := proto.Unmarshal(k.Data, latestAnnouncement) + if err != nil { + return errors.Wrap(err, "handle key bundle") + } + + if bytes.Equal( + latestAnnouncement.IdentityKey.Challenge, + keyBundleAnnouncement.IdentityKey.Challenge, + ) && bytes.Equal( + latestAnnouncement.IdentityKey.Response, + keyBundleAnnouncement.IdentityKey.Response, + ) && bytes.Equal( + latestAnnouncement.IdentityKey.Statement, + keyBundleAnnouncement.IdentityKey.Statement, + ) && bytes.Equal( + latestAnnouncement.SignedPreKey.Challenge, + keyBundleAnnouncement.SignedPreKey.Challenge, + ) && bytes.Equal( + latestAnnouncement.SignedPreKey.Response, + keyBundleAnnouncement.SignedPreKey.Response, + ) && bytes.Equal( + latestAnnouncement.SignedPreKey.Statement, + keyBundleAnnouncement.SignedPreKey.Statement, + ) { + // This has already been proven, ignore + return nil + } + } + + var provingKey *protobufs.ProvingKeyAnnouncement + inclusion, err := e.keyStore.GetProvingKey( + keyBundleAnnouncement.ProvingKeyBytes, + ) + if err != nil { + if !errors.Is(err, store.ErrNotFound) { + return errors.Wrap(err, "handle key bundle") + } + + provingKey, err = e.keyStore.GetStagedProvingKey( + keyBundleAnnouncement.ProvingKeyBytes, + ) + if err != nil && !errors.Is(err, store.ErrNotFound) { + return errors.Wrap(err, "handle key bundle") + } + } else { + err := proto.Unmarshal(inclusion.Data, provingKey) + if err != nil { + return errors.Wrap(err, "handle key bundle") + } + } + + // We have a matching proving key, we can set this up to be committed. + if provingKey != nil { + e.logger.Info("verifying key bundle announcement") + if err := keyBundleAnnouncement.Verify(provingKey); err != nil { + e.logger.Error( + "could not verify key bundle announcement", + zap.Error(err), + ) + return errors.Wrap(err, "handle key bundle") + } + + go func() { + e.logger.Info("adding key bundle announcement to pending commits") + + e.pendingCommits <- any + }() + + return nil + } else { + e.logger.Info("proving key not found, requesting from peers") + + if err = e.publishMessage(e.filter, &protobufs.ProvingKeyRequest{ + ProvingKeyBytes: keyBundleAnnouncement.ProvingKeyBytes, + }); err != nil { + return errors.Wrap(err, "handle key bundle") + } + + e.dependencyMapMx.Lock() + e.dependencyMap[string(keyBundleAnnouncement.ProvingKeyBytes)] = any + e.dependencyMapMx.Unlock() + } + + return nil +} + +func (e *CeremonyDataClockConsensusEngine) handleProvingKey( + peerID []byte, + address []byte, + any *anypb.Any, +) error { + e.logger.Info("received proving key") + + provingKeyAnnouncement := &protobufs.ProvingKeyAnnouncement{} + if err := any.UnmarshalTo(provingKeyAnnouncement); err != nil { + return errors.Wrap(err, "handle proving key") + } + + if err := provingKeyAnnouncement.Verify(); err != nil { + return errors.Wrap(err, "handle proving key") + } + + if err := e.keyStore.StageProvingKey(provingKeyAnnouncement); err != nil { + return errors.Wrap(err, "handle proving key") + } + + provingKey := provingKeyAnnouncement.PublicKey() + + e.logger.Info( + "proving key staged", + zap.Binary("proving_key", provingKey), + ) + + if e.dependencyMap[string(provingKey)] != nil { + go func() { + keyBundleAnnouncement := &protobufs.KeyBundleAnnouncement{} + if err := proto.Unmarshal( + e.dependencyMap[string(provingKey)].Value, + keyBundleAnnouncement, + ); err != nil { + e.logger.Error( + "could not unmarshal key bundle announcement", + zap.Error(err), + ) + } + if err := keyBundleAnnouncement.Verify( + provingKeyAnnouncement, + ); err != nil { + e.logger.Error( + "could not verify key bundle announcement", + zap.Error(err), + ) + } + + e.pendingCommits <- e.dependencyMap[string(provingKey)] + + e.dependencyMapMx.Lock() + delete(e.dependencyMap, string(provingKey)) + e.dependencyMapMx.Unlock() + }() + } + + return nil +} + +func (e *CeremonyDataClockConsensusEngine) handleClockFrameData( + peerID []byte, + address []byte, + any *anypb.Any, +) error { + frame := &protobufs.ClockFrame{} + if err := any.UnmarshalTo(frame); err != nil { + return errors.Wrap(err, "handle clock frame data") + } + + earliestFrame, _, count := e.frameProverTrie.Get(address) + _, latestFrame, _ := e.frameSeenProverTrie.Get(address) + if frame.FrameNumber == latestFrame { + e.logger.Info( + "already received frame from address", + zap.Binary("address", address), + zap.Binary("filter", frame.Filter), + zap.Uint64("frame_number", frame.FrameNumber), + ) + return nil + } else if frame.FrameNumber <= earliestFrame || count == 0 { + e.logger.Info( + "prover not in trie at frame, address may be in fork", + zap.Binary("address", address), + zap.Binary("filter", frame.Filter), + zap.Uint64("frame_number", frame.FrameNumber), + ) + return nil + } + + e.logger.Info( + "got clock frame", + zap.Binary("address", address), + zap.Binary("filter", frame.Filter), + zap.Uint64("frame_number", frame.FrameNumber), + zap.Int("proof_count", len(frame.AggregateProofs)), + ) + + if err := frame.VerifyDataClockFrame(); err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + + aggregateCommitments := []curves.PairingPoint{} + for i := 0; i < (len(frame.Input)-516)/74; i++ { + c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed( + frame.Input[516+(i*74) : 516+(i*74)+74], + ) + if err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + aggregateCommitments = append(aggregateCommitments, c.(curves.PairingPoint)) + } + + for i, proof := range frame.AggregateProofs { + aggregatePoly := [][]curves.PairingScalar{} + commitments := []curves.PairingPoint{} + + for _, commit := range proof.GetInclusionCommitments() { + switch commit.TypeUrl { + case protobufs.IntrinsicExecutionOutputType: + e.logger.Info("confirming inclusion in aggregate") + digest := sha3.NewShake256() + _, err := digest.Write(commit.Data) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame data") + } + + expand := make([]byte, 1024) + _, err = digest.Read(expand) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame data") + } + + poly, err := e.prover.BytesToPolynomial(expand) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame data") + } + + evalPoly, err := qcrypto.FFT( + poly, + *curves.BLS48581( + curves.BLS48581G1().NewGeneratorPoint(), + ), + 16, + false, + ) + if err != nil { + e.logger.Error( + "error performing fast fourier transform on key bundle", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame data") + } + e.logger.Info( + "created fft of polynomial", + zap.Int("poly_size", len(evalPoly)), + ) + + aggregatePoly = append(aggregatePoly, evalPoly) + + c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed( + commit.Commitment, + ) + if err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + commitments = append(commitments, c.(curves.PairingPoint)) + default: + e.logger.Info("confirming inclusion in aggregate") + poly, err := e.prover.BytesToPolynomial(commit.Data) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame data") + } + + for i := 0; i < 128-len(poly); i++ { + poly = append( + poly, + curves.BLS48581G1().Scalar.Zero().(curves.PairingScalar), + ) + } + + evalPoly, err := qcrypto.FFT( + poly, + *curves.BLS48581( + curves.BLS48581G1().NewGeneratorPoint(), + ), + 128, + false, + ) + if err != nil { + e.logger.Error( + "error performing fast fourier transform on key bundle", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame data") + } + e.logger.Info( + "created fft of polynomial", + zap.Int("poly_size", len(evalPoly)), + ) + + aggregatePoly = append(aggregatePoly, evalPoly) + + c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed( + commit.Commitment, + ) + if err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + commitments = append(commitments, c.(curves.PairingPoint)) + } + } + + p, err := curves.BLS48581G1().Point.FromAffineCompressed( + proof.Proof, + ) + if err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + + result, err := e.prover.VerifyAggregateProof( + aggregatePoly, + commitments, + aggregateCommitments[i], + p.(curves.PairingPoint), + ) + if err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + + if !result { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap( + errors.New("invalid proof"), + "handle clock frame data", + ) + } + } + + e.logger.Info( + "clock frame was valid", + zap.Binary("address", address), + zap.Binary("filter", frame.Filter), + zap.Uint64("frame_number", frame.FrameNumber), + ) + + parentSelector, selector, distance, err := + frame.GetParentSelectorAndDistance() + if err != nil { + return errors.Wrap(err, "handle clock frame data") + } + e.logger.Info( + "difference between selector/discriminator", + zap.Binary("difference", distance.Bytes()), + ) + + if _, err := e.clockStore.GetParentDataClockFrame( + frame.Filter, + frame.FrameNumber-1, + frame.ParentSelector, + ); errors.Is(err, store.ErrNotFound) { + // If this is a frame number higher than what we're already caught up to, + // push a request to fill the gap, unless we're syncing or it's in step, + // then just lazily seek. + from := e.frame + if e.syncingStatus != SyncStatusNotSyncing || from >= frame.FrameNumber-1 { + from = frame.FrameNumber - 1 + } + + if err := e.publishMessage(e.filter, &protobufs.ClockFramesRequest{ + Filter: e.filter, + FromFrameNumber: from, + ToFrameNumber: frame.FrameNumber, + }); err != nil { + e.logger.Error( + "could not publish clock frame parent request, skipping", + zap.Error(err), + ) + } + } + + txn, err := e.clockStore.NewTransaction() + if err != nil { + e.logger.Error("could not save candidate clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + + if err := e.clockStore.PutCandidateDataClockFrame( + parentSelector.Bytes(), + distance.Bytes(), + selector.Bytes(), + frame, + txn, + ); err != nil { + e.logger.Error("could not save candidate clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + + if err := txn.Commit(); err != nil { + e.logger.Error("could not save candidate clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + + if e.frame < frame.FrameNumber { + e.latestFrameReceived = frame.FrameNumber + e.lastFrameReceivedAt = time.Now().UTC() + } + e.frameSeenProverTrie.Add(address, frame.FrameNumber) + return nil +} + +func (e *CeremonyDataClockConsensusEngine) publishProof( + frame *protobufs.ClockFrame, +) error { + if e.state == consensus.EngineStatePublishing { + e.logger.Info( + "publishing frame and aggregations", + zap.Uint64("frame_number", frame.FrameNumber), + ) + if err := e.publishMessage(e.filter, frame); err != nil { + return errors.Wrap( + err, + "publish proof", + ) + } + + e.state = consensus.EngineStateCollecting + } + + return nil +} + +func (e *CeremonyDataClockConsensusEngine) publishMessage( + filter []byte, + message proto.Message, +) error { + any := &anypb.Any{} + if err := any.MarshalFrom(message); err != nil { + return errors.Wrap(err, "publish message") + } + + any.TypeUrl = strings.Replace( + any.TypeUrl, + "type.googleapis.com", + "types.quilibrium.com", + 1, + ) + + payload, err := proto.Marshal(any) + if err != nil { + return errors.Wrap(err, "publish message") + } + + h, err := poseidon.HashBytes(payload) + if err != nil { + return errors.Wrap(err, "publish message") + } + + msg := &protobufs.Message{ + Hash: h.Bytes(), + Address: e.provingKeyAddress, + Payload: payload, + } + data, err := proto.Marshal(msg) + if err != nil { + return errors.Wrap(err, "publish message") + } + return e.pubSub.PublishToBitmask(filter, data) +} + +func (e *CeremonyDataClockConsensusEngine) announceKeyBundle() error { + e.logger.Info("announcing key bundle") + idk, err := e.keyManager.GetAgreementKey("q-ratchet-idk") + if err != nil { + if errors.Is(err, keys.KeyNotFoundErr) { + idk, err = e.keyManager.CreateAgreementKey( + "q-ratchet-idk", + keys.KeyTypeX448, + ) + if err != nil { + return errors.Wrap(err, "announce key bundle") + } + } else { + return errors.Wrap(err, "announce key bundle") + } + } + + spk, err := e.keyManager.GetAgreementKey("q-ratchet-spk") + if err != nil { + if errors.Is(err, keys.KeyNotFoundErr) { + spk, err = e.keyManager.CreateAgreementKey( + "q-ratchet-spk", + keys.KeyTypeX448, + ) + if err != nil { + return errors.Wrap(err, "announce key bundle") + } + } else { + return errors.Wrap(err, "announce key bundle") + } + } + + idkPoint := curves.ED448().NewGeneratorPoint().Mul(idk) + idkProver := schnorr.NewProver( + curves.ED448(), + curves.ED448().NewGeneratorPoint(), + sha3.New256(), + []byte{}, + ) + + spkPoint := curves.ED448().NewGeneratorPoint().Mul(spk) + spkProver := schnorr.NewProver( + curves.ED448(), + curves.ED448().NewGeneratorPoint(), + sha3.New256(), + []byte{}, + ) + + idkProof, idkCommitment, err := idkProver.ProveCommit(idk) + if err != nil { + return errors.Wrap(err, "announce key bundle") + } + + spkProof, spkCommitment, err := spkProver.ProveCommit(spk) + if err != nil { + return errors.Wrap(err, "announce key bundle") + } + + msg := append( + append([]byte{}, idkCommitment...), + spkCommitment..., + ) + + signature, err := e.provingKey.Sign(rand.Reader, msg, crypto.Hash(0)) + if err != nil { + return errors.Wrap(err, "announce key bundle") + } + + signatureProto := &protobufs.ProvingKeyAnnouncement_ProvingKeySignatureEd448{ + ProvingKeySignatureEd448: &protobufs.Ed448Signature{ + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: e.provingKeyBytes, + }, + Signature: signature, + }, + } + provingKeyAnnouncement := &protobufs.ProvingKeyAnnouncement{ + IdentityCommitment: idkCommitment, + PrekeyCommitment: spkCommitment, + ProvingKeySignature: signatureProto, + } + + if err := e.publishMessage(e.filter, provingKeyAnnouncement); err != nil { + return errors.Wrap(err, "announce key bundle") + } + + idkSignature, err := e.provingKey.Sign( + rand.Reader, + idkPoint.ToAffineCompressed(), + crypto.Hash(0), + ) + if err != nil { + return errors.Wrap(err, "announce key bundle") + } + + spkSignature, err := e.provingKey.Sign( + rand.Reader, + spkPoint.ToAffineCompressed(), + crypto.Hash(0), + ) + if err != nil { + return errors.Wrap(err, "announce key bundle") + } + + keyBundleAnnouncement := &protobufs.KeyBundleAnnouncement{ + ProvingKeyBytes: e.provingKeyBytes, + IdentityKey: &protobufs.IdentityKey{ + Challenge: idkProof.C.Bytes(), + Response: idkProof.S.Bytes(), + Statement: idkProof.Statement.ToAffineCompressed(), + IdentityKeySignature: &protobufs.IdentityKey_PublicKeySignatureEd448{ + PublicKeySignatureEd448: &protobufs.Ed448Signature{ + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: idkPoint.ToAffineCompressed(), + }, + Signature: idkSignature, + }, + }, + }, + SignedPreKey: &protobufs.SignedPreKey{ + Challenge: spkProof.C.Bytes(), + Response: spkProof.S.Bytes(), + Statement: spkProof.Statement.ToAffineCompressed(), + SignedPreKeySignature: &protobufs.SignedPreKey_PublicKeySignatureEd448{ + PublicKeySignatureEd448: &protobufs.Ed448Signature{ + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: spkPoint.ToAffineCompressed(), + }, + Signature: spkSignature, + }, + }, + }, + } + + return errors.Wrap( + e.publishMessage(e.filter, keyBundleAnnouncement), + "announce key bundle", + ) +} diff --git a/node/consensus/ceremony/ceremony_data_clock_consensus_engine.go b/node/consensus/ceremony/ceremony_data_clock_consensus_engine.go new file mode 100644 index 0000000..83bbc08 --- /dev/null +++ b/node/consensus/ceremony/ceremony_data_clock_consensus_engine.go @@ -0,0 +1,280 @@ +package ceremony + +import ( + "crypto" + "math/big" + "sync" + "time" + + "github.com/pkg/errors" + "go.uber.org/zap" + "google.golang.org/protobuf/types/known/anypb" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + "source.quilibrium.com/quilibrium/monorepo/node/config" + "source.quilibrium.com/quilibrium/monorepo/node/consensus" + qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/execution" + "source.quilibrium.com/quilibrium/monorepo/node/keys" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/store" + "source.quilibrium.com/quilibrium/monorepo/node/tries" +) + +type InclusionMap = map[curves.PairingPoint]*protobufs.InclusionCommitment +type PolynomialMap = map[curves.PairingPoint][]curves.PairingScalar +type SyncStatusType int + +const ( + SyncStatusNotSyncing = iota + SyncStatusAwaitingResponse + SyncStatusSynchronizing +) + +type CeremonyDataClockConsensusEngine struct { + frame uint64 + activeFrame *protobufs.ClockFrame + difficulty uint32 + logger *zap.Logger + state consensus.EngineState + clockStore store.ClockStore + keyStore store.KeyStore + pubSub p2p.PubSub + keyManager keys.KeyManager + provingKey crypto.Signer + provingKeyBytes []byte + provingKeyType keys.KeyType + provingKeyAddress []byte + lastFrameReceivedAt time.Time + latestFrameReceived uint64 + frameProverTrie *tries.RollingFrecencyCritbitTrie + frameSeenProverTrie *tries.RollingFrecencyCritbitTrie + dependencyMap map[string]*anypb.Any + pendingCommits chan *anypb.Any + pendingCommitWorkers int64 + prover *qcrypto.KZGProver + stagedKeyCommits InclusionMap + stagedKeyPolynomials PolynomialMap + stagedLobbyStateTransitions *protobufs.CeremonyLobbyStateTransition + + frameChan chan *protobufs.ClockFrame + executionEngines map[string]execution.ExecutionEngine + filter []byte + input []byte + parentSelector []byte + syncingStatus SyncStatusType + syncingTarget []byte + currentDistance *big.Int + engineMx sync.Mutex + dependencyMapMx sync.Mutex + stagedKeyCommitsMx sync.Mutex + stagedLobbyStateTransitionsMx sync.Mutex + lastKeyBundleAnnouncementFrame uint64 +} + +var _ consensus.DataConsensusEngine = (*CeremonyDataClockConsensusEngine)(nil) + +// Creates a new data clock for ceremony execution – this is a hybrid clock, +// normally data clocks are bloom sharded and have node-specific proofs along +// with the public VDF proofs, but in this case it is a proof from the execution +// across all participating nodes. +func NewCeremonyDataClockConsensusEngine( + engineConfig *config.EngineConfig, + logger *zap.Logger, + keyManager keys.KeyManager, + clockStore store.ClockStore, + keyStore store.KeyStore, + pubSub p2p.PubSub, +) *CeremonyDataClockConsensusEngine { + if logger == nil { + panic(errors.New("logger is nil")) + } + + if engineConfig == nil { + panic(errors.New("engine config is nil")) + } + + if keyManager == nil { + panic(errors.New("key manager is nil")) + } + + if clockStore == nil { + panic(errors.New("clock store is nil")) + } + + if keyStore == nil { + panic(errors.New("key store is nil")) + } + + if pubSub == nil { + panic(errors.New("pubsub is nil")) + } + + e := &CeremonyDataClockConsensusEngine{ + frame: 0, + difficulty: 10000, + logger: logger, + state: consensus.EngineStateStopped, + clockStore: clockStore, + keyStore: keyStore, + keyManager: keyManager, + pubSub: pubSub, + frameChan: make(chan *protobufs.ClockFrame), + executionEngines: map[string]execution.ExecutionEngine{}, + dependencyMap: make(map[string]*anypb.Any), + parentSelector: []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + lastFrameReceivedAt: time.Time{}, + frameProverTrie: &tries.RollingFrecencyCritbitTrie{}, + frameSeenProverTrie: &tries.RollingFrecencyCritbitTrie{}, + pendingCommits: make(chan *anypb.Any), + pendingCommitWorkers: engineConfig.PendingCommitWorkers, + prover: qcrypto.DefaultKZGProver(), + stagedKeyCommits: make(InclusionMap), + stagedKeyPolynomials: make(PolynomialMap), + syncingStatus: SyncStatusNotSyncing, + } + + logger.Info("constructing consensus engine") + + signer, keyType, bytes, address := e.GetProvingKey( + engineConfig, + ) + + e.provingKey = signer + e.provingKeyType = keyType + e.provingKeyBytes = bytes + e.provingKeyAddress = address + + return e +} + +func (e *CeremonyDataClockConsensusEngine) Start( + filter []byte, + seed []byte, +) <-chan error { + e.logger.Info("starting ceremony consensus engine") + e.state = consensus.EngineStateStarting + errChan := make(chan error) + + e.filter = filter + e.input = seed + e.state = consensus.EngineStateLoading + + e.logger.Info("loading last seen state") + latestFrame, err := e.clockStore.GetLatestDataClockFrame( + e.filter, + e.frameProverTrie, + ) + if err != nil && !errors.Is(err, store.ErrNotFound) { + panic(err) + } + + if latestFrame != nil { + e.setFrame(latestFrame) + } else { + latestFrame = e.createGenesisFrame() + } + + e.logger.Info("subscribing to pubsub messages") + e.pubSub.Subscribe(e.filter, e.handleMessage, true) + e.pubSub.Subscribe( + append(append([]byte{}, e.filter...), e.pubSub.GetPeerID()...), + e.handleSync, + true, + ) + + e.state = consensus.EngineStateCollecting + + for i := int64(0); i < e.pendingCommitWorkers; i++ { + go e.handlePendingCommits(i) + } + + go func() { + for e.state < consensus.EngineStateStopping { + switch e.state { + case consensus.EngineStateCollecting: + if latestFrame, err = e.collect(latestFrame); err != nil { + e.logger.Error("could not collect", zap.Error(err)) + errChan <- err + } + case consensus.EngineStateProving: + if latestFrame, err = e.prove(latestFrame); err != nil { + e.logger.Error("could not prove", zap.Error(err)) + errChan <- err + } + case consensus.EngineStatePublishing: + if err = e.publishProof(latestFrame); err != nil { + e.logger.Error("could not publish", zap.Error(err)) + errChan <- err + } + } + } + }() + + go func() { + errChan <- nil + }() + + return errChan +} + +func (e *CeremonyDataClockConsensusEngine) Stop(force bool) <-chan error { + e.logger.Info("stopping ceremony consensus engine") + e.state = consensus.EngineStateStopping + errChan := make(chan error) + + wg := sync.WaitGroup{} + wg.Add(len(e.executionEngines)) + for name := range e.executionEngines { + name := name + go func(name string) { + err := <-e.UnregisterExecutor(name, e.frame, force) + if err != nil { + errChan <- err + } + wg.Done() + }(name) + } + + e.logger.Info("waiting for execution engines to stop") + wg.Wait() + e.logger.Info("execution engines stopped") + + e.state = consensus.EngineStateStopped + + e.engineMx.Lock() + defer e.engineMx.Unlock() + go func() { + errChan <- nil + }() + return errChan +} + +func (e *CeremonyDataClockConsensusEngine) GetDifficulty() uint32 { + return e.difficulty +} + +func (e *CeremonyDataClockConsensusEngine) GetFrame() uint64 { + return e.frame +} + +func (e *CeremonyDataClockConsensusEngine) GetState() consensus.EngineState { + return e.state +} + +func ( + e *CeremonyDataClockConsensusEngine, +) GetFrameChannel() <-chan *protobufs.ClockFrame { + return e.frameChan +} + +func ( + e *CeremonyDataClockConsensusEngine, +) GetActiveFrame() *protobufs.ClockFrame { + return e.activeFrame +} diff --git a/node/consensus/ceremony/consensus_frames.go b/node/consensus/ceremony/consensus_frames.go new file mode 100644 index 0000000..a2fff4c --- /dev/null +++ b/node/consensus/ceremony/consensus_frames.go @@ -0,0 +1,940 @@ +package ceremony + +import ( + "bytes" + "encoding/binary" + "encoding/hex" + "fmt" + "math/big" + "strings" + "time" + + "github.com/iden3/go-iden3-crypto/ff" + "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/pkg/errors" + "go.uber.org/zap" + "golang.org/x/crypto/sha3" + "google.golang.org/protobuf/proto" + "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf" + "source.quilibrium.com/quilibrium/monorepo/node/consensus" + qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony/application" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/store" + "source.quilibrium.com/quilibrium/monorepo/node/tries" +) + +func (e *CeremonyDataClockConsensusEngine) prove( + previousFrame *protobufs.ClockFrame, +) (*protobufs.ClockFrame, error) { + if e.state == consensus.EngineStateProving { + e.logger.Info("proving new frame") + if !e.frameProverTrie.Contains(e.provingKeyAddress) { + e.state = consensus.EngineStateCollecting + return previousFrame, nil + } + + commitments := [][]byte{} + aggregations := []*protobufs.InclusionAggregateProof{} + + e.stagedKeyCommitsMx.Lock() + if len(e.stagedKeyCommits) > 0 && len(e.stagedKeyPolynomials) > 0 { + e.logger.Info( + "adding staged key commits to frame", + zap.Uint64("frame_number", previousFrame.FrameNumber+1), + ) + keyCommitments := []curves.PairingPoint{} + keyInclusions := []*protobufs.InclusionCommitment{} + keyPolynomials := [][]curves.PairingScalar{} + i := uint32(0) + + for commit, inclusion := range e.stagedKeyCommits { + e.logger.Info( + "adding staged key commit to aggregate proof", + zap.Uint64("frame_number", previousFrame.FrameNumber+1), + zap.Uint32("position", i), + ) + keyCommitments = append(keyCommitments, commit) + inclusion.FrameNumber = previousFrame.FrameNumber + 1 + inclusion.Position = i + keyInclusions = append(keyInclusions, inclusion) + keyPolynomials = append(keyPolynomials, e.stagedKeyPolynomials[commit]) + } + + proof, commitment, err := e.prover.ProveAggregate( + keyPolynomials, + keyCommitments, + ) + if err != nil { + e.logger.Error("could not produce proof", zap.Error(err)) + return nil, errors.Wrap(err, "prove") + } + if proof.IsIdentity() { + return nil, errors.Wrap(errors.New("invalid proof"), "prove") + } + + commitments = append(commitments, commitment.ToAffineCompressed()) + + keyAggregation := &protobufs.InclusionAggregateProof{ + Filter: e.filter, + FrameNumber: previousFrame.FrameNumber + 1, + InclusionCommitments: keyInclusions, + Proof: proof.ToAffineCompressed(), + } + + aggregations = append(aggregations, keyAggregation) + + e.stagedKeyCommits = make( + map[curves.PairingPoint]*protobufs.InclusionCommitment, + ) + e.stagedKeyPolynomials = make( + map[curves.PairingPoint][]curves.PairingScalar, + ) + } + e.stagedKeyCommitsMx.Unlock() + + e.stagedLobbyStateTransitionsMx.Lock() + executionOutput := &protobufs.IntrinsicExecutionOutput{} + app, err := application.MaterializeApplicationFromFrame(previousFrame) + if err != nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + return nil, errors.Wrap(err, "prove") + } + + if e.stagedLobbyStateTransitions == nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + } + + app, err = app.ApplyTransition( + previousFrame.FrameNumber, + e.stagedLobbyStateTransitions, + ) + if err != nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + return nil, errors.Wrap(err, "prove") + } + + lobbyState, err := app.MaterializeLobbyStateFromApplication() + if err != nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + return nil, errors.Wrap(err, "prove") + } + + executionOutput.Address = application.CEREMONY_ADDRESS + executionOutput.Output, err = proto.Marshal(lobbyState) + if err != nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + return nil, errors.Wrap(err, "prove") + } + + executionOutput.Proof, err = proto.Marshal(e.stagedLobbyStateTransitions) + if err != nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + return nil, errors.Wrap(err, "prove") + } + + data, err := proto.Marshal(executionOutput) + if err != nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + return nil, errors.Wrap(err, "prove") + } + + e.logger.Info("encoded execution output") + + // Execution data in the ceremony is plaintext, we do not need to leverage + // full encoding for commit/proof reference. + digest := sha3.NewShake256() + _, err = digest.Write(data) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return nil, errors.Wrap(err, "prove") + } + + expand := make([]byte, 1024) + _, err = digest.Read(expand) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return nil, errors.Wrap(err, "prove") + } + poly, err := e.prover.BytesToPolynomial(expand) + if err != nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + return nil, errors.Wrap(err, "prove") + } + + e.logger.Info("proving execution output for inclusion") + polys, err := qcrypto.FFT( + poly, + *curves.BLS48581( + curves.BLS48581G1().NewGeneratorPoint(), + ), + 16, + false, + ) + if err != nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + return nil, errors.Wrap(err, "prove") + } + + e.logger.Info("converted execution output chunk to evaluation form") + + e.logger.Info("creating kzg commitment") + commitment, err := e.prover.Commit(polys) + if err != nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + return nil, errors.Wrap(err, "prove") + } + + e.logger.Info("creating kzg proof") + proof, aggregate, err := e.prover.ProveAggregate( + [][]curves.PairingScalar{polys}, + []curves.PairingPoint{commitment}, + ) + if err != nil { + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + return nil, errors.Wrap(err, "prove") + } + if proof.IsIdentity() { + return nil, errors.Wrap(errors.New("invalid proof"), "prove") + } + + commitments = append(commitments, aggregate.ToAffineCompressed()) + + e.logger.Info("finalizing execution proof") + + e.stagedLobbyStateTransitions = &protobufs.CeremonyLobbyStateTransition{} + e.stagedLobbyStateTransitionsMx.Unlock() + + execInclusion := &protobufs.InclusionCommitment{ + Filter: e.filter, + FrameNumber: previousFrame.FrameNumber + 1, + TypeUrl: protobufs.IntrinsicExecutionOutputType, + Data: data, + Commitment: commitment.ToAffineCompressed(), + } + + execAggregation := &protobufs.InclusionAggregateProof{ + Filter: e.filter, + FrameNumber: previousFrame.FrameNumber + 1, + InclusionCommitments: []*protobufs.InclusionCommitment{ + execInclusion, + }, + Proof: proof.ToAffineCompressed(), + } + + aggregations = append(aggregations, execAggregation) + + frame, err := protobufs.ProveDataClockFrame( + previousFrame, + commitments, + aggregations, + e.provingKey, + e.difficulty, + ) + if err != nil { + return nil, errors.Wrap(err, "prove") + } + e.state = consensus.EngineStatePublishing + e.logger.Info( + "returning new proven frame", + zap.Int("proof_count", len(aggregations)), + zap.Int("commitment_count", len(commitments)), + ) + return frame, nil + } + + return nil, nil +} + +func (e *CeremonyDataClockConsensusEngine) setFrame( + frame *protobufs.ClockFrame, +) { + pubkey := []byte{} + discriminator := big.NewInt(0) + ed448PublicKey := frame.GetPublicKeySignatureEd448() + if frame.PublicKeySignature == nil && frame.FrameNumber != 0 { + e.logger.Error("could not set frame, signature invalid for non-zero frame") + return + } else if ed448PublicKey != nil { + pubkey = ed448PublicKey.PublicKey.KeyValue + } + + if len(pubkey) != 0 { + var err error + discriminator, err = poseidon.HashBytes(pubkey) + if err != nil { + e.logger.Error( + "could not set frame", + zap.Error(err), + ) + return + } + } + + selector := new(big.Int).SetBytes(frame.ParentSelector) + + l := new(big.Int).Mod(new(big.Int).Sub(selector, discriminator), ff.Modulus()) + r := new(big.Int).Mod(new(big.Int).Sub(discriminator, selector), ff.Modulus()) + distance := r + if l.Cmp(r) == -1 { + distance = l + } + + previousSelectorBytes := [516]byte{} + copy(previousSelectorBytes[:], frame.Output[:516]) + + parent, err := poseidon.HashBytes(previousSelectorBytes[:]) + if err != nil { + panic(errors.Wrap(err, "set frame")) + } + e.logger.Info("set frame", zap.Uint64("frame_number", frame.FrameNumber)) + e.currentDistance = distance + e.frame = frame.FrameNumber + e.parentSelector = parent.Bytes() + e.activeFrame = frame + go func() { + e.frameChan <- frame + }() +} + +func ( + e *CeremonyDataClockConsensusEngine, +) createGenesisFrame() *protobufs.ClockFrame { + e.logger.Info("creating genesis frame") + for _, l := range strings.Split(string(e.input), "\n") { + e.logger.Info(l) + } + + b := sha3.Sum256(e.input) + v := vdf.New(e.difficulty, b) + + v.Execute() + o := v.GetOutput() + inputMessage := o[:] + + e.logger.Info("encoding ceremony and phase one signatories") + transcript := &protobufs.CeremonyTranscript{} + for p, s := range qcrypto.CeremonyBLS48581G1 { + transcript.G1Powers = append( + transcript.G1Powers, + &protobufs.BLS48581G1PublicKey{ + KeyValue: s.ToAffineCompressed(), + }, + ) + e.logger.Info(fmt.Sprintf("encoded G1 power %d", p)) + } + for p, s := range qcrypto.CeremonyBLS48581G2 { + transcript.G2Powers = append( + transcript.G2Powers, + &protobufs.BLS48581G2PublicKey{ + KeyValue: s.ToAffineCompressed(), + }, + ) + e.logger.Info(fmt.Sprintf("encoded G2 power %d", p)) + } + + transcript.RunningG1_256Witnesses = append( + transcript.RunningG1_256Witnesses, + &protobufs.BLS48581G1PublicKey{ + KeyValue: qcrypto.CeremonyRunningProducts[0].ToAffineCompressed(), + }, + ) + + transcript.RunningG2_256Powers = append( + transcript.RunningG2_256Powers, + &protobufs.BLS48581G2PublicKey{ + KeyValue: qcrypto.CeremonyPotPubKeys[len(qcrypto.CeremonyPotPubKeys)-1]. + ToAffineCompressed(), + }, + ) + + outputProof := &protobufs.CeremonyLobbyStateTransition{ + TypeUrls: []string{}, + TransitionInputs: [][]byte{}, + } + + proofBytes, err := proto.Marshal(outputProof) + if err != nil { + panic(err) + } + + e.logger.Info("encoded transcript") + e.logger.Info("encoding ceremony signatories into application state") + + rewardTrie := &tries.RewardCritbitTrie{} + for _, s := range qcrypto.CeremonySignatories { + pubkey := s.ToAffineCompressed() + + addr, err := poseidon.HashBytes(pubkey) + if err != nil { + panic(err) + } + + addrBytes := addr.Bytes() + addrBytes = append(make([]byte, 32-len(addrBytes)), addrBytes...) + rewardTrie.Add(addrBytes, 0, 50) + } + + trieBytes, err := rewardTrie.Serialize() + if err != nil { + panic(err) + } + + ceremonyLobbyState := &protobufs.CeremonyLobbyState{ + LobbyState: 0, + CeremonyState: &protobufs.CeremonyLobbyState_CeremonyOpenState{ + CeremonyOpenState: &protobufs.CeremonyOpenState{ + JoinedParticipants: []*protobufs.CeremonyLobbyJoin{}, + PreferredParticipants: []*protobufs.Ed448PublicKey{}, + }, + }, + LatestTranscript: transcript, + RewardTrie: trieBytes, + } + outputBytes, err := proto.Marshal(ceremonyLobbyState) + if err != nil { + panic(err) + } + + executionOutput := &protobufs.IntrinsicExecutionOutput{ + Address: []byte(e.filter), + Output: outputBytes, + Proof: proofBytes, + } + + data, err := proto.Marshal(executionOutput) + if err != nil { + panic(err) + } + + e.logger.Info("encoded execution output") + + digest := sha3.NewShake256() + _, err = digest.Write(data) + if err != nil { + panic(err) + } + + expand := make([]byte, 1024) + _, err = digest.Read(expand) + if err != nil { + panic(err) + } + + poly, err := e.prover.BytesToPolynomial(expand) + if err != nil { + panic(err) + } + + e.logger.Info("proving execution output for inclusion") + evalPoly, err := qcrypto.FFT( + poly, + *curves.BLS48581( + curves.BLS48581G1().NewGeneratorPoint(), + ), + 16, + false, + ) + if err != nil { + panic(err) + } + + e.logger.Info( + "converted execution output chunk to evaluation form", + zap.Int("poly_size", len(evalPoly)), + ) + + e.logger.Info("creating kzg commitment") + commitment, err := e.prover.Commit(evalPoly) + if err != nil { + panic(err) + } + + e.logger.Info("creating kzg proof") + proof, aggregate, err := e.prover.ProveAggregate( + [][]curves.PairingScalar{evalPoly}, + []curves.PairingPoint{commitment}, + ) + if err != nil { + panic(err) + } + + e.logger.Info("finalizing execution proof") + + inputMessage = append( + append([]byte{}, inputMessage...), + aggregate.ToAffineCompressed()..., + ) + + ceremonyExecutiveProof := &protobufs.InclusionAggregateProof{ + Filter: e.filter, + FrameNumber: 0, + InclusionCommitments: []*protobufs.InclusionCommitment{ + { + Filter: e.filter, + FrameNumber: 0, + Position: 0, + TypeUrl: protobufs.IntrinsicExecutionOutputType, + Data: data, + Commitment: commitment.ToAffineCompressed(), + }, + }, + Proof: proof.ToAffineCompressed(), + } + + // Signatories are special, they don't have an inclusion proof because they + // have not broadcasted communication keys, but they still get contribution + // rights prior to PoMW, because they did produce meaningful work in the + // first phase: + e.logger.Info("encoding signatories to prover trie") + + for _, s := range qcrypto.CeremonySignatories { + pubkey := s.ToAffineCompressed() + e.logger.Info("0x" + hex.EncodeToString(pubkey)) + + addr, err := poseidon.HashBytes(pubkey) + if err != nil { + panic(err) + } + + addrBytes := addr.Bytes() + addrBytes = append(make([]byte, 32-len(addrBytes)), addrBytes...) + e.frameProverTrie.Add(addrBytes, 0) + } + + e.logger.Info("proving genesis frame") + input := []byte{} + input = append(input, e.filter...) + input = binary.BigEndian.AppendUint64(input, e.frame) + input = binary.BigEndian.AppendUint64(input, uint64(0)) + input = binary.BigEndian.AppendUint32(input, e.difficulty) + input = append(input, e.input...) + + b = sha3.Sum256(input) + v = vdf.New(e.difficulty, b) + + v.Execute() + o = v.GetOutput() + + frame := &protobufs.ClockFrame{ + Filter: e.filter, + FrameNumber: e.frame, + Timestamp: 0, + Difficulty: e.difficulty, + Input: inputMessage, + Output: o[:], + ParentSelector: e.parentSelector, + AggregateProofs: []*protobufs.InclusionAggregateProof{ + ceremonyExecutiveProof, + }, + PublicKeySignature: nil, + } + + parent, distance, selector, err := frame.GetParentSelectorAndDistance() + if err != nil { + panic(err) + } + + txn, err := e.clockStore.NewTransaction() + if err != nil { + panic(err) + } + + if err := e.clockStore.PutCandidateDataClockFrame( + parent.Bytes(), + distance.Bytes(), + selector.Bytes(), + frame, + txn, + ); err != nil { + panic(err) + } + + if err := e.clockStore.PutDataClockFrame( + frame, + e.frameProverTrie, + txn, + ); err != nil { + panic(err) + } + + if err := txn.Commit(); err != nil { + panic(err) + } + + e.setFrame(frame) + return frame +} + +func (e *CeremonyDataClockConsensusEngine) commitLongestPath() ( + *protobufs.ClockFrame, + error, +) { + current, err := e.clockStore.GetLatestDataClockFrame(e.filter, nil) + if err != nil { + return nil, errors.Wrap(err, "commit longest path") + } + + e.logger.Info( + "searching from committed frame", + zap.Uint64("frame_number", current.FrameNumber), + ) + + runningFrames := [][]*protobufs.ClockFrame{{current}} + commitReady := false + currentDepth := 0 + + for { + nextRunningFrames := [][]*protobufs.ClockFrame{} + for _, s := range runningFrames { + e.logger.Info( + "ranging over candidates for frame", + zap.Uint64("frame_number", s[currentDepth].FrameNumber), + ) + selector, err := s[currentDepth].GetSelector() + if err != nil { + return nil, errors.Wrap(err, "commit longest path") + } + + iter, err := e.clockStore.RangeCandidateDataClockFrames( + e.filter, + selector.Bytes(), + s[currentDepth].FrameNumber+1, + ) + if err != nil { + return nil, errors.Wrap(err, "commit longest path") + } + + for iter.First(); iter.Valid(); iter.Next() { + value, err := iter.Value() + if err != nil { + return nil, errors.Wrap(err, "commit longest path") + } + + selectorBytes := selector.Bytes() + selectorBytes = append( + make([]byte, 32-len(selectorBytes)), + selectorBytes..., + ) + nearest := e.frameProverTrie.FindNearest( + selectorBytes, + ) + addr, err := value.GetAddress() + + // If we got the outright nearest, then skip all this, we know this is + // the right frame for the selector. + if err != nil && bytes.Equal(nearest.Bits(), addr) { + nextRunningFrames = append( + nextRunningFrames, + append( + append([]*protobufs.ClockFrame{}, s...), + value, + ), + ) + break + } + + // Iterated values will always be in order of shortest distance, this + // will always keep closest selected, longest path + if current.FrameNumber < value.FrameNumber { + e.logger.Info( + "setting longest path cursor to frame", + zap.Uint64("frame_number", value.FrameNumber), + ) + current = value + } + + e.logger.Info( + "adding candidate", + zap.Uint64("frame_number", value.FrameNumber), + zap.Binary("output", value.Output), + ) + + nextRunningFrames = append( + nextRunningFrames, + append( + append([]*protobufs.ClockFrame{}, s...), + value, + ), + ) + } + + iter.Close() + } + + if commitReady && len(nextRunningFrames) == 1 { + commitReady = false + e.logger.Info( + "consensus found, committing frames", + zap.Int("commit_depth", len(runningFrames[0])), + ) + + txn, err := e.clockStore.NewTransaction() + if err != nil { + return nil, errors.Wrap(err, "commit longest path") + } + + for _, s := range runningFrames[0][1:] { + e.logger.Info( + "committing candidate", + zap.Uint64("frame_number", s.FrameNumber), + zap.Binary("output", s.Output), + ) + + addr, err := s.GetAddress() + if err != nil { + return nil, errors.Wrap(err, "commit longest path") + } + + e.frameProverTrie.Add(addr, s.FrameNumber) + if err := e.clockStore.PutDataClockFrame( + s, + e.frameProverTrie, + txn, + ); err != nil { + e.logger.Error( + "could not commit candidate", + zap.Error(err), + zap.Uint64("frame_number", s.FrameNumber), + zap.Binary("output", s.Output), + ) + return nil, errors.Wrap(err, "commit longest path") + } + + e.logger.Info( + "committing aggregate proofs", + zap.Int("proof_count", len(s.AggregateProofs)), + ) + + for _, p := range s.AggregateProofs { + e.logger.Info( + "committing inclusions", + zap.Int("inclusions_count", len(p.InclusionCommitments)), + ) + + for _, c := range p.InclusionCommitments { + switch c.TypeUrl { + case protobufs.ProvingKeyAnnouncementType: + provingKey := &protobufs.ProvingKeyAnnouncement{} + if err := proto.Unmarshal(c.Data, provingKey); err != nil { + e.logger.Error( + "could not commit candidate", + zap.Error(err), + zap.Uint64("frame_number", s.FrameNumber), + zap.Binary("commitment", c.Commitment), + ) + return nil, errors.Wrap(err, "commit longest path") + } + + e.logger.Info( + "committing proving key", + zap.Uint64("frame_number", s.FrameNumber), + zap.Binary("commitment", c.Commitment), + ) + + if err := e.keyStore.IncludeProvingKey(c, txn); err != nil { + e.logger.Error( + "could not commit candidate", + zap.Error(err), + zap.Uint64("frame_number", s.FrameNumber), + zap.Binary("output", s.Output), + ) + return nil, errors.Wrap(err, "commit longest path") + } + case protobufs.KeyBundleAnnouncementType: + bundle := &protobufs.KeyBundleAnnouncement{} + if err := proto.Unmarshal(c.Data, bundle); err != nil { + e.logger.Error( + "could not commit candidate", + zap.Error(err), + zap.Uint64("frame_number", s.FrameNumber), + zap.Binary("commitment", c.Commitment), + ) + return nil, errors.Wrap(err, "commit longest path") + } + + e.logger.Info( + "committing key bundle", + zap.Uint64("frame_number", s.FrameNumber), + zap.Binary("commitment", c.Commitment), + ) + + if err := e.keyStore.PutKeyBundle( + bundle.ProvingKeyBytes, + c, + txn, + ); err != nil { + e.logger.Error( + "could not commit candidate", + zap.Error(err), + zap.Uint64("frame_number", s.FrameNumber), + zap.Binary("output", s.Output), + ) + return nil, errors.Wrap(err, "commit longest path") + } + } + } + } + } + + if err := txn.Commit(); err != nil { + e.logger.Error( + "could not commit candidates", + zap.Error(err), + ) + return nil, errors.Wrap(err, "commit longest path") + } + + runningFrames = [][]*protobufs.ClockFrame{ + {nextRunningFrames[0][currentDepth+1]}, + } + currentDepth = 0 + } else { + e.logger.Info( + "not ready to commit", + zap.Int("forks", len(nextRunningFrames)), + zap.Int("current_depth", currentDepth), + ) + commitReady = len(nextRunningFrames) == 1 + runningFrames = nextRunningFrames + currentDepth++ + } + + if len(nextRunningFrames) == 0 { + e.logger.Info("deepest consensus reached") + break + } + } + + return current, nil +} + +func (e *CeremonyDataClockConsensusEngine) collect( + currentFramePublished *protobufs.ClockFrame, +) (*protobufs.ClockFrame, error) { + if e.state == consensus.EngineStateCollecting { + e.logger.Info("collecting vdf proofs") + + latest, err := e.clockStore.GetLatestDataClockFrame(e.filter, nil) + if err != nil { + e.logger.Error("could not obtain latest clock frame", zap.Error(err)) + + return nil, errors.Wrap(err, "collect") + } + + if e.syncingStatus == SyncStatusNotSyncing { + peer, err := e.pubSub.GetRandomPeer(e.filter) + if err != nil { + if errors.Is(err, p2p.ErrNoPeersAvailable) { + e.logger.Warn("no peers available, skipping sync") + } else { + e.logger.Error("error while fetching random peer", zap.Error(err)) + } + } else { + e.syncingStatus = SyncStatusAwaitingResponse + e.logger.Info("setting syncing target", zap.Binary("peer_id", peer)) + e.syncingTarget = peer + + channel := e.createPeerReceiveChannel(peer) + e.logger.Info( + "listening on peer receive channel", + zap.Binary("channel", channel), + ) + e.pubSub.Subscribe(channel, e.handleSync, true) + e.pubSub.Subscribe( + append(append([]byte{}, e.filter...), peer...), + func(message *pb.Message) error { return nil }, + true, + ) + + go func() { + time.Sleep(2 * time.Second) + if err := e.publishMessage( + append(append([]byte{}, e.filter...), peer...), + &protobufs.ClockFramesRequest{ + Filter: e.filter, + FromFrameNumber: latest.FrameNumber + 1, + }); err != nil { + e.logger.Error( + "could not publish clock frame request", + zap.Error(err), + ) + } + }() + } + } + + waitDecay := time.Duration(2000) + for e.syncingStatus != SyncStatusNotSyncing { + e.logger.Info( + "waiting for sync to complete...", + zap.Duration("wait_decay", waitDecay), + ) + + time.Sleep(waitDecay * time.Millisecond) + + waitDecay = waitDecay * 2 + if waitDecay >= (100 * (2 << 6)) { + if e.syncingStatus == SyncStatusAwaitingResponse { + e.logger.Info("maximum wait for sync response, skipping sync") + e.syncingStatus = SyncStatusNotSyncing + break + } else { + waitDecay = 100 * (2 << 6) + } + } + } + + e.logger.Info("selecting leader") + latestFrame, err := e.commitLongestPath() + if err != nil { + e.logger.Error("could not collect longest path", zap.Error(err)) + return nil, errors.Wrap(err, "collect") + } + + go func() { + _, err = e.keyStore.GetProvingKey(e.provingKeyBytes) + if errors.Is(err, store.ErrNotFound) && + latestFrame.FrameNumber-e.lastKeyBundleAnnouncementFrame > 6 { + if err = e.announceKeyBundle(); err != nil { + panic(err) + } + e.lastKeyBundleAnnouncementFrame = latestFrame.FrameNumber + } + }() + + e.logger.Info( + "returning leader frame", + zap.Uint64("frame_number", latestFrame.FrameNumber), + ) + + if latestFrame.FrameNumber >= currentFramePublished.FrameNumber { + e.setFrame(latestFrame) + e.state = consensus.EngineStateProving + return latestFrame, nil + } else { + return latestFrame, nil + } + } + + return nil, nil +} diff --git a/node/consensus/ceremony/execution_registration.go b/node/consensus/ceremony/execution_registration.go new file mode 100644 index 0000000..7e89a08 --- /dev/null +++ b/node/consensus/ceremony/execution_registration.go @@ -0,0 +1,78 @@ +package ceremony + +import ( + "go.uber.org/zap" + "source.quilibrium.com/quilibrium/monorepo/node/execution" +) + +func (e *CeremonyDataClockConsensusEngine) RegisterExecutor( + exec execution.ExecutionEngine, + frame uint64, +) <-chan error { + logger := e.logger.With(zap.String("execution_engine_name", exec.GetName())) + logger.Info("registering execution engine") + errChan := make(chan error) + + go func() { + for { + logger.Info( + "awaiting frame", + zap.Uint64("current_frame", e.frame), + zap.Uint64("target_frame", frame), + ) + + newFrame := e.frame + if newFrame >= frame { + logger.Info( + "injecting execution engine at frame", + zap.Uint64("current_frame", newFrame), + ) + + e.engineMx.Lock() + e.executionEngines[exec.GetName()] = exec + e.engineMx.Unlock() + + errChan <- nil + break + } + } + }() + + return errChan +} + +func (e *CeremonyDataClockConsensusEngine) UnregisterExecutor( + name string, + frame uint64, + force bool, +) <-chan error { + logger := e.logger.With(zap.String("execution_engine_name", name)) + logger.Info("unregistering execution engine") + errChan := make(chan error) + + go func() { + for { + logger.Info( + "awaiting frame", + zap.Uint64("current_frame", e.frame), + zap.Uint64("target_frame", frame), + ) + + newFrame := e.frame + if newFrame >= frame { + logger.Info( + "removing execution engine at frame", + zap.Uint64("current_frame", newFrame), + ) + e.engineMx.Lock() + delete(e.executionEngines, name) + e.engineMx.Unlock() + + errChan <- nil + break + } + } + }() + + return errChan +} diff --git a/node/consensus/ceremony/handle_pending_commit_worker.go b/node/consensus/ceremony/handle_pending_commit_worker.go new file mode 100644 index 0000000..f316c5c --- /dev/null +++ b/node/consensus/ceremony/handle_pending_commit_worker.go @@ -0,0 +1,85 @@ +package ceremony + +import ( + "github.com/pkg/errors" + "go.uber.org/zap" + "google.golang.org/protobuf/types/known/anypb" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func (e *CeremonyDataClockConsensusEngine) handlePendingCommits( + workerId int64, +) { + for { + msg := <-e.pendingCommits + switch msg.TypeUrl { + case protobufs.KeyBundleAnnouncementType: + if err := e.includeKeyBundle(msg); err != nil { + e.logger.Error( + "failed to include key bundle", + zap.Error(errors.Wrap(err, "handle pending commits")), + zap.Int64("worker_id", workerId), + ) + } + } + } +} + +func (e *CeremonyDataClockConsensusEngine) includeKeyBundle( + any *anypb.Any, +) error { + poly, err := e.prover.BytesToPolynomial(any.Value) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return errors.Wrap(err, "include key bundle") + } + + for i := 0; i < 128-len(poly); i++ { + poly = append( + poly, + curves.BLS48581G1().Scalar.Zero().(curves.PairingScalar), + ) + } + + evalPoly, err := crypto.FFT( + poly, + *curves.BLS48581( + curves.BLS48581G1().NewGeneratorPoint(), + ), + 128, + false, + ) + if err != nil { + e.logger.Error( + "error performing fast fourier transform on key bundle", + zap.Error(err), + ) + return errors.Wrap(err, "include key bundle") + } + + commitment, err := e.prover.Commit(evalPoly) + if err != nil { + e.logger.Error( + "error creating kzg commitment", + zap.Error(err), + ) + return errors.Wrap(err, "include key bundle") + } + + e.stagedKeyCommitsMx.Lock() + e.stagedKeyCommits[commitment] = &protobufs.InclusionCommitment{ + Filter: e.filter, + TypeUrl: any.TypeUrl, + Data: any.Value, + Commitment: commitment.ToAffineCompressed(), + } + e.stagedKeyPolynomials[commitment] = evalPoly + e.stagedKeyCommitsMx.Unlock() + + return nil +} diff --git a/node/consensus/ceremony/peer_messaging.go b/node/consensus/ceremony/peer_messaging.go new file mode 100644 index 0000000..c8e2eeb --- /dev/null +++ b/node/consensus/ceremony/peer_messaging.go @@ -0,0 +1,655 @@ +package ceremony + +import ( + "bytes" + "time" + + "github.com/pkg/errors" + "go.uber.org/zap" + "golang.org/x/crypto/sha3" + "golang.org/x/sync/errgroup" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/store" + "source.quilibrium.com/quilibrium/monorepo/node/tries" +) + +func (e *CeremonyDataClockConsensusEngine) handleSync( + message *pb.Message, +) error { + e.logger.Debug( + "received message", + zap.Binary("data", message.Data), + zap.Binary("from", message.From), + zap.Binary("signature", message.Signature), + ) + msg := &protobufs.Message{} + + if err := proto.Unmarshal(message.Data, msg); err != nil { + return errors.Wrap(err, "handle sync") + } + + any := &anypb.Any{} + if err := proto.Unmarshal(msg.Payload, any); err != nil { + return errors.Wrap(err, "handle sync") + } + + eg := errgroup.Group{} + eg.SetLimit(len(e.executionEngines)) + + for name := range e.executionEngines { + name := name + eg.Go(func() error { + // if message,err := e.executionEngines[name].ProcessMessage( + if _, err := e.executionEngines[name].ProcessMessage( + msg.Address, + msg, + ); err != nil { + e.logger.Error( + "could not process message for engine", + zap.Error(err), + zap.String("engine_name", name), + ) + return err + } + + return nil + }) + } + + if err := eg.Wait(); err != nil { + e.logger.Error("rejecting invalid message", zap.Error(err)) + return errors.Wrap(err, "handle sync") + } + + switch any.TypeUrl { + case protobufs.ClockFramesResponseType: + if err := e.handleClockFramesResponse( + message.From, + msg.Address, + any, + ); err != nil { + return errors.Wrap(err, "handle sync") + } + case protobufs.ClockFramesRequestType: + if err := e.handleClockFramesRequest( + message.From, + msg.Address, + any, + ); err != nil { + return errors.Wrap(err, "handle sync") + } + case protobufs.ProvingKeyAnnouncementType: + if err := e.handleProvingKey( + message.From, + msg.Address, + any, + ); err != nil { + return errors.Wrap(err, "handle sync") + } + case protobufs.KeyBundleAnnouncementType: + if err := e.handleKeyBundle( + message.From, + msg.Address, + any, + ); err != nil { + return errors.Wrap(err, "handle sync") + } + } + + return nil +} + +func (e *CeremonyDataClockConsensusEngine) createPeerReceiveChannel( + peerID []byte, +) []byte { + return append( + append(append([]byte{}, e.filter...), peerID...), + e.pubSub.GetPeerID()..., + ) +} + +func (e *CeremonyDataClockConsensusEngine) createPeerSendChannel( + peerID []byte, +) []byte { + return append( + append(append([]byte{}, e.filter...), e.pubSub.GetPeerID()...), + peerID..., + ) +} + +func (e *CeremonyDataClockConsensusEngine) handleClockFramesResponse( + peerID []byte, + address []byte, + any *anypb.Any, +) error { + if bytes.Equal(address, e.provingKeyAddress) { + return nil + } + + if !bytes.Equal(peerID, e.syncingTarget) { + e.logger.Warn( + "received clock frames response from unexpected target", + zap.Binary("peer_id", peerID), + zap.Binary("expected_peer_id", e.syncingTarget), + ) + return nil + } + + e.syncingStatus = SyncStatusSynchronizing + + defer func() { e.syncingStatus = SyncStatusNotSyncing }() + + response := &protobufs.ClockFramesResponse{} + if err := any.UnmarshalTo(response); err != nil { + return errors.Wrap(err, "handle clock frames response") + } + + trieCopyBytes, err := e.frameProverTrie.Serialize() + if err != nil { + return errors.Wrap(err, "handle clock frames response") + } + + trieCopy := &tries.RollingFrecencyCritbitTrie{} + if err = trieCopy.Deserialize(trieCopyBytes); err != nil { + return errors.Wrap(err, "handle clock frames response") + } + + for _, frame := range response.ClockFrames { + prover, err := frame.GetAddress() + if err != nil { + return errors.Wrap(err, "handle clock frames response") + } + + earliestFrame, _, count := trieCopy.Get(prover) + if count == 0 || earliestFrame >= frame.FrameNumber { + return errors.Wrap( + errors.New("prover not in trie"), + "handle clock frame response", + ) + } + + e.logger.Info( + "processing clock frame", + zap.Binary("sender_address", address), + zap.Binary("prover_address", prover), + zap.Binary("filter", frame.Filter), + zap.Uint64("frame_number", frame.FrameNumber), + ) + + if err := frame.VerifyDataClockFrame(); err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame response") + } + + aggregateCommitments := []curves.PairingPoint{} + for i := 0; i < (len(frame.Input)-516)/74; i++ { + c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed( + frame.Input[516+(i*74) : 516+(i*74)+74], + ) + if err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame response") + } + aggregateCommitments = append( + aggregateCommitments, + c.(curves.PairingPoint), + ) + } + + for i, proof := range frame.AggregateProofs { + aggregatePoly := [][]curves.PairingScalar{} + commitments := []curves.PairingPoint{} + + for _, commit := range proof.GetInclusionCommitments() { + switch commit.TypeUrl { + case protobufs.IntrinsicExecutionOutputType: + e.logger.Info("confirming inclusion in aggregate") + digest := sha3.NewShake256() + _, err := digest.Write(commit.Data) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame response") + } + + expand := make([]byte, 1024) + _, err = digest.Read(expand) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame response") + } + + poly, err := e.prover.BytesToPolynomial(expand) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame response") + } + + evalPoly, err := qcrypto.FFT( + poly, + *curves.BLS48581( + curves.BLS48581G1().NewGeneratorPoint(), + ), + 16, + false, + ) + if err != nil { + e.logger.Error( + "error performing fast fourier transform on key bundle", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame response") + } + e.logger.Info( + "created fft of polynomial", + zap.Int("poly_size", len(evalPoly)), + ) + + aggregatePoly = append(aggregatePoly, evalPoly) + + c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed( + commit.Commitment, + ) + if err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame data") + } + commitments = append(commitments, c.(curves.PairingPoint)) + default: + poly, err := e.prover.BytesToPolynomial(commit.Data) + if err != nil { + e.logger.Error( + "error converting key bundle to polynomial", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame response") + } + + for i := 0; i < 128-len(poly); i++ { + poly = append( + poly, + curves.BLS48581G1().Scalar.Zero().(curves.PairingScalar), + ) + } + + evalPoly, err := qcrypto.FFT( + poly, + *curves.BLS48581( + curves.BLS48581G1().NewGeneratorPoint(), + ), + 128, + false, + ) + if err != nil { + e.logger.Error( + "error performing fast fourier transform on key bundle", + zap.Error(err), + ) + return errors.Wrap(err, "handle clock frame response") + } + + aggregatePoly = append(aggregatePoly, evalPoly) + + c, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed( + commit.Commitment, + ) + if err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame response") + } + commitments = append(commitments, c.(curves.PairingPoint)) + } + } + + p, err := curves.BLS48581G1().NewGeneratorPoint().FromAffineCompressed( + proof.Proof, + ) + if err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame response") + } + + result, err := e.prover.VerifyAggregateProof( + aggregatePoly, + commitments, + aggregateCommitments[i], + p.(curves.PairingPoint), + ) + if err != nil { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame response") + } + + if !result { + e.logger.Error("could not verify clock frame", zap.Error(err)) + return errors.Wrap( + errors.New("invalid proof"), + "handle clock frame response", + ) + } + } + + e.logger.Info( + "clock frame was valid", + zap.Binary("sender_address", address), + zap.Binary("prover_address", prover), + zap.Binary("filter", frame.Filter), + zap.Uint64("frame_number", frame.FrameNumber), + ) + + parentSelector, selector, distance, err := + frame.GetParentSelectorAndDistance() + if err != nil { + return errors.Wrap(err, "handle clock frame data") + } + e.logger.Info( + "difference between selector/discriminator", + zap.Binary("difference", distance.Bytes()), + ) + + txn, err := e.clockStore.NewTransaction() + if err != nil { + e.logger.Error("could not save candidate clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame response") + } + + if err := e.clockStore.PutCandidateDataClockFrame( + parentSelector.Bytes(), + distance.Bytes(), + selector.Bytes(), + frame, + txn, + ); err != nil { + e.logger.Error("could not save candidate clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame response") + } + + if err := txn.Commit(); err != nil { + e.logger.Error("could not save candidate clock frame", zap.Error(err)) + return errors.Wrap(err, "handle clock frame response") + } + + if e.frame < frame.FrameNumber { + e.latestFrameReceived = frame.FrameNumber + e.lastFrameReceivedAt = time.Now().UTC() + } + trieCopy.Add(prover, frame.FrameNumber) + e.frameSeenProverTrie.Add(prover, frame.FrameNumber) + } + + return nil +} + +func (e *CeremonyDataClockConsensusEngine) handleProvingKeyRequest( + peerID []byte, + address []byte, + any *anypb.Any, +) error { + if bytes.Equal(address, e.provingKeyAddress) { + return nil + } + + request := &protobufs.ProvingKeyRequest{} + if err := any.UnmarshalTo(request); err != nil { + return errors.Wrap(err, "handle proving key request") + } + + if len(request.ProvingKeyBytes) == 0 { + e.logger.Warn( + "received proving key request for empty key", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + ) + return errors.Wrap( + errors.New("empty proving key"), + "handle proving key request", + ) + } + + channel := e.createPeerSendChannel(peerID) + e.pubSub.Subscribe(channel, e.handleSync, true) + + e.logger.Info( + "received proving key request", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Binary("proving_key", request.ProvingKeyBytes), + ) + + var provingKey *protobufs.ProvingKeyAnnouncement + inclusion, err := e.keyStore.GetProvingKey(request.ProvingKeyBytes) + if err != nil { + if !errors.Is(err, store.ErrNotFound) { + e.logger.Error( + "peer asked for proving key that returned error", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Binary("proving_key", request.ProvingKeyBytes), + ) + return errors.Wrap(err, "handle proving key request") + } + + provingKey, err = e.keyStore.GetStagedProvingKey(request.ProvingKeyBytes) + if !errors.Is(err, store.ErrNotFound) { + e.logger.Error( + "peer asked for proving key that returned error", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Binary("proving_key", request.ProvingKeyBytes), + ) + return errors.Wrap(err, "handle proving key request") + } else if err != nil { + e.logger.Warn( + "peer asked for unknown proving key", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Binary("proving_key", request.ProvingKeyBytes), + ) + return nil + } + } else { + err := proto.Unmarshal(inclusion.Data, provingKey) + if err != nil { + e.logger.Error( + "inclusion commitment could not be deserialized", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Binary("proving_key", request.ProvingKeyBytes), + ) + return errors.Wrap(err, "handle proving key request") + } + } + + if err := e.publishMessage(channel, provingKey); err != nil { + return errors.Wrap(err, "handle proving key request") + } + + return nil +} + +func (e *CeremonyDataClockConsensusEngine) handleClockFramesRequest( + peerID []byte, + address []byte, + any *anypb.Any, +) error { + if bytes.Equal(address, e.provingKeyAddress) { + return nil + } + + request := &protobufs.ClockFramesRequest{} + if err := any.UnmarshalTo(request); err != nil { + return errors.Wrap(err, "handle clock frame request") + } + + channel := e.createPeerSendChannel(peerID) + + e.pubSub.Subscribe(channel, e.handleSync, true) + + e.logger.Info( + "received clock frame request", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Uint64("from_frame_number", request.FromFrameNumber), + zap.Uint64("to_frame_number", request.ToFrameNumber), + ) + + from := request.FromFrameNumber + + base, _, err := e.clockStore.GetDataClockFrame( + request.Filter, + from, + ) + if err != nil { + if !errors.Is(err, store.ErrNotFound) { + e.logger.Error( + "peer asked for frame that returned error", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Uint64("frame_number", request.FromFrameNumber), + ) + return errors.Wrap(err, "handle clock frame request") + } else { + e.logger.Info( + "peer asked for undiscovered frame", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Uint64("frame_number", request.FromFrameNumber), + ) + + if err = e.publishMessage(channel, &protobufs.ClockFramesResponse{ + Filter: request.Filter, + FromFrameNumber: 0, + ToFrameNumber: 0, + ClockFrames: []*protobufs.ClockFrame{}, + }); err != nil { + return errors.Wrap(err, "handle clock frame request") + } + + return nil + } + } + + to := request.ToFrameNumber + if to == 0 || to-request.FromFrameNumber > 128 { + to = request.FromFrameNumber + 127 + } + + set := []*protobufs.ClockFrame{base} + noMoreFinalized := false + searchSpan := []*protobufs.ClockFrame{base} + currentNumber := 1 + + for len(searchSpan) != 0 && from+uint64(currentNumber) <= to { + e.logger.Info( + "scanning frames to add to response", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Uint64("from", from), + zap.Uint64("to", to), + zap.Uint64("current_number", uint64(currentNumber)), + ) + nextSpan := []*protobufs.ClockFrame{} + for _, s := range searchSpan { + selector, err := s.GetSelector() + if err != nil { + return errors.Wrap(err, "handle clock frame request") + } + + if !noMoreFinalized { + frame, _, err := e.clockStore.GetDataClockFrame( + s.Filter, + s.FrameNumber+1, + ) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + noMoreFinalized = true + } else { + e.logger.Error( + "fetching clock frame produced error", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Uint64("frame_number", s.FrameNumber+1), + ) + return errors.Wrap(err, "handle clock frame request") + } + } else { + nextSpan = append(nextSpan, frame) + set = append(set, frame) + } + } + + if noMoreFinalized { + iter, err := e.clockStore.RangeCandidateDataClockFrames( + s.Filter, + selector.Bytes(), + s.FrameNumber+1, + ) + if err != nil { + e.logger.Error( + "peer asked for frame that returned error while iterating", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Binary("parent_selector", s.ParentSelector), + zap.Uint64("frame_number", s.FrameNumber+1), + ) + return errors.Wrap(err, "handle clock frame request") + } + + for iter.First(); iter.Valid(); iter.Next() { + frame, err := iter.Value() + + if err != nil { + e.logger.Error( + "peer asked for frame that returned error while getting value", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Binary("parent_selector", selector.Bytes()), + zap.Uint64("frame_number", s.FrameNumber+1), + ) + return errors.Wrap(err, "handle clock frame request") + } + + nextSpan = append(nextSpan, frame) + set = append(set, frame) + } + + iter.Close() + } + } + currentNumber++ + searchSpan = nextSpan + } + + e.logger.Info( + "sending response", + zap.Binary("peer_id", peerID), + zap.Binary("address", address), + zap.Uint64("from", from), + zap.Uint64("to", to), + zap.Uint64("total_frames", uint64(len(set))), + ) + + if err = e.publishMessage(channel, &protobufs.ClockFramesResponse{ + Filter: request.Filter, + FromFrameNumber: request.FromFrameNumber, + ToFrameNumber: to, + ClockFrames: set, + }); err != nil { + return errors.Wrap(err, "handle clock frame request") + } + + return nil +} diff --git a/node/consensus/ceremony/prover_lookup.go b/node/consensus/ceremony/prover_lookup.go new file mode 100644 index 0000000..1da144a --- /dev/null +++ b/node/consensus/ceremony/prover_lookup.go @@ -0,0 +1,61 @@ +package ceremony + +import ( + "crypto" + + "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/pkg/errors" + "go.uber.org/zap" + "source.quilibrium.com/quilibrium/monorepo/node/config" + "source.quilibrium.com/quilibrium/monorepo/node/keys" +) + +func (e *CeremonyDataClockConsensusEngine) GetProvingKey( + engineConfig *config.EngineConfig, +) (crypto.Signer, keys.KeyType, []byte, []byte) { + provingKey, err := e.keyManager.GetSigningKey(engineConfig.ProvingKeyId) + if errors.Is(err, keys.KeyNotFoundErr) { + e.logger.Info("could not get proving key, generating") + provingKey, err = e.keyManager.CreateSigningKey( + engineConfig.ProvingKeyId, + keys.KeyTypeEd448, + ) + } + + if err != nil { + e.logger.Error("could not get proving key", zap.Error(err)) + panic(err) + } + + rawKey, err := e.keyManager.GetRawKey(engineConfig.ProvingKeyId) + if err != nil { + e.logger.Error("could not get proving key type", zap.Error(err)) + panic(err) + } + + provingKeyType := rawKey.Type + + h, err := poseidon.HashBytes(rawKey.PublicKey) + if err != nil { + e.logger.Error("could not hash proving key", zap.Error(err)) + panic(err) + } + + provingKeyAddress := h.Bytes() + provingKeyAddress = append( + make([]byte, 32-len(provingKeyAddress)), + provingKeyAddress..., + ) + + return provingKey, provingKeyType, rawKey.PublicKey, provingKeyAddress +} + +func (e *CeremonyDataClockConsensusEngine) IsInProverTrie(key []byte) bool { + h, err := poseidon.HashBytes(key) + if err != nil { + return false + } + + provingKeyAddress := h.Bytes() + return e.frameProverTrie.Contains(provingKeyAddress) +} diff --git a/node/consensus/consensus_engine.go b/node/consensus/consensus_engine.go index 46c67e8..cf03d34 100644 --- a/node/consensus/consensus_engine.go +++ b/node/consensus/consensus_engine.go @@ -1,7 +1,12 @@ package consensus import ( + "crypto" + + "source.quilibrium.com/quilibrium/monorepo/node/config" "source.quilibrium.com/quilibrium/monorepo/node/execution" + "source.quilibrium.com/quilibrium/monorepo/node/keys" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" ) type EngineState int @@ -27,3 +32,19 @@ type ConsensusEngine interface { GetState() EngineState GetFrameChannel() <-chan uint64 } + +type DataConsensusEngine interface { + Start(filter []byte, seed []byte) <-chan error + Stop(force bool) <-chan error + RegisterExecutor(exec execution.ExecutionEngine, frame uint64) <-chan error + UnregisterExecutor(name string, frame uint64, force bool) <-chan error + GetFrame() uint64 + GetDifficulty() uint32 + GetState() EngineState + GetFrameChannel() <-chan *protobufs.ClockFrame + GetActiveFrame() *protobufs.ClockFrame + GetProvingKey( + engineConfig *config.EngineConfig, + ) (crypto.Signer, keys.KeyType, []byte, []byte) + IsInProverTrie(key []byte) bool +} diff --git a/node/consensus/master/broadcast_messaging.go b/node/consensus/master/broadcast_messaging.go index 1091679..10a602b 100644 --- a/node/consensus/master/broadcast_messaging.go +++ b/node/consensus/master/broadcast_messaging.go @@ -40,32 +40,27 @@ func (e *MasterClockConsensusEngine) handleMessage(message *pb.Message) error { for name := range e.executionEngines { name := name eg.Go(func() error { - applications := e.executionEngines[name].GetSupportedApplications() - for _, application := range applications { - if bytes.Equal(msg.Address, application.Address) { - messages, err := e.executionEngines[name].ProcessMessage( - msg.Address, - msg, - ) - if err != nil { - e.logger.Error( - "could not process message for engine", - zap.Error(err), - zap.String("engine_name", name), - ) - return errors.Wrap(err, "handle message") - } + messages, err := e.executionEngines[name].ProcessMessage( + msg.Address, + msg, + ) + if err != nil { + e.logger.Error( + "could not process message for engine", + zap.Error(err), + zap.String("engine_name", name), + ) + return errors.Wrap(err, "handle message") + } - for _, m := range messages { - if err := e.publishMessage(e.filter, m); err != nil { - e.logger.Error( - "could not publish message for engine", - zap.Error(err), - zap.String("engine_name", name), - ) - return errors.Wrap(err, "handle message") - } - } + for _, m := range messages { + if err := e.publishMessage(m.Address, m); err != nil { + e.logger.Error( + "could not publish message for engine", + zap.Error(err), + zap.String("engine_name", name), + ) + return errors.Wrap(err, "handle message") } } @@ -87,6 +82,7 @@ func (e *MasterClockConsensusEngine) handleMessage(message *pb.Message) error { return errors.Wrap(err, "handle message") } } + return nil } @@ -115,7 +111,10 @@ func (e *MasterClockConsensusEngine) handleClockFrameData( "frame difficulty mismatched", zap.Uint32("difficulty", frame.Difficulty), ) - return nil + return errors.Wrap( + errors.New("frame difficulty"), + "handle clock frame data", + ) } e.logger.Info( diff --git a/node/consensus/master/consensus_frames.go b/node/consensus/master/consensus_frames.go index 9fa47dc..b625067 100644 --- a/node/consensus/master/consensus_frames.go +++ b/node/consensus/master/consensus_frames.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/binary" "sort" - "strings" "time" "github.com/pkg/errors" @@ -56,10 +55,6 @@ func ( e *MasterClockConsensusEngine, ) createGenesisFrame() *protobufs.ClockFrame { e.logger.Info("creating genesis frame") - for _, l := range strings.Split(string(e.input), "\n") { - e.logger.Info(l) - } - b := sha3.Sum256(e.input) v := vdf.New(e.difficulty, b) diff --git a/node/consensus/master/master_clock_consensus_engine.go b/node/consensus/master/master_clock_consensus_engine.go index 130149a..97f5f8a 100644 --- a/node/consensus/master/master_clock_consensus_engine.go +++ b/node/consensus/master/master_clock_consensus_engine.go @@ -177,6 +177,10 @@ func (e *MasterClockConsensusEngine) Start() <-chan error { zap.Int("peer_store_count", e.pubSub.GetPeerstoreCount()), zap.Int("network_peer_count", e.pubSub.GetNetworkPeersCount()), ) + e.logger.Info( + "peers by bitmask", + zap.Any("peers", e.pubSub.GetBitmaskPeers()), + ) time.Sleep(10 * time.Second) } }() diff --git a/node/consensus/master/peer_messaging.go b/node/consensus/master/peer_messaging.go index 68baf88..4ef5e25 100644 --- a/node/consensus/master/peer_messaging.go +++ b/node/consensus/master/peer_messaging.go @@ -36,32 +36,27 @@ func (e *MasterClockConsensusEngine) handleSync(message *pb.Message) error { for name := range e.executionEngines { name := name eg.Go(func() error { - applications := e.executionEngines[name].GetSupportedApplications() - for _, application := range applications { - if bytes.Equal(msg.Address, application.Address) { - messages, err := e.executionEngines[name].ProcessMessage( - msg.Address, - msg, - ) - if err != nil { - e.logger.Error( - "could not process message for engine", - zap.Error(err), - zap.String("engine_name", name), - ) - return errors.Wrap(err, "handle message") - } + messages, err := e.executionEngines[name].ProcessMessage( + msg.Address, + msg, + ) + if err != nil { + e.logger.Error( + "could not process message for engine", + zap.Error(err), + zap.String("engine_name", name), + ) + return errors.Wrap(err, "handle message") + } - for _, m := range messages { - if err := e.publishMessage(e.filter, m); err != nil { - e.logger.Error( - "could not publish message for engine", - zap.Error(err), - zap.String("engine_name", name), - ) - return errors.Wrap(err, "handle message") - } - } + for _, m := range messages { + if err := e.publishMessage(e.filter, m); err != nil { + e.logger.Error( + "could not publish message for engine", + zap.Error(err), + zap.String("engine_name", name), + ) + return errors.Wrap(err, "handle message") } } diff --git a/node/crypto/doubleratchet.go b/node/crypto/doubleratchet.go index f3e70d2..3e7d6a1 100644 --- a/node/crypto/doubleratchet.go +++ b/node/crypto/doubleratchet.go @@ -16,8 +16,8 @@ import ( "source.quilibrium.com/quilibrium/monorepo/node/protobufs" ) -const PROTOCOL_VERSION = 1 -const PROTOCOL = 1<<8 + PROTOCOL_VERSION +const DOUBLE_RATCHET_PROTOCOL_VERSION = 1 +const DOUBLE_RATCHET_PROTOCOL = 1<<8 + DOUBLE_RATCHET_PROTOCOL_VERSION const CHAIN_KEY = 0x01 const MESSAGE_KEY = 0x02 @@ -29,7 +29,7 @@ const AEAD_KEY = 0x03 type DoubleRatchetParticipant struct { sendingEphemeralPrivateKey curves.Scalar receivingEphemeralKey curves.Point - curve curves.Curve + curve *curves.Curve keyManager keys.KeyManager rootKey []byte sendingChainKey []byte @@ -52,7 +52,7 @@ func NewDoubleRatchetParticipant( isSender bool, sendingEphemeralPrivateKey curves.Scalar, receivingEphemeralKey curves.Point, - curve curves.Curve, + curve *curves.Curve, keyManager keys.KeyManager, ) (*DoubleRatchetParticipant, error) { participant := &DoubleRatchetParticipant{} @@ -106,7 +106,7 @@ func (r *DoubleRatchetParticipant) RatchetEncrypt( message []byte, ) (*protobufs.P2PChannelEnvelope, error) { envelope := &protobufs.P2PChannelEnvelope{ - ProtocolIdentifier: PROTOCOL, + ProtocolIdentifier: DOUBLE_RATCHET_PROTOCOL, MessageHeader: &protobufs.MessageCiphertext{}, MessageBody: &protobufs.MessageCiphertext{}, } @@ -181,8 +181,6 @@ func (r *DoubleRatchetParticipant) RatchetDecrypt( } newChainKey, messageKey, aeadKey := ratchetKeys(r.receivingChainKey) - r.receivingChainKey = newChainKey - r.currentReceivingChainLength++ plaintext, err = r.decrypt( envelope.MessageBody, @@ -193,6 +191,9 @@ func (r *DoubleRatchetParticipant) RatchetDecrypt( ), ) + r.receivingChainKey = newChainKey + r.currentReceivingChainLength++ + return plaintext, errors.Wrap(err, "could not decrypt message") } diff --git a/node/crypto/doubleratchet_test.go b/node/crypto/doubleratchet_test.go index 438b62e..76ad924 100644 --- a/node/crypto/doubleratchet_test.go +++ b/node/crypto/doubleratchet_test.go @@ -43,7 +43,7 @@ func TestRatchetEncrypt(t *testing.T) { true, x448SendingEphemeralPrivateKey, x448ReceivingSignedPreKey, - *curves.ED448(), + curves.ED448(), nil, ) require.NoError(t, err) @@ -55,7 +55,7 @@ func TestRatchetEncrypt(t *testing.T) { false, x448ReceivingSignedPrePrivateKey, x448SendingEphemeralKey, - *curves.ED448(), + curves.ED448(), nil, ) require.NoError(t, err) diff --git a/node/crypto/fft.go b/node/crypto/fft.go index 72f992f..23ad694 100644 --- a/node/crypto/fft.go +++ b/node/crypto/fft.go @@ -86,7 +86,7 @@ func FFT( } // We make a copy so we can mutate it during the work. - workingValues := make([]curves.PairingScalar, width, width) + workingValues := make([]curves.PairingScalar, width) for i := 0; i < len(values); i++ { workingValue := values[i].Clone() workingValues[i] = workingValue.(curves.PairingScalar) @@ -101,7 +101,7 @@ func FFT( workingValues[i] = workingValue.(curves.PairingScalar) } - out := make([]curves.PairingScalar, width, width) + out := make([]curves.PairingScalar, width) stride := fftWidth / width for i := 0; i < len(out); i++ { @@ -210,7 +210,7 @@ func FFTG1( width = nearestPowerOfTwo(width) } - workingValues := make([]curves.PairingPoint, width, width) + workingValues := make([]curves.PairingPoint, width) for i := 0; i < len(values); i++ { workingValue, err := curve.NewG1GeneratorPoint().FromAffineCompressed( values[i].ToAffineCompressed(), @@ -224,7 +224,7 @@ func FFTG1( workingValues[i] = curve.NewG1IdentityPoint() } - out := make([]curves.PairingPoint, width, width) + out := make([]curves.PairingPoint, width) stride := fftWidth / width for i := 0; i < len(out); i++ { diff --git a/node/crypto/kzg.go b/node/crypto/kzg.go index 9d8acec..ffbf9a6 100644 --- a/node/crypto/kzg.go +++ b/node/crypto/kzg.go @@ -82,6 +82,8 @@ func Init() { panic(err) } + bls48581.Init() + cs := &CeremonyState{} if err := json.Unmarshal(csBytes, cs); err != nil { panic(err) @@ -607,7 +609,7 @@ func (p *KZGProver) CommitAggregate( var err error commitments[i], err = p.Commit(poly) if err != nil { - return nil, errors.Wrap(err, "prove aggregate") + return nil, errors.Wrap(err, "commit aggregate") } } diff --git a/node/crypto/kzg_test.go b/node/crypto/kzg_test.go index 115e2d0..87c4668 100644 --- a/node/crypto/kzg_test.go +++ b/node/crypto/kzg_test.go @@ -328,16 +328,7 @@ func TestKZGProof(t *testing.T) { commitment, proof, ) + require.False(t, proof.IsIdentity()) require.NoError(t, err) require.True(t, valid) } - -func ReverseScalarBytes(inBytes []byte) []byte { - outBytes := make([]byte, len(inBytes)) - - for i, j := 0, len(inBytes)-1; j >= 0; i, j = i+1, j-1 { - outBytes[i] = inBytes[j] - } - - return outBytes -} diff --git a/node/execution/ceremony/application/ceremony_application.go b/node/execution/ceremony/application/ceremony_application.go new file mode 100644 index 0000000..9e75c85 --- /dev/null +++ b/node/execution/ceremony/application/ceremony_application.go @@ -0,0 +1,1056 @@ +package application + +import ( + "bytes" + + "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/pkg/errors" + "google.golang.org/protobuf/proto" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/tries" +) + +var ErrInvalidStateTransition = errors.New("invalid state transition") + +type CeremonyApplicationState int + +var CEREMONY_ADDRESS = []byte{ + // SHA3-256("q_kzg_ceremony") + 0x34, 0x00, 0x1b, 0xe7, 0x43, 0x2c, 0x2e, 0x66, + 0x69, 0xad, 0xa0, 0x27, 0x97, 0x88, 0x68, 0x2a, + 0xb9, 0xf6, 0x26, 0x71, 0xb1, 0xb5, 0x38, 0xab, + 0x99, 0x50, 0x46, 0x94, 0xd9, 0x81, 0xcb, 0xd3, +} + +const ( + CEREMONY_APPLICATION_STATE_OPEN CeremonyApplicationState = iota + CEREMONY_APPLICATION_STATE_IN_PROGRESS + CEREMONY_APPLICATION_STATE_FINALIZING + CEREMONY_APPLICATION_STATE_VALIDATING +) + +func (s CeremonyApplicationState) String() string { + switch s { + case CEREMONY_APPLICATION_STATE_OPEN: + return "OPEN" + case CEREMONY_APPLICATION_STATE_IN_PROGRESS: + return "IN PROGRESS" + case CEREMONY_APPLICATION_STATE_FINALIZING: + return "FINALIZING" + case CEREMONY_APPLICATION_STATE_VALIDATING: + return "VALIDATING" + default: + return "UNKNOWN" + } +} + +type CeremonyApplication struct { + StateCount uint64 + RoundCount uint64 + LobbyState CeremonyApplicationState + ActiveParticipants []*protobufs.Ed448PublicKey + NextRoundPreferredParticipants []*protobufs.Ed448PublicKey + LatestSeenProverAttestations []*protobufs.CeremonySeenProverAttestation + DroppedParticipantAttestations []*protobufs.CeremonyDroppedProverAttestation + LobbyJoins []*protobufs.CeremonyLobbyJoin + TranscriptRoundAdvanceCommits []*protobufs.CeremonyAdvanceRound + FinalCommits []*protobufs.CeremonyTranscriptCommit + LatestTranscript *protobufs.CeremonyTranscript + RewardTrie *tries.RewardCritbitTrie + UpdatedTranscript *protobufs.CeremonyTranscript + TranscriptShares []*protobufs.CeremonyTranscriptShare +} + +func (a *CeremonyApplication) Equals(b *CeremonyApplication) bool { + if a.StateCount != b.StateCount { + return false + } + + if a.RoundCount != b.RoundCount { + return false + } + + if a.LobbyState != b.LobbyState { + return false + } + + if len(a.ActiveParticipants) != len(b.ActiveParticipants) { + return false + } + + for i := range a.ActiveParticipants { + if !bytes.Equal( + a.ActiveParticipants[i].KeyValue, + b.ActiveParticipants[i].KeyValue, + ) { + return false + } + } + + if len(a.NextRoundPreferredParticipants) != + len(b.NextRoundPreferredParticipants) { + return false + } + + for i := range a.NextRoundPreferredParticipants { + if !bytes.Equal( + a.NextRoundPreferredParticipants[i].KeyValue, + b.NextRoundPreferredParticipants[i].KeyValue, + ) { + return false + } + } + + if len(a.LatestSeenProverAttestations) != + len(b.LatestSeenProverAttestations) { + return false + } + + for i := range a.LatestSeenProverAttestations { + if b.LatestSeenProverAttestations[i].ProverSignature == nil { + return false + } + + if b.LatestSeenProverAttestations[i].ProverSignature.PublicKey == nil { + return false + } + + if b.LatestSeenProverAttestations[i].SeenProverKey == nil { + return false + } + + if !bytes.Equal( + a.LatestSeenProverAttestations[i].ProverSignature.Signature, + b.LatestSeenProverAttestations[i].ProverSignature.Signature, + ) { + return false + } + + if !bytes.Equal( + a.LatestSeenProverAttestations[i].ProverSignature.PublicKey.KeyValue, + b.LatestSeenProverAttestations[i].ProverSignature.PublicKey.KeyValue, + ) { + return false + } + + if !bytes.Equal( + a.LatestSeenProverAttestations[i].SeenProverKey.KeyValue, + b.LatestSeenProverAttestations[i].SeenProverKey.KeyValue, + ) { + return false + } + + if a.LatestSeenProverAttestations[i].LastSeenFrame != + b.LatestSeenProverAttestations[i].LastSeenFrame { + return false + } + } + + if len(a.DroppedParticipantAttestations) != + len(b.DroppedParticipantAttestations) { + return false + } + + for i := range a.DroppedParticipantAttestations { + if b.DroppedParticipantAttestations[i].ProverSignature == nil { + return false + } + + if b.DroppedParticipantAttestations[i].ProverSignature.PublicKey == nil { + return false + } + + if b.DroppedParticipantAttestations[i].DroppedProverKey == nil { + return false + } + + if !bytes.Equal( + a.DroppedParticipantAttestations[i].ProverSignature.Signature, + b.DroppedParticipantAttestations[i].ProverSignature.Signature, + ) { + return false + } + + if !bytes.Equal( + a.DroppedParticipantAttestations[i].ProverSignature.PublicKey.KeyValue, + b.DroppedParticipantAttestations[i].ProverSignature.PublicKey.KeyValue, + ) { + return false + } + + if !bytes.Equal( + a.DroppedParticipantAttestations[i].DroppedProverKey.KeyValue, + b.DroppedParticipantAttestations[i].DroppedProverKey.KeyValue, + ) { + return false + } + + if a.DroppedParticipantAttestations[i].LastSeenFrame != + b.DroppedParticipantAttestations[i].LastSeenFrame { + return false + } + } + + if len(a.LobbyJoins) != len(b.LobbyJoins) { + return false + } + + for i := range a.LobbyJoins { + if b.LobbyJoins[i].IdentityKey == nil { + return false + } + + if b.LobbyJoins[i].SignedPreKey == nil { + return false + } + + if b.LobbyJoins[i].PublicKeySignatureEd448 == nil { + return false + } + + if !bytes.Equal( + a.LobbyJoins[i].IdentityKey.KeyValue, + b.LobbyJoins[i].IdentityKey.KeyValue, + ) { + return false + } + + if !bytes.Equal( + a.LobbyJoins[i].SignedPreKey.KeyValue, + b.LobbyJoins[i].SignedPreKey.KeyValue, + ) { + return false + } + + if !bytes.Equal( + a.LobbyJoins[i].PublicKeySignatureEd448.Signature, + b.LobbyJoins[i].PublicKeySignatureEd448.Signature, + ) { + return false + } + + if a.LobbyJoins[i].FrameNumber != + b.LobbyJoins[i].FrameNumber { + return false + } + } + + if len(a.TranscriptRoundAdvanceCommits) != + len(b.TranscriptRoundAdvanceCommits) { + return false + } + + for i := range a.TranscriptRoundAdvanceCommits { + if len(a.TranscriptRoundAdvanceCommits[i].Commits) != + len(b.TranscriptRoundAdvanceCommits[i].Commits) { + return false + } + for j := range a.TranscriptRoundAdvanceCommits[i].Commits { + ca := a.TranscriptRoundAdvanceCommits[i].Commits[j] + cb := b.TranscriptRoundAdvanceCommits[i].Commits[j] + + if cb.ContributionSignature == nil { + return false + } + + if cb.ContributionSignature.PublicKey == nil { + return false + } + + if cb.ProverSignature == nil { + return false + } + + if cb.ProverSignature.PublicKey == nil { + return false + } + + if !bytes.Equal( + ca.ContributionSignature.Signature, + cb.ContributionSignature.Signature, + ) { + return false + } + + if !bytes.Equal( + ca.ContributionSignature.PublicKey.KeyValue, + cb.ContributionSignature.PublicKey.KeyValue, + ) { + return false + } + + if !bytes.Equal( + ca.ProverSignature.Signature, + cb.ProverSignature.Signature, + ) { + return false + } + + if !bytes.Equal( + ca.ProverSignature.PublicKey.KeyValue, + cb.ProverSignature.PublicKey.KeyValue, + ) { + return false + } + } + } + + if len(a.FinalCommits) != len(b.FinalCommits) { + return false + } + + for i := range a.FinalCommits { + ca := a.FinalCommits[i] + cb := b.FinalCommits[i] + + if cb.ContributionSignature == nil { + return false + } + + if cb.ContributionSignature.PublicKey == nil { + return false + } + + if cb.ProverSignature == nil { + return false + } + + if cb.ProverSignature.PublicKey == nil { + return false + } + + if !bytes.Equal( + ca.ContributionSignature.Signature, + cb.ContributionSignature.Signature, + ) { + return false + } + + if !bytes.Equal( + ca.ContributionSignature.PublicKey.KeyValue, + cb.ContributionSignature.PublicKey.KeyValue, + ) { + return false + } + + if !bytes.Equal( + ca.ProverSignature.Signature, + cb.ProverSignature.Signature, + ) { + return false + } + + if !bytes.Equal( + ca.ProverSignature.PublicKey.KeyValue, + cb.ProverSignature.PublicKey.KeyValue, + ) { + return false + } + } + + if a.LatestTranscript == nil && b.LatestTranscript != nil || + a.LatestTranscript != nil && b.LatestTranscript == nil { + return false + } + + if a.LatestTranscript != nil { + if len(a.LatestTranscript.G1Powers) != + len(b.LatestTranscript.G1Powers) { + return false + } + + if len(a.LatestTranscript.G2Powers) != + len(b.LatestTranscript.G2Powers) { + return false + } + + if len(a.LatestTranscript.RunningG1_256Witnesses) != + len(b.LatestTranscript.RunningG1_256Witnesses) { + return false + } + + if len(a.LatestTranscript.RunningG2_256Powers) != + len(b.LatestTranscript.RunningG2_256Powers) { + return false + } + + for i := range a.LatestTranscript.G1Powers { + if !bytes.Equal( + a.LatestTranscript.G1Powers[i].KeyValue, + b.LatestTranscript.G1Powers[i].KeyValue, + ) { + return false + } + } + + for i := range a.LatestTranscript.G2Powers { + if !bytes.Equal( + a.LatestTranscript.G2Powers[i].KeyValue, + b.LatestTranscript.G2Powers[i].KeyValue, + ) { + return false + } + } + + for i := range a.LatestTranscript.RunningG1_256Witnesses { + if !bytes.Equal( + a.LatestTranscript.RunningG1_256Witnesses[i].KeyValue, + b.LatestTranscript.RunningG1_256Witnesses[i].KeyValue, + ) { + return false + } + } + + for i := range a.LatestTranscript.RunningG2_256Powers { + if !bytes.Equal( + a.LatestTranscript.RunningG2_256Powers[i].KeyValue, + b.LatestTranscript.RunningG2_256Powers[i].KeyValue, + ) { + return false + } + } + } + + ra, err := a.RewardTrie.Serialize() + if err != nil { + return false + } + + rb, err := b.RewardTrie.Serialize() + if err != nil { + return false + } + + if !bytes.Equal(ra, rb) { + return false + } + + if a.UpdatedTranscript == nil && b.UpdatedTranscript != nil || + a.UpdatedTranscript != nil && b.UpdatedTranscript == nil { + return false + } + + if a.UpdatedTranscript != nil { + if len(a.UpdatedTranscript.G1Powers) != + len(b.UpdatedTranscript.G1Powers) { + return false + } + + if len(a.UpdatedTranscript.G2Powers) != + len(b.UpdatedTranscript.G2Powers) { + return false + } + + if len(a.UpdatedTranscript.RunningG1_256Witnesses) != + len(b.UpdatedTranscript.RunningG1_256Witnesses) { + return false + } + + if len(a.UpdatedTranscript.RunningG2_256Powers) != + len(b.UpdatedTranscript.RunningG2_256Powers) { + return false + } + + for i := range a.UpdatedTranscript.G1Powers { + if !bytes.Equal( + a.UpdatedTranscript.G1Powers[i].KeyValue, + b.UpdatedTranscript.G1Powers[i].KeyValue, + ) { + return false + } + } + + for i := range a.UpdatedTranscript.G2Powers { + if !bytes.Equal( + a.UpdatedTranscript.G2Powers[i].KeyValue, + b.UpdatedTranscript.G2Powers[i].KeyValue, + ) { + return false + } + } + + for i := range a.UpdatedTranscript.RunningG1_256Witnesses { + if !bytes.Equal( + a.UpdatedTranscript.RunningG1_256Witnesses[i].KeyValue, + b.UpdatedTranscript.RunningG1_256Witnesses[i].KeyValue, + ) { + return false + } + } + + for i := range a.UpdatedTranscript.RunningG2_256Powers { + if !bytes.Equal( + a.UpdatedTranscript.RunningG2_256Powers[i].KeyValue, + b.UpdatedTranscript.RunningG2_256Powers[i].KeyValue, + ) { + return false + } + } + } + + if len(a.TranscriptShares) != len(b.TranscriptShares) { + return false + } + + for i := range a.TranscriptShares { + if len(a.TranscriptShares[i].AdditiveG1Powers) != + len(b.TranscriptShares[i].AdditiveG1Powers) { + return false + } + + if len(a.TranscriptShares[i].AdditiveG2Powers) != + len(b.TranscriptShares[i].AdditiveG2Powers) { + return false + } + + for i := range a.TranscriptShares[i].AdditiveG1Powers { + if !bytes.Equal( + a.TranscriptShares[i].AdditiveG1Powers[i].KeyValue, + b.TranscriptShares[i].AdditiveG1Powers[i].KeyValue, + ) { + return false + } + } + + for i := range a.TranscriptShares[i].AdditiveG2Powers { + if !bytes.Equal( + a.TranscriptShares[i].AdditiveG2Powers[i].KeyValue, + b.TranscriptShares[i].AdditiveG2Powers[i].KeyValue, + ) { + return false + } + } + + if !bytes.Equal( + a.TranscriptShares[i].AdditiveG1_256Witness.KeyValue, + b.TranscriptShares[i].AdditiveG1_256Witness.KeyValue, + ) { + return false + } + + if !bytes.Equal( + a.TranscriptShares[i].AdditiveG2_256Witness.KeyValue, + b.TranscriptShares[i].AdditiveG2_256Witness.KeyValue, + ) { + return false + } + } + + return true +} + +func GetOutputsFromClockFrame( + frame *protobufs.ClockFrame, +) ( + *protobufs.CeremonyLobbyStateTransition, + *protobufs.CeremonyLobbyState, + error, +) { + var associatedProof []byte + var lobbyState *protobufs.CeremonyLobbyState + + if len(frame.AggregateProofs) > 0 { + for _, proofs := range frame.AggregateProofs { + for _, inclusion := range proofs.InclusionCommitments { + if inclusion.TypeUrl == protobufs.IntrinsicExecutionOutputType { + output := protobufs.IntrinsicExecutionOutput{} + if err := proto.Unmarshal(inclusion.Data, &output); err != nil { + return nil, nil, errors.Wrap(err, "get outputs from clock frame") + } + + lobbyState = &protobufs.CeremonyLobbyState{} + if err := proto.Unmarshal(output.Output, lobbyState); err != nil { + return nil, nil, errors.Wrap(err, "get outputs from clock frame") + } + + associatedProof = output.Proof + } + } + } + } + + transition := &protobufs.CeremonyLobbyStateTransition{} + if err := proto.Unmarshal(associatedProof, transition); err != nil { + return nil, nil, errors.Wrap(err, "get outputs from clock frame") + } + + return transition, lobbyState, nil +} + +func MaterializeApplicationFromFrame( + frame *protobufs.ClockFrame, +) (*CeremonyApplication, error) { + _, lobbyState, err := GetOutputsFromClockFrame(frame) + if err != nil { + return nil, errors.Wrap(err, "materialize application from frame") + } + + rewardTrie := &tries.RewardCritbitTrie{} + if err := rewardTrie.Deserialize(lobbyState.RewardTrie); err != nil { + return nil, errors.Wrap(err, "materialize application from frame") + } + + switch CeremonyApplicationState(lobbyState.LobbyState) { + case CEREMONY_APPLICATION_STATE_OPEN: + open := lobbyState.GetCeremonyOpenState() + if open == nil { + return nil, errors.Wrap( + errors.New("missing open state"), + "materialize application from frame", + ) + } + + stateCount := uint64(0) + + if len(open.JoinedParticipants) > 0 { + stateCount = frame.FrameNumber - + open.JoinedParticipants[len(open.JoinedParticipants)-1].FrameNumber + } + + return &CeremonyApplication{ + StateCount: stateCount, + RoundCount: 0, + LobbyState: CEREMONY_APPLICATION_STATE_OPEN, + LobbyJoins: open.JoinedParticipants, + NextRoundPreferredParticipants: open.PreferredParticipants, + LatestTranscript: lobbyState.LatestTranscript, + RewardTrie: rewardTrie, + }, nil + case CEREMONY_APPLICATION_STATE_IN_PROGRESS: + inProgress := lobbyState.GetCeremonyInProgressState() + if inProgress == nil { + return nil, errors.Wrap( + errors.New("missing in progress state"), + "materialize application from frame", + ) + } + + roundCount := len(inProgress.TranscriptRoundAdvanceCommits) + 1 + if roundCount > 1 && + len(inProgress.TranscriptRoundAdvanceCommits[roundCount-2].Commits) != + len(inProgress.ActiveParticipants) { + roundCount-- + } + + return &CeremonyApplication{ + StateCount: 0, + RoundCount: uint64(roundCount), + LobbyState: CEREMONY_APPLICATION_STATE_IN_PROGRESS, + NextRoundPreferredParticipants: inProgress.NextRoundParticipants, + DroppedParticipantAttestations: inProgress.DroppedParticipantAttestations, + LatestSeenProverAttestations: inProgress.LatestSeenProverAttestations, + ActiveParticipants: inProgress.ActiveParticipants, + LatestTranscript: lobbyState.LatestTranscript, + TranscriptRoundAdvanceCommits: inProgress.TranscriptRoundAdvanceCommits, + RewardTrie: rewardTrie, + }, nil + case CEREMONY_APPLICATION_STATE_FINALIZING: + finalizing := lobbyState.GetCeremonyFinalizingState() + if finalizing == nil { + return nil, errors.Wrap( + errors.New("missing finalizing state"), + "materialize application from frame", + ) + } + + return &CeremonyApplication{ + StateCount: 0, + RoundCount: 0, + LobbyState: CEREMONY_APPLICATION_STATE_FINALIZING, + ActiveParticipants: finalizing.ActiveParticipants, + FinalCommits: finalizing.Commits, + NextRoundPreferredParticipants: finalizing.NextRoundParticipants, + DroppedParticipantAttestations: finalizing.DroppedParticipantAttestations, + LatestSeenProverAttestations: finalizing.LatestSeenProverAttestations, + TranscriptShares: finalizing.Shares, + LatestTranscript: lobbyState.LatestTranscript, + RewardTrie: rewardTrie, + }, nil + case CEREMONY_APPLICATION_STATE_VALIDATING: + validating := lobbyState.GetCeremonyValidatingState() + if validating == nil { + return nil, errors.Wrap( + errors.New("missing validating state"), + "materialize application from frame", + ) + } + + return &CeremonyApplication{ + StateCount: 0, + RoundCount: 0, + LobbyState: CEREMONY_APPLICATION_STATE_VALIDATING, + FinalCommits: validating.Commits, + NextRoundPreferredParticipants: validating.NextRoundParticipants, + LatestTranscript: lobbyState.LatestTranscript, + UpdatedTranscript: validating.UpdatedTranscript, + RewardTrie: rewardTrie, + }, nil + } + + return nil, errors.Wrap( + errors.New("invalid state"), + "materialize application from frame", + ) +} + +func (a *CeremonyApplication) ApplyTransition( + currentFrameNumber uint64, + transition *protobufs.CeremonyLobbyStateTransition, +) (*CeremonyApplication, error) { + switch a.LobbyState { + case CEREMONY_APPLICATION_STATE_OPEN: + a.StateCount++ + + for i, url := range transition.TypeUrls { + switch url { + case protobufs.CeremonyLobbyJoinType: + join := &protobufs.CeremonyLobbyJoin{} + err := proto.Unmarshal(transition.TransitionInputs[i], join) + if err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + if err = a.applyLobbyJoin(join); err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + a.StateCount = 0 + default: + return a, nil + } + } + + if a.StateCount > 10 { + if len(a.LobbyJoins) == 0 { + return a, nil + } + + a.LobbyState = CEREMONY_APPLICATION_STATE_IN_PROGRESS + a.StateCount = 0 + a.RoundCount = 1 + + if err := a.finalizeParticipantSet(); err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + a.LobbyJoins = []*protobufs.CeremonyLobbyJoin{} + } + + return a, nil + case CEREMONY_APPLICATION_STATE_IN_PROGRESS: + for i, url := range transition.TypeUrls { + switch url { + case protobufs.CeremonySeenProverAttestationType: + seenProverAtt := &protobufs.CeremonySeenProverAttestation{} + err := proto.Unmarshal(transition.TransitionInputs[i], seenProverAtt) + if err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + if err = a.applySeenProverAttestation(seenProverAtt); err != nil { + return nil, errors.Wrap(err, "apply transition") + } + case protobufs.CeremonyDroppedProverAttestationType: + droppedProverAtt := &protobufs.CeremonyDroppedProverAttestation{} + err := proto.Unmarshal(transition.TransitionInputs[i], droppedProverAtt) + if err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + if err = a.applyDroppedProverAttestation(droppedProverAtt); err != nil { + return nil, errors.Wrap(err, "apply transition") + } + case protobufs.CeremonyTranscriptCommitType: + transcriptCommit := &protobufs.CeremonyTranscriptCommit{} + err := proto.Unmarshal(transition.TransitionInputs[i], transcriptCommit) + if err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + if err = a.applyTranscriptCommit(transcriptCommit); err != nil { + return nil, errors.Wrap(err, "apply transition") + } + default: + return a, nil + } + } + + maxRounds := uint64(1) + for i := 0; i < len(a.ActiveParticipants)-1; i++ { + maxRounds = maxRounds << 1 + } + + if a.RoundCount == maxRounds && + uint64(len(a.TranscriptRoundAdvanceCommits)) == a.RoundCount && + len(a.ActiveParticipants) == + len(a.TranscriptRoundAdvanceCommits[a.RoundCount-1].Commits) { + a.LobbyState = CEREMONY_APPLICATION_STATE_FINALIZING + a.FinalCommits = a.TranscriptRoundAdvanceCommits[a.RoundCount-1].Commits + a.RoundCount = 0 + a.StateCount = 0 + a.DroppedParticipantAttestations = + []*protobufs.CeremonyDroppedProverAttestation{} + a.LatestSeenProverAttestations = + []*protobufs.CeremonySeenProverAttestation{} + a.TranscriptRoundAdvanceCommits = + []*protobufs.CeremonyAdvanceRound{} + return a, nil + } + + attLimit := 1<= attLimit { + shouldReset = true + } + } + + if shouldReset { + a.LobbyState = CEREMONY_APPLICATION_STATE_OPEN + a.StateCount = 0 + a.RoundCount = 0 + for _, p := range a.ActiveParticipants { + if _, ok := droppedProversMap[string(p.KeyValue)]; !ok { + a.NextRoundPreferredParticipants = append( + append( + []*protobufs.Ed448PublicKey{}, + p, + ), + a.NextRoundPreferredParticipants..., + ) + } + } + a.ActiveParticipants = []*protobufs.Ed448PublicKey{} + a.DroppedParticipantAttestations = + []*protobufs.CeremonyDroppedProverAttestation{} + a.LatestSeenProverAttestations = + []*protobufs.CeremonySeenProverAttestation{} + a.TranscriptRoundAdvanceCommits = + []*protobufs.CeremonyAdvanceRound{} + } + + return a, nil + case CEREMONY_APPLICATION_STATE_FINALIZING: + for i, url := range transition.TypeUrls { + switch url { + case protobufs.CeremonySeenProverAttestationType: + seenProverAtt := &protobufs.CeremonySeenProverAttestation{} + err := proto.Unmarshal(transition.TransitionInputs[i], seenProverAtt) + if err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + if err = a.applySeenProverAttestation(seenProverAtt); err != nil { + return nil, errors.Wrap(err, "apply transition") + } + case protobufs.CeremonyDroppedProverAttestationType: + droppedProverAtt := &protobufs.CeremonyDroppedProverAttestation{} + err := proto.Unmarshal(transition.TransitionInputs[i], droppedProverAtt) + if err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + if err = a.applyDroppedProverAttestation(droppedProverAtt); err != nil { + return nil, errors.Wrap(err, "apply transition") + } + case protobufs.CeremonyTranscriptShareType: + transcriptShare := &protobufs.CeremonyTranscriptShare{} + err := proto.Unmarshal(transition.TransitionInputs[i], transcriptShare) + if err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + if err = a.applyTranscriptShare(transcriptShare); err != nil { + return nil, errors.Wrap(err, "apply transition") + } + default: + return a, nil + } + } + + if len(a.TranscriptShares) == len(a.ActiveParticipants) { + if err := a.finalizeTranscript(); err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + a.LobbyState = CEREMONY_APPLICATION_STATE_VALIDATING + a.ActiveParticipants = []*protobufs.Ed448PublicKey{} + a.DroppedParticipantAttestations = + []*protobufs.CeremonyDroppedProverAttestation{} + a.LatestSeenProverAttestations = + []*protobufs.CeremonySeenProverAttestation{} + + } + + shouldReset := false + droppedProversMap := map[string]int{} + for _, att := range a.DroppedParticipantAttestations { + if _, ok := droppedProversMap[string( + att.DroppedProverKey.KeyValue, + )]; !ok { + droppedProversMap[string(att.DroppedProverKey.KeyValue)] = 0 + } + + droppedProversMap[string(att.DroppedProverKey.KeyValue)]++ + + if droppedProversMap[string(att.DroppedProverKey.KeyValue)] >= len( + a.ActiveParticipants, + ) { + shouldReset = true + } + } + + if shouldReset { + a.LobbyState = CEREMONY_APPLICATION_STATE_OPEN + a.StateCount = 0 + a.RoundCount = 0 + for _, p := range a.ActiveParticipants { + if _, ok := droppedProversMap[string(p.KeyValue)]; !ok { + a.NextRoundPreferredParticipants = append( + append( + []*protobufs.Ed448PublicKey{}, + p, + ), + a.NextRoundPreferredParticipants..., + ) + } + } + a.ActiveParticipants = []*protobufs.Ed448PublicKey{} + a.DroppedParticipantAttestations = + []*protobufs.CeremonyDroppedProverAttestation{} + a.LatestSeenProverAttestations = + []*protobufs.CeremonySeenProverAttestation{} + a.TranscriptRoundAdvanceCommits = + []*protobufs.CeremonyAdvanceRound{} + a.TranscriptShares = + []*protobufs.CeremonyTranscriptShare{} + } + + return a, nil + case CEREMONY_APPLICATION_STATE_VALIDATING: + for i, url := range transition.TypeUrls { + switch url { + case protobufs.CeremonyTranscriptType: + transcript := &protobufs.CeremonyTranscript{} + err := proto.Unmarshal(transition.TransitionInputs[i], transcript) + if err != nil { + return nil, errors.Wrap(err, "apply transition") + } + + if err = a.applyTranscript(transcript); err != nil { + return nil, errors.Wrap(err, "apply transition") + } + default: + return a, nil + } + } + + if a.UpdatedTranscript == nil { + rewardMultiplier := uint64(1) + for i := 0; i < len(a.FinalCommits)-1; i++ { + rewardMultiplier = rewardMultiplier << 1 + } + + for _, c := range a.FinalCommits { + h, err := poseidon.HashBytes(c.ProverSignature.PublicKey.KeyValue) + if err != nil { + panic(err) + } + + addr := h.Bytes() + addr = append( + make([]byte, 32-len(addr)), + addr..., + ) + + a.RewardTrie.Add( + addr, + currentFrameNumber, + rewardMultiplier*161, + ) + } + + a.LobbyState = CEREMONY_APPLICATION_STATE_OPEN + a.StateCount = 0 + a.RoundCount = 0 + a.ActiveParticipants = []*protobufs.Ed448PublicKey{} + a.DroppedParticipantAttestations = + []*protobufs.CeremonyDroppedProverAttestation{} + a.LatestSeenProverAttestations = + []*protobufs.CeremonySeenProverAttestation{} + a.TranscriptRoundAdvanceCommits = + []*protobufs.CeremonyAdvanceRound{} + a.TranscriptShares = + []*protobufs.CeremonyTranscriptShare{} + a.FinalCommits = []*protobufs.CeremonyTranscriptCommit{} + } + + return a, nil + default: + return nil, errors.Wrap(ErrInvalidStateTransition, "apply transition") + } +} + +func (a *CeremonyApplication) MaterializeLobbyStateFromApplication() ( + *protobufs.CeremonyLobbyState, + error, +) { + var err error + state := &protobufs.CeremonyLobbyState{} + state.LobbyState = int32(a.LobbyState) + state.LatestTranscript = a.LatestTranscript + state.RewardTrie, err = a.RewardTrie.Serialize() + if err != nil { + return nil, errors.Wrap(err, "materialize lobby state from application") + } + + switch a.LobbyState { + case CEREMONY_APPLICATION_STATE_OPEN: + state.CeremonyState = &protobufs.CeremonyLobbyState_CeremonyOpenState{ + CeremonyOpenState: &protobufs.CeremonyOpenState{ + JoinedParticipants: a.LobbyJoins, + PreferredParticipants: a.NextRoundPreferredParticipants, + }, + } + case CEREMONY_APPLICATION_STATE_IN_PROGRESS: + state.CeremonyState = &protobufs.CeremonyLobbyState_CeremonyInProgressState{ + CeremonyInProgressState: &protobufs.CeremonyInProgressState{ + ActiveParticipants: a.ActiveParticipants, + LatestSeenProverAttestations: a.LatestSeenProverAttestations, + DroppedParticipantAttestations: a.DroppedParticipantAttestations, + TranscriptRoundAdvanceCommits: a.TranscriptRoundAdvanceCommits, + NextRoundParticipants: a.NextRoundPreferredParticipants, + }, + } + case CEREMONY_APPLICATION_STATE_FINALIZING: + state.CeremonyState = &protobufs.CeremonyLobbyState_CeremonyFinalizingState{ + CeremonyFinalizingState: &protobufs.CeremonyFinalizingState{ + ActiveParticipants: a.ActiveParticipants, + LatestSeenProverAttestations: a.LatestSeenProverAttestations, + DroppedParticipantAttestations: a.DroppedParticipantAttestations, + Commits: a.FinalCommits, + Shares: a.TranscriptShares, + NextRoundParticipants: a.NextRoundPreferredParticipants, + }, + } + case CEREMONY_APPLICATION_STATE_VALIDATING: + state.CeremonyState = &protobufs.CeremonyLobbyState_CeremonyValidatingState{ + CeremonyValidatingState: &protobufs.CeremonyValidatingState{ + Commits: a.FinalCommits, + UpdatedTranscript: a.UpdatedTranscript, + NextRoundParticipants: a.NextRoundPreferredParticipants, + }, + } + } + + return state, nil +} diff --git a/node/execution/ceremony/application/ceremony_application_finalizing.go b/node/execution/ceremony/application/ceremony_application_finalizing.go new file mode 100644 index 0000000..b0f6a34 --- /dev/null +++ b/node/execution/ceremony/application/ceremony_application_finalizing.go @@ -0,0 +1,262 @@ +package application + +import ( + "bytes" + "fmt" + + "github.com/pkg/errors" + "golang.org/x/sync/errgroup" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func (a *CeremonyApplication) applyTranscriptShare( + share *protobufs.CeremonyTranscriptShare, +) error { + if len(share.AdditiveG1Powers) != len(a.LatestTranscript.G1Powers)-1 { + return errors.Wrap(errors.New("invalid g1s"), "apply transcript share") + } + if len(share.AdditiveG2Powers) != len(a.LatestTranscript.G2Powers)-1 { + return errors.Wrap(errors.New("invalid g2s"), "apply transcript share") + } + if share.AdditiveG1_256Witness == nil || + share.AdditiveG1_256Witness.KeyValue == nil { + return errors.Wrap( + errors.New("invalid g1 witness"), + "apply transcript share", + ) + } + if _, err := curves.BLS48581G1().Point.FromAffineCompressed( + share.AdditiveG1_256Witness.KeyValue, + ); err != nil { + return errors.Wrap( + errors.Wrap(err, "invalid g1 witness"), + "apply transcript share", + ) + } + if share.AdditiveG2_256Witness == nil || + share.AdditiveG2_256Witness.KeyValue == nil { + return errors.Wrap( + errors.New("invalid g2 witness"), + "apply transcript share", + ) + } + + for _, s := range a.TranscriptShares { + if bytes.Equal( + s.AdditiveG1Powers[0].KeyValue, + share.AdditiveG1Powers[0].KeyValue, + ) { + return nil + } + } + + matchFound := false + + for _, c := range a.FinalCommits { + if bytes.Equal( + share.ProverSignature.PublicKey.KeyValue, + c.ProverSignature.PublicKey.KeyValue, + ) { + matchFound = true + break + } + } + + if !matchFound { + return errors.Wrap( + errors.New( + fmt.Sprintf( + "no corresponding commit in commit set (size %d)", + len(a.FinalCommits), + ), + ), + "apply transcript share", + ) + } + + if err := share.VerifySignature(); err != nil { + return errors.Wrap(err, "apply transcript share") + } + + eg := errgroup.Group{} + eg.SetLimit(100) + + for i, g1 := range a.LatestTranscript.G1Powers { + i := i + g1 := g1 + eg.Go(func() error { + if _, err := curves.BLS48581G1().Point.FromAffineCompressed( + g1.KeyValue, + ); err != nil { + return errors.Wrap( + errors.Wrap(err, fmt.Sprintf("invalid g1 at position %d", i)), + "apply transcript share", + ) + } + return nil + }) + } + + for i, g2 := range a.LatestTranscript.G2Powers { + i := i + g2 := g2 + eg.Go(func() error { + if _, err := curves.BLS48581G2().Point.FromAffineCompressed( + g2.KeyValue, + ); err != nil { + return errors.Wrap( + errors.Wrap(err, fmt.Sprintf("invalid g2 at position %d", i)), + "apply transcript share", + ) + } + return nil + }) + } + + if err := eg.Wait(); err != nil { + return err + } + + exists := false + for _, s := range a.TranscriptShares { + exists = bytes.Equal( + s.ProverSignature.Signature, + share.ProverSignature.Signature, + ) + if exists { + break + } + } + + if !exists { + a.TranscriptShares = append(a.TranscriptShares, share) + } + + return nil +} + +func (a *CeremonyApplication) finalizeTranscript() error { + a.UpdatedTranscript = &protobufs.CeremonyTranscript{ + G1Powers: make( + []*protobufs.BLS48581G1PublicKey, + len(a.LatestTranscript.G1Powers), + ), + G2Powers: make( + []*protobufs.BLS48581G2PublicKey, + len(a.LatestTranscript.G2Powers), + ), + RunningG1_256Witnesses: a.LatestTranscript.RunningG1_256Witnesses, + RunningG2_256Powers: a.LatestTranscript.RunningG2_256Powers, + } + + a.UpdatedTranscript.G1Powers[0] = a.LatestTranscript.G1Powers[0] + a.UpdatedTranscript.G2Powers[0] = a.LatestTranscript.G2Powers[0] + + for i := range a.UpdatedTranscript.G1Powers[1:] { + g1, err := curves.BLS48581G1().Point.FromAffineCompressed( + a.TranscriptShares[0].AdditiveG1Powers[i].KeyValue, + ) + if err != nil { + return errors.Wrap(err, "finalize transcript") + } + + if len(a.TranscriptShares) > 1 { + for _, share := range a.TranscriptShares[1:] { + ag1, err := curves.BLS48581G1().Point.FromAffineCompressed( + share.AdditiveG1Powers[i].KeyValue, + ) + if err != nil { + return errors.Wrap(err, "finalize transcript") + } + + g1 = g1.Add(ag1) + } + } + + if !g1.IsOnCurve() || g1.IsIdentity() { + return errors.Wrap( + errors.New("invalid g1 power"), + "finalize transcript", + ) + } + + a.UpdatedTranscript.G1Powers[i+1] = &protobufs.BLS48581G1PublicKey{ + KeyValue: g1.ToAffineCompressed(), + } + } + + for i := range a.UpdatedTranscript.G2Powers[1:] { + g2, err := curves.BLS48581G2().Point.FromAffineCompressed( + a.TranscriptShares[0].AdditiveG2Powers[i].KeyValue, + ) + if err != nil { + return errors.Wrap(err, "finalize transcript") + } + + if len(a.TranscriptShares) > 1 { + for _, share := range a.TranscriptShares[1:] { + ag2, err := curves.BLS48581G2().Point.FromAffineCompressed( + share.AdditiveG2Powers[i].KeyValue, + ) + if err != nil { + return errors.Wrap(err, "finalize transcript") + } + + g2 = g2.Add(ag2) + } + } + + if !g2.IsOnCurve() || g2.IsIdentity() { + return errors.Wrap( + errors.New("invalid g2 power"), + "finalize transcript", + ) + } + + a.UpdatedTranscript.G2Powers[i+1] = &protobufs.BLS48581G2PublicKey{ + KeyValue: g2.ToAffineCompressed(), + } + } + + g1Witness, err := curves.BLS48581G1().Point.FromAffineCompressed( + a.TranscriptShares[0].AdditiveG1_256Witness.KeyValue, + ) + if err != nil { + return errors.Wrap(err, "finalize transcript") + } + + if len(a.TranscriptShares) > 1 { + for _, share := range a.TranscriptShares[1:] { + ag1, err := curves.BLS48581G1().Point.FromAffineCompressed( + share.AdditiveG1_256Witness.KeyValue, + ) + if err != nil { + return errors.Wrap(err, "finalize transcript") + } + + g1Witness = g1Witness.Add(ag1) + } + } + + if !g1Witness.IsOnCurve() || g1Witness.IsIdentity() { + return errors.Wrap( + errors.New("invalid witness"), + "finalize transcript", + ) + } + + a.UpdatedTranscript.RunningG1_256Witnesses = append( + a.UpdatedTranscript.RunningG1_256Witnesses, + &protobufs.BLS48581G1PublicKey{ + KeyValue: g1Witness.ToAffineCompressed(), + }, + ) + + a.UpdatedTranscript.RunningG2_256Powers = append( + a.UpdatedTranscript.RunningG2_256Powers, + a.UpdatedTranscript.G2Powers[len(a.UpdatedTranscript.G2Powers)-1], + ) + + return nil +} diff --git a/node/execution/ceremony/application/ceremony_application_in_progress.go b/node/execution/ceremony/application/ceremony_application_in_progress.go new file mode 100644 index 0000000..f7f9a4e --- /dev/null +++ b/node/execution/ceremony/application/ceremony_application_in_progress.go @@ -0,0 +1,252 @@ +package application + +import ( + "bytes" + "encoding/binary" + + "github.com/pkg/errors" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func (a *CeremonyApplication) applySeenProverAttestation( + seenProverAttestation *protobufs.CeremonySeenProverAttestation, +) error { + if seenProverAttestation.SeenProverKey == nil || + seenProverAttestation.SeenProverKey.KeyValue == nil { + return errors.Wrap( + errors.New("signature is nil"), + "apply seen prover attestation", + ) + } + + inParticipantList := false + for _, p := range a.ActiveParticipants { + if bytes.Equal(p.KeyValue, seenProverAttestation.SeenProverKey.KeyValue) { + inParticipantList = true + break + } + } + + if !inParticipantList { + return errors.Wrap( + errors.New("prover not in active participant list"), + "apply seen prover attestation", + ) + } + + b := binary.BigEndian.AppendUint64( + []byte("lastseen"), + seenProverAttestation.LastSeenFrame, + ) + b = append(b, seenProverAttestation.SeenProverKey.KeyValue...) + signature := seenProverAttestation.GetProverSignature() + if signature == nil { + return errors.Wrap( + errors.New("signature is nil"), + "apply seen prover attestation", + ) + } + + if err := signature.Verify(b); err != nil { + return errors.Wrap(err, "apply seen prover attestation") + } + + replaced := false + for i, att := range a.LatestSeenProverAttestations { + if bytes.Equal( + att.SeenProverKey.KeyValue, + seenProverAttestation.SeenProverKey.KeyValue, + ) && + bytes.Equal( + att.ProverSignature.PublicKey.KeyValue, + seenProverAttestation.ProverSignature.PublicKey.KeyValue, + ) && att.LastSeenFrame < seenProverAttestation.LastSeenFrame { + a.LatestSeenProverAttestations[i] = att + replaced = true + break + } + } + + if !replaced { + a.LatestSeenProverAttestations = append( + a.LatestSeenProverAttestations, + seenProverAttestation, + ) + } + + return nil +} + +func (a *CeremonyApplication) applyDroppedProverAttestation( + droppedProverAttestation *protobufs.CeremonyDroppedProverAttestation, +) error { + if droppedProverAttestation.DroppedProverKey == nil || + droppedProverAttestation.DroppedProverKey.KeyValue == nil { + return errors.Wrap( + errors.New("signature is nil"), + "apply dropped prover attestation", + ) + } + + inParticipantList := false + for _, p := range a.ActiveParticipants { + if bytes.Equal( + p.KeyValue, + droppedProverAttestation.DroppedProverKey.KeyValue, + ) { + inParticipantList = true + break + } + } + + if !inParticipantList { + return errors.Wrap( + errors.New("prover not in active participant list"), + "apply dropped prover attestation", + ) + } + + b := binary.BigEndian.AppendUint64( + []byte("dropped"), + droppedProverAttestation.LastSeenFrame, + ) + b = append(b, droppedProverAttestation.DroppedProverKey.KeyValue...) + signature := droppedProverAttestation.GetProverSignature() + if signature == nil { + return errors.Wrap( + errors.New("signature is nil"), + "apply dropped prover attestation", + ) + } + + if err := signature.Verify(b); err != nil { + return errors.Wrap(err, "apply dropped prover attestation") + } + + replaced := false + for i, att := range a.DroppedParticipantAttestations { + if bytes.Equal( + att.DroppedProverKey.KeyValue, + droppedProverAttestation.DroppedProverKey.KeyValue, + ) && + bytes.Equal( + att.ProverSignature.PublicKey.KeyValue, + droppedProverAttestation.ProverSignature.PublicKey.KeyValue, + ) && att.LastSeenFrame < droppedProverAttestation.LastSeenFrame { + a.DroppedParticipantAttestations[i] = att + replaced = true + break + } + } + + if !replaced { + a.DroppedParticipantAttestations = append( + a.DroppedParticipantAttestations, + droppedProverAttestation, + ) + } + + return nil +} + +func (a *CeremonyApplication) applyTranscriptCommit( + transcriptCommit *protobufs.CeremonyTranscriptCommit, +) error { + if transcriptCommit.ContributionSignature == nil || + transcriptCommit.ProverSignature == nil || + transcriptCommit.ContributionSignature.PublicKey == nil || + transcriptCommit.ProverSignature.PublicKey == nil { + return errors.Wrap( + errors.New("signature is nil"), + "apply transcript commit", + ) + } + + point, err := curves.BLS48581G2().Point.FromAffineCompressed( + transcriptCommit.ContributionSignature.PublicKey.KeyValue, + ) + if err != nil { + return errors.Wrap(err, "apply transcript commit") + } + + if err := VerifySignatureOfProverKey( + transcriptCommit.ProverSignature.PublicKey.KeyValue, + transcriptCommit.ContributionSignature.Signature, + point, + ); err != nil { + return errors.Wrap(err, "apply transcript commit") + } + + if err := transcriptCommit.ProverSignature.Verify( + transcriptCommit.ContributionSignature.PublicKey.KeyValue, + ); err != nil { + return errors.Wrap(err, "apply transcript commit") + } + + inParticipantList := false + for _, p := range a.ActiveParticipants { + if bytes.Equal( + p.KeyValue, + transcriptCommit.ProverSignature.PublicKey.KeyValue, + ) { + inParticipantList = true + break + } + } + + if !inParticipantList { + return errors.Wrap( + errors.New("prover not in active participant list"), + "apply transcript commit", + ) + } + + maxRounds := uint64(1) + for i := 0; i < len(a.ActiveParticipants)-1; i++ { + maxRounds = maxRounds << 1 + } + + if len(a.TranscriptRoundAdvanceCommits) == 0 { + a.TranscriptRoundAdvanceCommits = []*protobufs.CeremonyAdvanceRound{ + { + Commits: []*protobufs.CeremonyTranscriptCommit{}, + }, + } + } + + if len(a.TranscriptRoundAdvanceCommits[a.RoundCount-1].Commits) == + len(a.ActiveParticipants) { + if maxRounds == + uint64(len(a.TranscriptRoundAdvanceCommits)) { + return errors.Wrap( + errors.New("round limit exceeded"), + "apply transcript commit", + ) + } + a.TranscriptRoundAdvanceCommits = append( + a.TranscriptRoundAdvanceCommits, + &protobufs.CeremonyAdvanceRound{ + Commits: []*protobufs.CeremonyTranscriptCommit{ + transcriptCommit, + }, + }, + ) + a.RoundCount++ + } else { + for _, c := range a.TranscriptRoundAdvanceCommits[a.RoundCount-1].Commits { + if bytes.Equal( + c.ProverSignature.PublicKey.KeyValue, + transcriptCommit.ProverSignature.PublicKey.KeyValue, + ) { + return nil + } + } + a.TranscriptRoundAdvanceCommits[a.RoundCount-1].Commits = append( + a.TranscriptRoundAdvanceCommits[a.RoundCount-1].Commits, + transcriptCommit, + ) + } + + return nil +} diff --git a/node/execution/ceremony/application/ceremony_application_open.go b/node/execution/ceremony/application/ceremony_application_open.go new file mode 100644 index 0000000..3d06ba2 --- /dev/null +++ b/node/execution/ceremony/application/ceremony_application_open.go @@ -0,0 +1,100 @@ +package application + +import ( + "bytes" + + "github.com/pkg/errors" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func (a *CeremonyApplication) applyLobbyJoin( + join *protobufs.CeremonyLobbyJoin, +) error { + signature := join.GetPublicKeySignatureEd448() + if signature == nil { + return errors.Wrap(errors.New("signature is nil"), "apply lobby join") + } + if join.IdentityKey == nil || join.IdentityKey.KeyValue == nil { + return errors.Wrap(errors.New("identity key is nil"), "apply lobby join") + } + if join.SignedPreKey == nil || join.SignedPreKey.KeyValue == nil { + return errors.Wrap(errors.New("signed prekey is nil"), "apply lobby join") + } + if _, err := curves.ED448().Point.FromAffineCompressed( + join.IdentityKey.KeyValue, + ); err != nil { + return errors.Wrap(err, "apply lobby join") + } + if _, err := curves.ED448().Point.FromAffineCompressed( + join.SignedPreKey.KeyValue, + ); err != nil { + return errors.Wrap(err, "apply lobby join") + } + if err := join.VerifySignature(); err != nil { + return errors.Wrap(err, "apply lobby join") + } + + if len(a.LobbyJoins) == 256 { + return nil + } + + for _, p := range a.LobbyJoins { + if bytes.Equal( + p.PublicKeySignatureEd448.PublicKey.KeyValue, + signature.PublicKey.KeyValue, + ) { + return nil + } + } + + prepend := false + nextRoundPreferredParticipants := []*protobufs.Ed448PublicKey{} + for _, p := range a.NextRoundPreferredParticipants { + if !bytes.Equal(p.KeyValue, signature.PublicKey.KeyValue) { + nextRoundPreferredParticipants = append( + nextRoundPreferredParticipants, + p, + ) + } + } + + if len(a.NextRoundPreferredParticipants) != + len(nextRoundPreferredParticipants) { + prepend = true + } + + a.NextRoundPreferredParticipants = nextRoundPreferredParticipants + + if prepend { + a.LobbyJoins = append( + append([]*protobufs.CeremonyLobbyJoin{}, join), + a.LobbyJoins..., + ) + } else { + a.LobbyJoins = append(a.LobbyJoins, join) + } + + return nil +} + +func (a *CeremonyApplication) finalizeParticipantSet() error { + power := uint64(1) + for uint64(len(a.LobbyJoins)) > power { + power = power << 1 + } + + if power != uint64(len(a.LobbyJoins)) { + power = power >> 1 + } + + a.ActiveParticipants = []*protobufs.Ed448PublicKey{} + for i := 0; i < int(power); i++ { + a.ActiveParticipants = append( + a.ActiveParticipants, + a.LobbyJoins[i].PublicKeySignatureEd448.PublicKey, + ) + } + + return nil +} diff --git a/node/execution/ceremony/application/ceremony_application_test.go b/node/execution/ceremony/application/ceremony_application_test.go new file mode 100644 index 0000000..be3f033 --- /dev/null +++ b/node/execution/ceremony/application/ceremony_application_test.go @@ -0,0 +1,284 @@ +package application + +import ( + "bytes" + "crypto" + "crypto/rand" + "testing" + + "github.com/cloudflare/circl/sign/ed448" + "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + bls48581 "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves/native/bls48581" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/tries" +) + +func TestCeremonyTransitions(t *testing.T) { + bls48581.Init() + old := curves.BLS48581G1().Scalar.Random(rand.Reader) + old2 := old.Mul(old) + old3 := old2.Mul(old) + + proverPubKey, proverKey, err := ed448.GenerateKey(rand.Reader) + require.NoError(t, err) + idk := curves.ED448().Scalar.Random(rand.Reader) + idkPub := curves.ED448().Point.Generator().Mul(idk).ToAffineCompressed() + spk := curves.ED448().Scalar.Random(rand.Reader) + spkPub := curves.ED448().Point.Generator().Mul(spk).ToAffineCompressed() + require.NoError(t, err) + + trie := &tries.RewardCritbitTrie{} + + a := &CeremonyApplication{ + RewardTrie: trie, + LatestTranscript: &protobufs.CeremonyTranscript{ + G1Powers: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old2, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old3, + ).ToAffineCompressed(), + }, + }, + G2Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + }, + RunningG1_256Witnesses: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + }, + RunningG2_256Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + }, + }, + } + + join := &protobufs.CeremonyLobbyJoin{ + FrameNumber: 0, + IdentityKey: &protobufs.X448PublicKey{ + KeyValue: idkPub, + }, + SignedPreKey: &protobufs.X448PublicKey{ + KeyValue: spkPub, + }, + } + sig, err := join.SignWithProverKey(proverKey) + require.NoError(t, err) + join.PublicKeySignatureEd448 = &protobufs.Ed448Signature{ + Signature: sig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: proverPubKey, + }, + } + joinBytes, err := proto.Marshal(join) + require.NoError(t, err) + + a, err = a.ApplyTransition(0, &protobufs.CeremonyLobbyStateTransition{ + TypeUrls: []string{protobufs.CeremonyLobbyJoinType}, + TransitionInputs: [][]byte{joinBytes}, + }) + require.NoError(t, err) + require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_OPEN) + + for i := uint64(0); i < 10; i++ { + a, err = a.ApplyTransition(i+1, &protobufs.CeremonyLobbyStateTransition{ + TypeUrls: []string{}, + TransitionInputs: [][]byte{}, + }) + require.NoError(t, err) + require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_OPEN) + } + + a, err = a.ApplyTransition(12, &protobufs.CeremonyLobbyStateTransition{ + TypeUrls: []string{}, + TransitionInputs: [][]byte{}, + }) + require.NoError(t, err) + require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_IN_PROGRESS) + require.True(t, bytes.Equal(a.ActiveParticipants[0].KeyValue, proverPubKey)) + + tau := curves.BLS48581G1().Scalar.Random(rand.Reader) + tau2 := tau.Mul(tau) + tau3 := tau2.Mul(tau) + tauPubG2 := curves.BLS48581G2().Point.Generator().Mul(tau) + + proverSig, err := proverKey.Sign( + rand.Reader, + tauPubG2.ToAffineCompressed(), + crypto.Hash(0), + ) + require.NoError(t, err) + + blsSignature := make([]byte, int(bls48581.MODBYTES)+1) + key := tau.Bytes() + + if bls48581.Core_Sign(blsSignature, proverPubKey, key) != bls48581.BLS_OK { + require.Fail(t, "could not sign") + } + + blsSig := blsSignature[:] + + advanceRound := &protobufs.CeremonyTranscriptCommit{ + ProverSignature: &protobufs.Ed448Signature{ + Signature: proverSig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: proverPubKey, + }, + }, + ContributionSignature: &protobufs.BLS48581Signature{ + Signature: blsSig, + PublicKey: &protobufs.BLS48581G2PublicKey{ + KeyValue: tauPubG2.ToAffineCompressed(), + }, + }, + } + advanceRoundBytes, err := proto.Marshal(advanceRound) + + require.NoError(t, err) + a, err = a.ApplyTransition(13, &protobufs.CeremonyLobbyStateTransition{ + TypeUrls: []string{protobufs.CeremonyTranscriptCommitType}, + TransitionInputs: [][]byte{advanceRoundBytes}, + }) + require.NoError(t, err) + require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_FINALIZING) + + g1 := curves.BLS48581G1().Point.Generator() + g2 := curves.BLS48581G2().Point.Generator() + transcriptShare := &protobufs.CeremonyTranscriptShare{ + AdditiveG1Powers: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: g1.Mul(old.Mul(tau)).ToAffineCompressed(), + }, + { + KeyValue: g1.Mul(old2.Mul(tau2)).ToAffineCompressed(), + }, + { + KeyValue: g1.Mul(old3.Mul(tau3)).ToAffineCompressed(), + }, + }, + AdditiveG2Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: g2.Mul(old.Mul(tau)).ToAffineCompressed(), + }, + }, + AdditiveG1_256Witness: &protobufs.BLS48581G1PublicKey{ + KeyValue: g1.Mul(tau).ToAffineCompressed(), + }, + AdditiveG2_256Witness: &protobufs.BLS48581G2PublicKey{ + KeyValue: g2.Mul(old.Mul(tau)).ToAffineCompressed(), + }, + } + sig, err = transcriptShare.SignWithProverKey(proverKey) + require.NoError(t, err) + transcriptShare.ProverSignature = &protobufs.Ed448Signature{ + Signature: sig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: proverPubKey, + }, + } + shareBytes, err := proto.Marshal(transcriptShare) + require.NoError(t, err) + + a, err = a.ApplyTransition(14, &protobufs.CeremonyLobbyStateTransition{ + TypeUrls: []string{protobufs.CeremonyTranscriptShareType}, + TransitionInputs: [][]byte{shareBytes}, + }) + require.NoError(t, err) + require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_VALIDATING) + + updatedTranscript := &protobufs.CeremonyTranscript{ + G1Powers: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old, + ).Mul(tau).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old2, + ).Mul(tau2).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old3, + ).Mul(tau3).ToAffineCompressed(), + }, + }, + G2Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).Mul(tau).ToAffineCompressed(), + }, + }, + RunningG1_256Witnesses: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + tau, + ).ToAffineCompressed(), + }, + }, + RunningG2_256Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).Mul(tau).ToAffineCompressed(), + }, + }, + } + transcriptBytes, err := proto.Marshal(updatedTranscript) + require.NoError(t, err) + a, err = a.ApplyTransition(15, &protobufs.CeremonyLobbyStateTransition{ + TypeUrls: []string{protobufs.CeremonyTranscriptType}, + TransitionInputs: [][]byte{transcriptBytes}, + }) + require.NoError(t, err) + require.Equal(t, a.LobbyState, CEREMONY_APPLICATION_STATE_OPEN) + bi, err := poseidon.HashBytes(proverPubKey) + require.NoError(t, err) + addr := bi.FillBytes(make([]byte, 32)) + _, f, reward := a.RewardTrie.Get(addr) + require.Equal(t, f, uint64(15)) + require.Equal(t, reward, uint64(161)) +} diff --git a/node/execution/ceremony/application/ceremony_application_validating.go b/node/execution/ceremony/application/ceremony_application_validating.go new file mode 100644 index 0000000..d642983 --- /dev/null +++ b/node/execution/ceremony/application/ceremony_application_validating.go @@ -0,0 +1,210 @@ +package application + +import ( + "bytes" + + "github.com/pkg/errors" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func (a *CeremonyApplication) applyTranscript( + transcript *protobufs.CeremonyTranscript, +) error { + if len(a.UpdatedTranscript.G1Powers) != len(transcript.G1Powers) { + return errors.Wrap(errors.New("invalid g1s"), "apply transcript") + } + if len(a.UpdatedTranscript.G2Powers) != len(transcript.G2Powers) { + return errors.Wrap(errors.New("invalid g2s"), "apply transcript") + } + if len(a.UpdatedTranscript.RunningG1_256Witnesses) != + len(transcript.RunningG1_256Witnesses) || + len(transcript.RunningG1_256Witnesses) != + len(a.LatestTranscript.RunningG1_256Witnesses)+1 { + return errors.Wrap( + errors.New("invalid witnesses"), + "apply transcript", + ) + } + if len(a.UpdatedTranscript.RunningG2_256Powers) != + len(transcript.RunningG2_256Powers) || + len(transcript.RunningG2_256Powers) != + len(a.LatestTranscript.RunningG2_256Powers)+1 { + return errors.Wrap( + errors.New("invalid g2^256 powers"), + "apply transcript", + ) + } + + g1s := []*curves.PointBls48581G1{} + for i := range a.UpdatedTranscript.G1Powers { + if !bytes.Equal( + a.UpdatedTranscript.G1Powers[i].KeyValue, + transcript.G1Powers[i].KeyValue, + ) { + return errors.Wrap(errors.New("invalid g1s"), "apply transcript") + } + + g1 := &curves.PointBls48581G1{} + x, err := g1.FromAffineCompressed(a.UpdatedTranscript.G1Powers[i].KeyValue) + if err != nil { + return errors.Wrap(err, "apply transcript") + } + g1, _ = x.(*curves.PointBls48581G1) + + g1s = append(g1s, g1) + } + + g2s := []*curves.PointBls48581G2{} + for i := range a.UpdatedTranscript.G2Powers { + if !bytes.Equal( + a.UpdatedTranscript.G2Powers[i].KeyValue, + transcript.G2Powers[i].KeyValue, + ) { + return errors.Wrap(errors.New("invalid g2s"), "apply transcript") + } + + g2 := &curves.PointBls48581G2{} + x, err := g2.FromAffineCompressed(a.UpdatedTranscript.G2Powers[i].KeyValue) + if err != nil { + return errors.Wrap(err, "apply transcript") + } + g2, _ = x.(*curves.PointBls48581G2) + + g2s = append(g2s, g2) + } + + g1Witnesses := []*curves.PointBls48581G1{} + for i := range a.UpdatedTranscript.RunningG1_256Witnesses { + if !bytes.Equal( + a.UpdatedTranscript.RunningG1_256Witnesses[i].KeyValue, + transcript.RunningG1_256Witnesses[i].KeyValue, + ) { + return errors.Wrap(errors.New("invalid g1 witnesses"), "apply transcript") + } + + g1w := &curves.PointBls48581G1{} + w, err := g1w.FromAffineCompressed( + a.UpdatedTranscript.RunningG1_256Witnesses[i].KeyValue, + ) + if err != nil { + return errors.Wrap(err, "apply transcript") + } + g1w, _ = w.(*curves.PointBls48581G1) + + g1Witnesses = append(g1Witnesses, g1w) + } + + g2Powers := []*curves.PointBls48581G2{} + for i := range a.UpdatedTranscript.RunningG2_256Powers { + if !bytes.Equal( + a.UpdatedTranscript.RunningG2_256Powers[i].KeyValue, + transcript.RunningG2_256Powers[i].KeyValue, + ) { + return errors.Wrap( + errors.New("invalid g2^256 powers"), + "apply transcript", + ) + } + + g2w := &curves.PointBls48581G2{} + w, err := g2w.FromAffineCompressed( + a.UpdatedTranscript.RunningG2_256Powers[i].KeyValue, + ) + if err != nil { + return errors.Wrap(err, "apply transcript") + } + g2w, _ = w.(*curves.PointBls48581G2) + + g2Powers = append(g2Powers, g2w) + } + + if !g2Powers[len(g2Powers)-1].Equal(g2s[len(g2s)-1]) { + return errors.Wrap( + errors.New("invalid running g2^256 power"), + "apply transcript", + ) + } + + for i := 0; i < len(a.LatestTranscript.RunningG1_256Witnesses); i++ { + if !bytes.Equal( + a.LatestTranscript.RunningG1_256Witnesses[i].KeyValue, + a.UpdatedTranscript.RunningG1_256Witnesses[i].KeyValue, + ) { + return errors.Wrap( + errors.New("running witness mismatch"), + "apply transcript", + ) + } + } + + for i := 0; i < len(a.LatestTranscript.RunningG2_256Powers); i++ { + if !bytes.Equal( + a.LatestTranscript.RunningG2_256Powers[i].KeyValue, + a.UpdatedTranscript.RunningG2_256Powers[i].KeyValue, + ) { + return errors.Wrap( + errors.New("running g2^256 power mismatch"), + "apply transcript", + ) + } + } + + mp := []curves.PairingPoint{} + mpg2 := curves.BLS48581G2().Point.Generator().(curves.PairingPoint) + mpg2n := g2s[1].Neg().(curves.PairingPoint) + + for i := 0; i < len(g1s)-1; i++ { + mp = append(mp, g1s[i]) + mp = append(mp, mpg2n) + mp = append(mp, g1s[i+1]) + mp = append(mp, mpg2) + } + + mp2 := []curves.PairingPoint{} + mpg1 := curves.BLS48581G1().Point.Generator().(curves.PairingPoint) + mpg1n := g1s[1].Neg().(curves.PairingPoint) + for i := 0; i < len(g2s)-1; i++ { + mp2 = append(mp2, mpg1n) + mp2 = append(mp2, g2s[i]) + mp2 = append(mp2, mpg1) + mp2 = append(mp2, g2s[i+1]) + } + + l := g1s[0].MultiPairing(mp...) + if !l.IsOne() { + return errors.Wrap( + errors.New("pairing check failed for g1s"), + "apply transcript", + ) + } + + l = g1s[0].MultiPairing(mp2...) + if !l.IsOne() { + return errors.Wrap( + errors.New("pairing check failed for g2s"), + "apply transcript", + ) + } + + mp3 := []curves.PairingPoint{} + for i := 0; i < len(g2Powers)-1; i++ { + mp3 = append(mp3, g1Witnesses[i+1].Neg().(curves.PairingPoint)) + mp3 = append(mp3, g2Powers[i]) + mp3 = append(mp3, mpg1) + mp3 = append(mp3, g2Powers[i+1]) + } + + l = g1s[0].MultiPairing(mp3...) + if !l.IsOne() { + return errors.Wrap( + errors.New("pairing check failed for witnesses"), + "apply transcript", + ) + } + + a.LatestTranscript = a.UpdatedTranscript + a.UpdatedTranscript = nil + + return nil +} diff --git a/node/execution/ceremony/application/ceremony_application_validating_test.go b/node/execution/ceremony/application/ceremony_application_validating_test.go new file mode 100644 index 0000000..7f6c196 --- /dev/null +++ b/node/execution/ceremony/application/ceremony_application_validating_test.go @@ -0,0 +1,326 @@ +package application + +import ( + "crypto" + "crypto/rand" + "testing" + + "github.com/cloudflare/circl/sign/ed448" + "github.com/stretchr/testify/require" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + bls48581 "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves/native/bls48581" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +func TestApplyTranscript(t *testing.T) { + old := curves.BLS48581G1().Scalar.Random(rand.Reader) + old2 := old.Mul(old) + old3 := old2.Mul(old) + tau := curves.BLS48581G1().Scalar.Random(rand.Reader) + tau2 := tau.Mul(tau) + tau3 := tau2.Mul(tau) + tauPubG2 := curves.BLS48581G2().Point.Generator().Mul(tau) + + proverPubKey, proverKey, err := ed448.GenerateKey(rand.Reader) + require.NoError(t, err) + proverSig, err := proverKey.Sign( + rand.Reader, + tauPubG2.ToAffineCompressed(), + crypto.Hash(0), + ) + require.NoError(t, err) + + blsSignature := make([]byte, int(bls48581.MODBYTES)+1) + key := tau.Bytes() + + for i, j := 0, len(key)-1; i < j; i, j = i+1, j-1 { + key[i], key[j] = key[j], key[i] + } + + if bls48581.Core_Sign(blsSignature, proverKey, key) != bls48581.BLS_OK { + require.Fail(t, "could not sign") + } + + blsSig := blsSignature[:] + updatedTranscript := &protobufs.CeremonyTranscript{ + G1Powers: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old, + ).Mul(tau).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old2, + ).Mul(tau2).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old3, + ).Mul(tau3).ToAffineCompressed(), + }, + }, + G2Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).Mul(tau).ToAffineCompressed(), + }, + }, + RunningG1_256Witnesses: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + tau, + ).ToAffineCompressed(), + }, + }, + RunningG2_256Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).Mul(tau).ToAffineCompressed(), + }, + }, + } + + a := &CeremonyApplication{ + StateCount: 0, + RoundCount: 0, + LobbyState: CEREMONY_APPLICATION_STATE_VALIDATING, + FinalCommits: []*protobufs.CeremonyTranscriptCommit{ + { + ProverSignature: &protobufs.Ed448Signature{ + Signature: proverSig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: proverPubKey, + }, + }, + ContributionSignature: &protobufs.BLS48581Signature{ + Signature: blsSig, + PublicKey: &protobufs.BLS48581G2PublicKey{ + KeyValue: tauPubG2.ToAffineCompressed(), + }, + }, + }, + }, + LatestTranscript: &protobufs.CeremonyTranscript{ + G1Powers: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old2, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old3, + ).ToAffineCompressed(), + }, + }, + G2Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + }, + RunningG1_256Witnesses: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + }, + RunningG2_256Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + }, + }, + UpdatedTranscript: updatedTranscript, + } + + err = a.applyTranscript(updatedTranscript) + require.NoError(t, err) +} + +func TestApplyRewritingTranscriptFails(t *testing.T) { + old := curves.BLS48581G1().Scalar.Random(rand.Reader) + old2 := old.Mul(old) + old3 := old2.Mul(old) + tau := curves.BLS48581G1().Scalar.Random(rand.Reader) + tau2 := tau.Mul(tau) + tau3 := tau2.Mul(tau) + tauPubG2 := curves.BLS48581G2().Point.Generator().Mul(tau) + + proverPubKey, proverKey, err := ed448.GenerateKey(rand.Reader) + require.NoError(t, err) + proverSig, err := proverKey.Sign( + rand.Reader, + tauPubG2.ToAffineCompressed(), + crypto.Hash(0), + ) + require.NoError(t, err) + + blsSignature := make([]byte, int(bls48581.MODBYTES)+1) + key := tau.Bytes() + + for i, j := 0, len(key)-1; i < j; i, j = i+1, j-1 { + key[i], key[j] = key[j], key[i] + } + + if bls48581.Core_Sign(blsSignature, proverKey, key) != bls48581.BLS_OK { + require.Fail(t, "could not sign") + } + + blsSig := blsSignature[:] + updatedTranscript := &protobufs.CeremonyTranscript{ + G1Powers: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + tau, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + tau2, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + tau3, + ).ToAffineCompressed(), + }, + }, + G2Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + tau, + ).ToAffineCompressed(), + }, + }, + // Pretend we're accumulating still + RunningG1_256Witnesses: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + tau, + ).ToAffineCompressed(), + }, + }, + RunningG2_256Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).Mul(tau).ToAffineCompressed(), + }, + }, + } + + a := &CeremonyApplication{ + StateCount: 0, + RoundCount: 0, + LobbyState: CEREMONY_APPLICATION_STATE_VALIDATING, + FinalCommits: []*protobufs.CeremonyTranscriptCommit{ + { + ProverSignature: &protobufs.Ed448Signature{ + Signature: proverSig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: proverPubKey, + }, + }, + ContributionSignature: &protobufs.BLS48581Signature{ + Signature: blsSig, + PublicKey: &protobufs.BLS48581G2PublicKey{ + KeyValue: tauPubG2.ToAffineCompressed(), + }, + }, + }, + }, + LatestTranscript: &protobufs.CeremonyTranscript{ + G1Powers: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old2, + ).ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + old3, + ).ToAffineCompressed(), + }, + }, + G2Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().ToAffineCompressed(), + }, + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + }, + RunningG1_256Witnesses: []*protobufs.BLS48581G1PublicKey{ + { + KeyValue: curves.BLS48581G1().Point.Generator().ToAffineCompressed(), + }, + }, + RunningG2_256Powers: []*protobufs.BLS48581G2PublicKey{ + { + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + old, + ).ToAffineCompressed(), + }, + }, + }, + UpdatedTranscript: updatedTranscript, + } + + err = a.applyTranscript(updatedTranscript) + require.NoError(t, err) +} diff --git a/node/execution/ceremony/application/multiply.go b/node/execution/ceremony/application/multiply.go new file mode 100644 index 0000000..d78d8cf --- /dev/null +++ b/node/execution/ceremony/application/multiply.go @@ -0,0 +1,583 @@ +package application + +import ( + "encoding/binary" + "encoding/json" + + "github.com/pkg/errors" + "golang.org/x/crypto/sha3" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + bls48581 "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves/native/bls48581" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/ot/base/simplest" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/ot/extension/kos" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/tecdsa/dkls/v1/sign" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/zkp/schnorr" +) + +type MultiplyReceiverRound int +type MultiplySenderRound int + +const ( + MULTIPLY_RECEIVER_ROUND_UNINITIALIZED = MultiplyReceiverRound(iota) + MULTIPLY_RECEIVER_ROUND_1_COMPUTE_AND_ZKP_TO_PUBKEY + MULTIPLY_RECEIVER_ROUND_2_PAD_TRANSFER + MULTIPLY_RECEIVER_ROUND_3_VERIFY + MULTIPLY_RECEIVER_ROUND_4_MULTIPLY_INIT + MULTIPLY_RECEIVER_ROUND_5_MULTIPLY + MULTIPLY_RECEIVER_ROUND_6_DONE +) + +const ( + MULTIPLY_SENDER_ROUND_UNINITIALIZED = MultiplySenderRound(iota) + MULTIPLY_SENDER_ROUND_1_INITIALIZED + MULTIPLY_SENDER_ROUND_2_VERIFY_SCHNORR_AND_PAD_TRANSFER + MULTIPLY_SENDER_ROUND_3_RESPOND_TO_CHALLENGE + MULTIPLY_SENDER_ROUND_4_VERIFY + MULTIPLY_SENDER_ROUND_5_MULTIPLY + MULTIPLY_SENDER_ROUND_6_DONE +) + +type Iterator interface { + Init() error + Next(message []byte) ([]byte, error) + IsDone() bool + GetPoints() []curves.Point + GetScalars() []curves.Scalar +} + +type MultiplySender struct { + seed [32]byte + alphas []curves.Scalar + curve *curves.Curve + simplestReceiver *simplest.Receiver + sender []*sign.MultiplySender + step MultiplySenderRound +} + +type MultiplyReceiver struct { + seed [32]byte + betas []curves.Scalar + curve *curves.Curve + simplestSender *simplest.Sender + receiver []*sign.MultiplyReceiver + step MultiplyReceiverRound +} + +var _ Iterator = (*MultiplySender)(nil) +var _ Iterator = (*MultiplyReceiver)(nil) + +type SchnorrProof struct { + C []byte + S []byte + Statement []byte +} + +type KOSRound2Output struct { + Tau [][][]byte +} + +type MultiplyRound2Output struct { + COTRound2Output *KOSRound2Output + R [][]byte + U []byte +} + +func NewMultiplySender( + alphas []curves.Scalar, + curve *curves.Curve, + seed [32]byte, +) *MultiplySender { + return &MultiplySender{ + seed: seed, + alphas: alphas, + curve: curve, + simplestReceiver: nil, + sender: []*sign.MultiplySender{}, + step: MULTIPLY_SENDER_ROUND_UNINITIALIZED, + } +} + +func NewMultiplyReceiver( + betas []curves.Scalar, + curve *curves.Curve, + seed [32]byte, +) *MultiplyReceiver { + return &MultiplyReceiver{ + seed: seed, + betas: betas, + curve: curve, + simplestSender: nil, + receiver: []*sign.MultiplyReceiver{}, + step: MULTIPLY_RECEIVER_ROUND_UNINITIALIZED, + } +} + +func (s *MultiplySender) Init() error { + seed := sha3.Sum256(append(append([]byte{}, s.seed[:]...), []byte("OT")...)) + var err error + s.simplestReceiver, err = simplest.NewReceiver(s.curve, 584, seed) + s.step = MULTIPLY_SENDER_ROUND_1_INITIALIZED + return err +} + +func (r *MultiplyReceiver) Init() error { + seed := sha3.Sum256(append(append([]byte{}, r.seed[:]...), []byte("OT")...)) + var err error + r.simplestSender, err = simplest.NewSender(r.curve, 584, seed) + r.step = MULTIPLY_RECEIVER_ROUND_1_COMPUTE_AND_ZKP_TO_PUBKEY + return err +} + +func (s *MultiplySender) Next(message []byte) ([]byte, error) { + switch s.step { + case MULTIPLY_SENDER_ROUND_1_INITIALIZED: + s.step = MULTIPLY_SENDER_ROUND_2_VERIFY_SCHNORR_AND_PAD_TRANSFER + return nil, nil + case MULTIPLY_SENDER_ROUND_2_VERIFY_SCHNORR_AND_PAD_TRANSFER: + proof := &SchnorrProof{} + err := json.Unmarshal([]byte(message), proof) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + schnorrC, err := s.curve.Scalar.SetBytes(proof.C) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + schnorrS, err := s.curve.Scalar.SetBytes(proof.S) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + schnorrStatement, err := s.curve.Point.FromAffineCompressed(proof.Statement) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + schnorrProof := &schnorr.Proof{ + C: schnorrC, + S: schnorrS, + Statement: schnorrStatement, + } + + receiversMaskedChoice, err := + s.simplestReceiver.Round2VerifySchnorrAndPadTransfer(schnorrProof) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + marshaledReceiversMaskedChoice, err := json.Marshal(receiversMaskedChoice) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + s.step = MULTIPLY_SENDER_ROUND_3_RESPOND_TO_CHALLENGE + return marshaledReceiversMaskedChoice, nil + case MULTIPLY_SENDER_ROUND_3_RESPOND_TO_CHALLENGE: + challenge := [][32]byte{} + err := json.Unmarshal([]byte(message), &challenge) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + challengeResponse, err := s.simplestReceiver.Round4RespondToChallenge( + challenge, + ) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + marshaledChallengeResponse, err := json.Marshal(challengeResponse) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + s.step = MULTIPLY_SENDER_ROUND_4_VERIFY + return marshaledChallengeResponse, errors.Wrap(err, "next") + case MULTIPLY_SENDER_ROUND_4_VERIFY: + challengeOpenings := [][2][32]byte{} + err := json.Unmarshal([]byte(message), &challengeOpenings) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + err = s.simplestReceiver.Round6Verify(challengeOpenings) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + baseOtReceiverOutput := s.simplestReceiver.Output + + for i := 0; i < len(s.alphas); i++ { + seed := sha3.Sum256( + append( + append( + append([]byte{}, s.seed[:]...), + []byte("MUL")..., + ), + binary.BigEndian.AppendUint64([]byte{}, uint64(i))..., + ), + ) + sender, err := sign.NewMultiplySender( + 584, + 160, + baseOtReceiverOutput, + s.curve, + seed, + ) + if err != nil { + return nil, errors.Wrap(err, "next") + } + s.sender = append(s.sender, sender) + } + + s.step = MULTIPLY_SENDER_ROUND_5_MULTIPLY + return nil, nil + case MULTIPLY_SENDER_ROUND_5_MULTIPLY: + round1Outputs := []*kos.Round1Output{} + err := json.Unmarshal([]byte(message), &round1Outputs) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + if len(round1Outputs) != len(s.alphas) { + return nil, errors.Wrap(errors.New("incorrect number of outputs"), "next") + } + + outputs := []*MultiplyRound2Output{} + + for i := 0; i < len(s.alphas); i++ { + round2Output, err := s.sender[i].Round2Multiply( + s.alphas[i], + round1Outputs[i], + ) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + tau := [][][]byte{} + for _, t := range round2Output.COTRound2Output.Tau { + tBytes := [][]byte{} + for _, ts := range t { + tBytes = append(tBytes, ts.Bytes()) + } + tau = append(tau, tBytes) + } + + r := [][]byte{} + for _, rs := range round2Output.R { + r = append(r, rs.Bytes()) + } + + outputs = append(outputs, &MultiplyRound2Output{ + COTRound2Output: &KOSRound2Output{ + Tau: tau, + }, + R: r, + U: round2Output.U.Bytes(), + }) + } + + marshaledOutputs, err := json.Marshal(outputs) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + s.step = MULTIPLY_SENDER_ROUND_6_DONE + return marshaledOutputs, nil + } + + return nil, nil +} + +func (r *MultiplyReceiver) Next(message []byte) ([]byte, error) { + switch r.step { + case MULTIPLY_RECEIVER_ROUND_1_COMPUTE_AND_ZKP_TO_PUBKEY: + proof, err := r.simplestSender.Round1ComputeAndZkpToPublicKey() + if err != nil { + return nil, errors.Wrap(err, "next") + } + + schnorrProof := &SchnorrProof{ + C: proof.C.Bytes(), + S: proof.S.Bytes(), + Statement: proof.Statement.ToAffineCompressed(), + } + + marshaledProof, err := json.Marshal(schnorrProof) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + r.step = MULTIPLY_RECEIVER_ROUND_2_PAD_TRANSFER + return marshaledProof, nil + case MULTIPLY_RECEIVER_ROUND_2_PAD_TRANSFER: + receiversMaskedChoice := [][]byte{} + err := json.Unmarshal([]byte(message), &receiversMaskedChoice) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + challenge, err := r.simplestSender.Round3PadTransfer(receiversMaskedChoice) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + marshaledChallenge, err := json.Marshal(challenge) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + r.step = MULTIPLY_RECEIVER_ROUND_3_VERIFY + return marshaledChallenge, nil + case MULTIPLY_RECEIVER_ROUND_3_VERIFY: + challengeResponse := [][32]byte{} + err := json.Unmarshal([]byte(message), &challengeResponse) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + challengeOpenings, err := r.simplestSender.Round5Verify(challengeResponse) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + marshaledChallengeOpenings, err := json.Marshal(challengeOpenings) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + r.step = MULTIPLY_RECEIVER_ROUND_4_MULTIPLY_INIT + + return marshaledChallengeOpenings, nil + case MULTIPLY_RECEIVER_ROUND_4_MULTIPLY_INIT: + baseOtSenderOutput := r.simplestSender.Output + outputs := []*kos.Round1Output{} + + for i := 0; i < len(r.betas); i++ { + seed := sha3.Sum256( + append( + append( + append([]byte{}, r.seed[:]...), + []byte("MUL")..., + ), + binary.BigEndian.AppendUint64([]byte{}, uint64(i))..., + ), + ) + receiver, err := sign.NewMultiplyReceiver( + 584, + 160, + baseOtSenderOutput, + r.curve, + seed, + ) + if err != nil { + return nil, errors.Wrap(err, "next") + } + r.receiver = append(r.receiver, receiver) + round1Output, err := r.receiver[i].Round1Initialize(r.betas[i]) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + outputs = append(outputs, round1Output) + } + + marshaledOutputs, err := json.Marshal(outputs) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + r.step = MULTIPLY_RECEIVER_ROUND_5_MULTIPLY + return marshaledOutputs, nil + case MULTIPLY_RECEIVER_ROUND_5_MULTIPLY: + round2Output := []*MultiplyRound2Output{} + err := json.Unmarshal([]byte(message), &round2Output) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + if len(round2Output) != len(r.betas) { + return nil, errors.Wrap(errors.New("incorrect number of outputs"), "next") + } + + for i := 0; i < len(r.betas); i++ { + rawRound2Output := &sign.MultiplyRound2Output{ + COTRound2Output: &kos.Round2Output{ + Tau: [][]curves.Scalar{}, + }, + R: []curves.Scalar{}, + U: nil, + } + + for _, t := range round2Output[i].COTRound2Output.Tau { + tScalars := []curves.Scalar{} + for _, ts := range t { + sc, err := r.curve.Scalar.SetBytes(ts) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + tScalars = append(tScalars, sc) + } + rawRound2Output.COTRound2Output.Tau = append( + rawRound2Output.COTRound2Output.Tau, + tScalars, + ) + } + + for _, rs := range round2Output[i].R { + sc, err := r.curve.Scalar.SetBytes(rs) + if err != nil { + return nil, errors.Wrap(err, "next") + } + rawRound2Output.R = append(rawRound2Output.R, sc) + } + + rawRound2Output.U, err = r.curve.Scalar.SetBytes(round2Output[i].U) + if err != nil { + return nil, errors.Wrap(err, "next") + } + + err := r.receiver[i].Round3Multiply(rawRound2Output) + if err != nil { + return nil, errors.Wrap(err, "next") + } + } + + r.step = MULTIPLY_RECEIVER_ROUND_6_DONE + return nil, nil + } + return nil, nil +} + +func (s *MultiplySender) IsDone() bool { + return s.step == MULTIPLY_SENDER_ROUND_6_DONE +} + +func (r *MultiplyReceiver) IsDone() bool { + return r.step == MULTIPLY_RECEIVER_ROUND_6_DONE +} + +func (s *MultiplySender) GetPoints() []curves.Point { + points := []curves.Point{} + + for i := 0; i < len(s.alphas); i++ { + points = append( + points, + s.curve.NewGeneratorPoint().Mul( + s.sender[i].OutputAdditiveShare, + ), + ) + } + + return points +} + +func (r *MultiplyReceiver) GetPoints() []curves.Point { + points := []curves.Point{} + + for i := 0; i < len(r.betas); i++ { + points = append( + points, + r.curve.NewGeneratorPoint().Mul( + r.receiver[i].OutputAdditiveShare, + ), + ) + } + + return points +} + +func (s *MultiplySender) GetScalars() []curves.Scalar { + scalars := []curves.Scalar{} + + for i := 0; i < len(s.alphas); i++ { + scalars = append( + scalars, + s.sender[i].OutputAdditiveShare, + ) + } + + return scalars +} + +func (r *MultiplyReceiver) GetScalars() []curves.Scalar { + scalars := []curves.Scalar{} + + for i := 0; i < len(r.betas); i++ { + scalars = append( + scalars, + r.receiver[i].OutputAdditiveShare, + ) + } + + return scalars +} + +func (s *MultiplySender) GetSignatureOfProverKey( + proverKey []byte, +) ([]byte, error) { + signature := make([]byte, int(bls48581.MODBYTES)+1) + key := s.sender[0].OutputAdditiveShare.Bytes() + + if bls48581.Core_Sign(signature, proverKey, key) != bls48581.BLS_OK { + return nil, errors.Wrap( + errors.New("could not sign"), + "get signature of prover key", + ) + } + + return signature[:], nil +} + +func (r *MultiplyReceiver) GetSignatureOfProverKey( + proverKey []byte, +) ([]byte, error) { + signature := make([]byte, int(bls48581.MODBYTES)+1) + key := r.receiver[0].OutputAdditiveShare.Bytes() + + if bls48581.Core_Sign(signature, proverKey, key) != bls48581.BLS_OK { + return nil, errors.Wrap( + errors.New("could not sign"), + "get signature of prover key", + ) + } + + return signature[:], nil +} + +func SignProverKeyForCommit( + proverKey []byte, + commitKey curves.Scalar, +) ([]byte, error) { + signature := make([]byte, int(bls48581.MODBYTES)+1) + key := commitKey.Bytes() + + if bls48581.Core_Sign(signature, proverKey, key) != bls48581.BLS_OK { + return nil, errors.Wrap( + errors.New("could not sign"), + "sign prover key for commit", + ) + } + + return signature[:], nil +} + +func VerifySignatureOfProverKey( + proverKey []byte, + signature []byte, + publicPointG2 curves.Point, +) error { + w := publicPointG2.ToAffineCompressed() + + if bls48581.Core_Verify(signature, proverKey, w) != bls48581.BLS_OK { + return errors.Wrap( + errors.New("could not verify"), + "verify signature of prover key", + ) + } + + return nil +} diff --git a/node/execution/ceremony/application/oblivious_powers_of_tau.go b/node/execution/ceremony/application/oblivious_powers_of_tau.go new file mode 100644 index 0000000..db843a7 --- /dev/null +++ b/node/execution/ceremony/application/oblivious_powers_of_tau.go @@ -0,0 +1,169 @@ +package application + +import ( + "bytes" + + "github.com/pkg/errors" + "golang.org/x/crypto/sha3" + "golang.org/x/sync/errgroup" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" +) + +func ProcessRound( + i []byte, + idkKey curves.Scalar, + round int, + peers [][]byte, + peerIdks []curves.Point, + secrets []curves.Scalar, + curve *curves.Curve, + send func(int, []byte, []byte) error, + recv func(int, []byte) ([]byte, error), + seed []byte, +) ([]curves.Scalar, error) { + roundPeers, roundIdks, isReceiver := GetPairings(i, round, peers, peerIdks) + if roundPeers == nil { + return nil, nil + } + + var participants []Iterator + if isReceiver { + for _, roundIdk := range roundIdks { + hashKeySeed := sha3.Sum256( + append( + roundIdk.Mul(idkKey).ToAffineCompressed(), + seed..., + ), + ) + participant := NewMultiplyReceiver(secrets, curve, hashKeySeed) + participants = append(participants, participant) + + if err := participant.Init(); err != nil { + return nil, errors.Wrap(err, "process round") + } + } + } else { + for _, roundIdk := range roundIdks { + hashKeySeed := sha3.Sum256( + append( + roundIdk.Mul(idkKey).ToAffineCompressed(), + seed..., + ), + ) + participant := NewMultiplySender(secrets, curve, hashKeySeed) + participants = append(participants, participant) + + if err := participant.Init(); err != nil { + return nil, errors.Wrap(err, "process round") + } + } + } + + eg := errgroup.Group{} + eg.SetLimit(len(participants)) + + for j := range participants { + j := j + eg.Go(func() error { + var msg []byte + seq := 0 + for !participants[j].IsDone() { + var err error + if isReceiver { + msg, err = recv(seq, append(append([]byte{}, roundPeers[j]...), i...)) + if err != nil { + return err + } + } + + next, err := participants[j].Next(msg) + if err != nil { + return err + } + + err = send(seq, append(append([]byte{}, i...), roundPeers[j]...), next) + if err != nil { + return err + } + + if !isReceiver { + msg, err = recv(seq, append(append([]byte{}, roundPeers[j]...), i...)) + if err != nil { + return err + } + } + seq++ + } + + return nil + }) + } + + if err := eg.Wait(); err != nil { + return nil, errors.Wrap(err, "process round") + } + + sums := make([]curves.Scalar, len(secrets)) + for j := range sums { + sums[j] = curve.Scalar.Zero() + } + + for _, participant := range participants { + scalars := participant.GetScalars() + for j := range sums { + sums[j] = sums[j].Add(scalars[j]) + } + } + + return sums, nil +} + +func GetPairings(i []byte, round int, peers [][]byte, peerIdks []curves.Point) ( + [][]byte, + []curves.Point, + bool, +) { + n := len(peers) + index := -1 + + for j := 0; j < n; j++ { + if bytes.Equal([]byte(peers[j]), []byte(i)) { + index = j + 1 + break + } + } + + if index < 1 || index > n { + return nil, nil, false // invalid input + } + + power := uint64(n) >> round + if power == 0 { + return nil, nil, false // rounds exceeded + } + + // Find the size of the subset for this round + subsetSize := 1 << (round - 1) + + // Determine the subset that i belongs to + subsetIndex := (index - 1) / subsetSize + + // If subsetIndex is odd, i's pairings are in the subset before it + // If subsetIndex is even, i's pairings are in the subset after it + complementarySubsetStart := 0 + if subsetIndex%2 == 0 { + complementarySubsetStart = (subsetIndex+1)*subsetSize + 1 + } else { + complementarySubsetStart = subsetIndex*subsetSize - subsetSize + 1 + } + + // Generate the pairings + pairings := make([][]byte, subsetSize) + idks := make([]curves.Point, subsetSize) + for j := 0; j < subsetSize; j++ { + pairings[j] = peers[complementarySubsetStart+j-1] + idks[j] = peerIdks[complementarySubsetStart+j-1] + } + + return pairings, idks, (index - 1) < complementarySubsetStart +} diff --git a/node/execution/ceremony/application/oblivious_powers_of_tau_test.go b/node/execution/ceremony/application/oblivious_powers_of_tau_test.go new file mode 100644 index 0000000..d097a2c --- /dev/null +++ b/node/execution/ceremony/application/oblivious_powers_of_tau_test.go @@ -0,0 +1,439 @@ +package application_test + +import ( + "crypto/rand" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" + "golang.org/x/sync/syncmap" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + bls48581 "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves/native/bls48581" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/ot/base/simplest" + "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony/application" +) + +func TestPairings(t *testing.T) { + a := []byte{0x01} + b := []byte{0x02} + c := []byte{0x03} + d := []byte{0x04} + e := []byte{0x05} + f := []byte{0x06} + g := []byte{0x07} + h := []byte{0x08} + + peers := [][]byte{a, b, c, d, e, f, g, h} + idks := []curves.Point{ + curves.ED448().Point.Generator(), + curves.ED448().Point.Generator(), + curves.ED448().Point.Generator(), + curves.ED448().Point.Generator(), + curves.ED448().Point.Generator(), + curves.ED448().Point.Generator(), + curves.ED448().Point.Generator(), + curves.ED448().Point.Generator(), + } + + a1pairing, _, isABob := application.GetPairings(a, 1, peers, idks) + b1pairing, _, isBBob := application.GetPairings(b, 1, peers, idks) + c1pairing, _, isCBob := application.GetPairings(c, 1, peers, idks) + d1pairing, _, isDBob := application.GetPairings(d, 1, peers, idks) + e1pairing, _, isEBob := application.GetPairings(e, 1, peers, idks) + f1pairing, _, isFBob := application.GetPairings(f, 1, peers, idks) + g1pairing, _, isGBob := application.GetPairings(g, 1, peers, idks) + h1pairing, _, isHBob := application.GetPairings(h, 1, peers, idks) + + require.ElementsMatch(t, a1pairing, [][]byte{b}) + require.ElementsMatch(t, b1pairing, [][]byte{a}) + require.ElementsMatch(t, c1pairing, [][]byte{d}) + require.ElementsMatch(t, d1pairing, [][]byte{c}) + require.ElementsMatch(t, e1pairing, [][]byte{f}) + require.ElementsMatch(t, f1pairing, [][]byte{e}) + require.ElementsMatch(t, g1pairing, [][]byte{h}) + require.ElementsMatch(t, h1pairing, [][]byte{g}) + require.ElementsMatch(t, + []bool{isABob, isBBob, isCBob, isDBob, isEBob, isFBob, isGBob, isHBob}, + []bool{false, true, false, true, false, true, false, true}, + ) + + a2pairing, _, isABob := application.GetPairings(a, 2, peers, idks) + b2pairing, _, isBBob := application.GetPairings(b, 2, peers, idks) + c2pairing, _, isCBob := application.GetPairings(c, 2, peers, idks) + d2pairing, _, isDBob := application.GetPairings(d, 2, peers, idks) + e2pairing, _, isEBob := application.GetPairings(e, 2, peers, idks) + f2pairing, _, isFBob := application.GetPairings(f, 2, peers, idks) + g2pairing, _, isGBob := application.GetPairings(g, 2, peers, idks) + h2pairing, _, isHBob := application.GetPairings(h, 2, peers, idks) + + require.ElementsMatch(t, a2pairing, [][]byte{c, d}) + require.ElementsMatch(t, b2pairing, [][]byte{c, d}) + require.ElementsMatch(t, c2pairing, [][]byte{a, b}) + require.ElementsMatch(t, d2pairing, [][]byte{a, b}) + require.ElementsMatch(t, e2pairing, [][]byte{g, h}) + require.ElementsMatch(t, f2pairing, [][]byte{g, h}) + require.ElementsMatch(t, g2pairing, [][]byte{e, f}) + require.ElementsMatch(t, h2pairing, [][]byte{e, f}) + require.ElementsMatch(t, + []bool{isABob, isBBob, isCBob, isDBob, isEBob, isFBob, isGBob, isHBob}, + []bool{false, false, true, true, false, false, true, true}, + ) + + a3pairing, _, isABob := application.GetPairings(a, 3, peers, idks) + b3pairing, _, isBBob := application.GetPairings(b, 3, peers, idks) + c3pairing, _, isCBob := application.GetPairings(c, 3, peers, idks) + d3pairing, _, isDBob := application.GetPairings(d, 3, peers, idks) + e3pairing, _, isEBob := application.GetPairings(e, 3, peers, idks) + f3pairing, _, isFBob := application.GetPairings(f, 3, peers, idks) + g3pairing, _, isGBob := application.GetPairings(g, 3, peers, idks) + h3pairing, _, isHBob := application.GetPairings(h, 3, peers, idks) + + require.ElementsMatch(t, a3pairing, [][]byte{e, f, g, h}) + require.ElementsMatch(t, b3pairing, [][]byte{e, f, g, h}) + require.ElementsMatch(t, c3pairing, [][]byte{e, f, g, h}) + require.ElementsMatch(t, d3pairing, [][]byte{e, f, g, h}) + require.ElementsMatch(t, e3pairing, [][]byte{a, b, c, d}) + require.ElementsMatch(t, f3pairing, [][]byte{a, b, c, d}) + require.ElementsMatch(t, g3pairing, [][]byte{a, b, c, d}) + require.ElementsMatch(t, h3pairing, [][]byte{a, b, c, d}) + require.ElementsMatch(t, + []bool{isABob, isBBob, isCBob, isDBob, isEBob, isFBob, isGBob, isHBob}, + []bool{false, false, false, false, true, true, true, true}, + ) + + a4pairing, _, isABob := application.GetPairings(a, 4, peers, idks) + b4pairing, _, isBBob := application.GetPairings(b, 4, peers, idks) + c4pairing, _, isCBob := application.GetPairings(c, 4, peers, idks) + d4pairing, _, isDBob := application.GetPairings(d, 4, peers, idks) + e4pairing, _, isEBob := application.GetPairings(e, 4, peers, idks) + f4pairing, _, isFBob := application.GetPairings(f, 4, peers, idks) + g4pairing, _, isGBob := application.GetPairings(g, 4, peers, idks) + h4pairing, _, isHBob := application.GetPairings(h, 4, peers, idks) + + require.ElementsMatch(t, a4pairing, [][]byte{}) + require.ElementsMatch(t, b4pairing, [][]byte{}) + require.ElementsMatch(t, c4pairing, [][]byte{}) + require.ElementsMatch(t, d4pairing, [][]byte{}) + require.ElementsMatch(t, e4pairing, [][]byte{}) + require.ElementsMatch(t, f4pairing, [][]byte{}) + require.ElementsMatch(t, g4pairing, [][]byte{}) + require.ElementsMatch(t, h4pairing, [][]byte{}) + require.ElementsMatch(t, + []bool{isABob, isBBob, isCBob, isDBob, isEBob, isFBob, isGBob, isHBob}, + []bool{false, false, false, false, false, false, false, false}, + ) +} + +func TestProcessRound(t *testing.T) { + a := []byte{0x01} + aKey := curves.ED448().Scalar.Random(rand.Reader) + aPoint := curves.ED448().Point.Generator().Mul(aKey) + b := []byte{0x02} + bKey := curves.ED448().Scalar.Random(rand.Reader) + bPoint := curves.ED448().Point.Generator().Mul(bKey) + c := []byte{0x03} + cKey := curves.ED448().Scalar.Random(rand.Reader) + cPoint := curves.ED448().Point.Generator().Mul(cKey) + d := []byte{0x04} + dKey := curves.ED448().Scalar.Random(rand.Reader) + dPoint := curves.ED448().Point.Generator().Mul(dKey) + e := []byte{0x05} + eKey := curves.ED448().Scalar.Random(rand.Reader) + ePoint := curves.ED448().Point.Generator().Mul(eKey) + f := []byte{0x06} + fKey := curves.ED448().Scalar.Random(rand.Reader) + fPoint := curves.ED448().Point.Generator().Mul(fKey) + g := []byte{0x07} + gKey := curves.ED448().Scalar.Random(rand.Reader) + gPoint := curves.ED448().Point.Generator().Mul(gKey) + h := []byte{0x08} + hKey := curves.ED448().Scalar.Random(rand.Reader) + hPoint := curves.ED448().Point.Generator().Mul(hKey) + + peerKeys := []curves.Scalar{aKey, bKey, cKey, dKey, eKey, fKey, gKey, hKey} + peerPoints := [][]byte{ + aPoint.ToAffineCompressed(), + bPoint.ToAffineCompressed(), + cPoint.ToAffineCompressed(), + dPoint.ToAffineCompressed(), + ePoint.ToAffineCompressed(), + fPoint.ToAffineCompressed(), + gPoint.ToAffineCompressed(), + hPoint.ToAffineCompressed(), + } + idkPoints := []curves.Point{ + aPoint, + bPoint, + cPoint, + dPoint, + ePoint, + fPoint, + gPoint, + hPoint, + } + + peers := [][]byte{a, b, c, d, e, f, g, h} + peerSecrets := [][]curves.Scalar{} + originalPeerSecrets := [][]curves.Scalar{} + + for i := range peers { + fmt.Printf("generating secrets for peer %d\n", i) + x := curves.BLS48581G1().Scalar.Random(rand.Reader) + xs := x.Clone() + secrets := []curves.Scalar{x} + originalSecrets := []curves.Scalar{x} + fmt.Printf("secret %d(%d): %+x\n", i, 0, xs.Bytes()) + + for j := 0; j < 1; j++ { + xs = xs.Mul(x) + secrets = append(secrets, xs) + fmt.Printf("secret %d(%d): %+x\n", i, 1, xs.Bytes()) + originalSecrets = append(originalSecrets, xs) + } + + peerSecrets = append(peerSecrets, secrets) + originalPeerSecrets = append(originalPeerSecrets, originalSecrets) + + } + + messages := syncmap.Map{} + send := func(seq int, dst, msg []byte) error { + fmt.Printf("send %d bytes for seq %d to %+x\n", len(msg), seq, dst) + + b := byte(seq) + dst = append(append([]byte{}, b), dst...) + if msg == nil { + msg = []byte{0x01} + } + messages.Store(string(dst), string(msg)) + return nil + } + recv := func(seq int, src []byte) ([]byte, error) { + fmt.Printf("recv %d from %+x\n", seq, src) + + b := byte(seq) + bsrc := append(append([]byte{}, b), src...) + + msg, ok := messages.LoadAndDelete(string(bsrc)) + for !ok { + fmt.Printf("no message yet, waiting for recv %d from %+x\n", seq, src) + + time.Sleep(100 * time.Millisecond) + msg, ok = messages.LoadAndDelete(string(bsrc)) + } + + return []byte(msg.(string)), nil + } + + for j := 1; j < 4; j++ { + eg := errgroup.Group{} + eg.SetLimit(8) + for i := range peers { + i := i + eg.Go(func() error { + fmt.Printf("running round %d for %d\n", j, i) + + newSecrets, err := application.ProcessRound( + peerPoints[i], + peerKeys[i], + j, + peerPoints, + idkPoints, + peerSecrets[i], + curves.BLS48581G1(), + send, + recv, + []byte{0x01}, + ) + require.NoError(t, err) + + for s := range newSecrets { + fmt.Printf("secret %d(%d): %+x\n", i, s, newSecrets[s].Bytes()) + } + + peerSecrets[i] = newSecrets + return err + }) + } + + err := eg.Wait() + require.NoError(t, err) + } + + checks := []curves.Point{} + for i := 0; i < len(originalPeerSecrets[0]); i++ { + mul := curves.BLS48581G1().Scalar.One() + for j := 0; j < len(originalPeerSecrets); j++ { + mul = mul.Mul(originalPeerSecrets[j][i]) + } + checks = append(checks, curves.BLS48581G1().Point.Generator().Mul(mul)) + } + + result := []curves.Point{} + for i := 0; i < len(peerSecrets[0]); i++ { + var add curves.Point = nil + for j := 0; j < len(peerSecrets); j++ { + if add == nil { + add = curves.BLS48581G1().Point.Generator().Mul(peerSecrets[j][i]) + } else { + add = add.Add( + curves.BLS48581G1().Point.Generator().Mul(peerSecrets[j][i]), + ) + } + } + result = append(result, add) + } + + for i := range checks { + require.Equal(t, true, checks[i].Equal(result[i])) + } +} + +func TestCompositeConstructionOfBLS(t *testing.T) { + // needed to verify signatures + bls48581.Init() + curve := curves.BLS48581G1() + hashKeySeed := [simplest.DigestSize]byte{} + _, err := rand.Read(hashKeySeed[:]) + require.NoError(t, err) + + alpha := curve.Scalar.Random(rand.Reader) + beta := curve.Scalar.Random(rand.Reader) + alpha2 := alpha.Mul(alpha) + beta2 := beta.Mul(beta) + + sender := application.NewMultiplySender([]curves.Scalar{alpha, alpha2}, curve, hashKeySeed) + receiver := application.NewMultiplyReceiver([]curves.Scalar{beta, beta2}, curve, hashKeySeed) + + var senderMsg []byte = nil + var receiverMsg []byte = nil + + sErr := sender.Init() + require.NoError(t, sErr) + + rErr := receiver.Init() + require.NoError(t, rErr) + + x448SendingIdentityPrivateKey := curves.ED448().Scalar.Random(rand.Reader) + x448SendingEphemeralPrivateKey := curves.ED448().Scalar.Random(rand.Reader) + x448ReceivingIdentityPrivateKey := curves.ED448().Scalar.Random(rand.Reader) + x448ReceivingSignedPrePrivateKey := curves.ED448().Scalar.Random(rand.Reader) + x448SendingIdentityKey := curves.ED448().NewGeneratorPoint().Mul(x448SendingIdentityPrivateKey) + x448SendingEphemeralKey := curves.ED448().NewGeneratorPoint().Mul(x448SendingEphemeralPrivateKey) + x448ReceivingIdentityKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingIdentityPrivateKey) + x448ReceivingSignedPreKey := curves.ED448().NewGeneratorPoint().Mul(x448ReceivingSignedPrePrivateKey) + + senderResult := crypto.SenderX3DH( + x448SendingIdentityPrivateKey, + x448SendingEphemeralPrivateKey, + x448ReceivingIdentityKey, + x448ReceivingSignedPreKey, + 96, + ) + + receiverResult := crypto.ReceiverX3DH( + x448ReceivingIdentityPrivateKey, + x448ReceivingSignedPrePrivateKey, + x448SendingIdentityKey, + x448SendingEphemeralKey, + 96, + ) + + drSender, err := crypto.NewDoubleRatchetParticipant( + senderResult[:32], + senderResult[32:64], + senderResult[64:], + true, + x448SendingEphemeralPrivateKey, + x448ReceivingSignedPreKey, + curves.ED448(), + nil, + ) + require.NoError(t, err) + + drReceiver, err := crypto.NewDoubleRatchetParticipant( + receiverResult[:32], + receiverResult[32:64], + receiverResult[64:], + false, + x448ReceivingSignedPrePrivateKey, + x448SendingEphemeralKey, + curves.ED448(), + nil, + ) + require.NoError(t, err) + + for !sender.IsDone() && !receiver.IsDone() { + senderMsg, err = sender.Next(receiverMsg) + require.NoError(t, err) + senderEnvelope, err := drSender.RatchetEncrypt(senderMsg) + require.NoError(t, err) + + senderMsg, err = drReceiver.RatchetDecrypt(senderEnvelope) + require.NoError(t, err) + + receiverMsg, err = receiver.Next(senderMsg) + require.NoError(t, err) + + receiverEnvelope, err := drReceiver.RatchetEncrypt(receiverMsg) + require.NoError(t, err) + + receiverMsg, err = drSender.RatchetDecrypt(receiverEnvelope) + require.NoError(t, err) + } + + senderPoints := sender.GetPoints() + receiverPoints := receiver.GetPoints() + + generator := alpha.Point().Generator() + product := generator.Mul(alpha).Mul(beta) + sum := senderPoints[0].Add(receiverPoints[0]) + + product2 := generator.Mul(alpha2).Mul(beta2) + sum2 := senderPoints[1].Add(receiverPoints[1]) + fmt.Println(alpha.Bytes()) + fmt.Println(beta.Bytes()) + fmt.Println(curves.BLS48581G1().Point.Generator().ToAffineCompressed()) + + fmt.Println(sum.ToAffineCompressed()) + fmt.Println(product.ToAffineCompressed()) + require.Equal(t, true, product.Equal(sum)) + require.Equal(t, true, product2.Equal(sum2)) + sendSig, err := sender.GetSignatureOfProverKey([]byte{0x01}) + require.NoError(t, err) + require.Equal(t, len(sendSig), 74) + recvSig, err := receiver.GetSignatureOfProverKey([]byte{0x02}) + require.NoError(t, err) + require.Equal(t, len(recvSig), 74) + require.NoError(t, application.VerifySignatureOfProverKey( + []byte{0x01}, + sendSig, + curves.BLS48581G2().Point.Generator().Mul( + sender.GetScalars()[0], + ), + )) + require.NoError(t, application.VerifySignatureOfProverKey( + []byte{0x02}, + recvSig, + curves.BLS48581G2().Point.Generator().Mul( + receiver.GetScalars()[0], + ), + )) + require.Error(t, application.VerifySignatureOfProverKey( + []byte{0x02}, + sendSig, + curves.BLS48581G2().Point.Generator().Mul( + sender.GetScalars()[0], + ), + )) + require.Error(t, application.VerifySignatureOfProverKey( + []byte{0x01}, + recvSig, + curves.BLS48581G2().Point.Generator().Mul( + receiver.GetScalars()[0], + ), + )) +} diff --git a/node/execution/ceremony/ceremony_execution_engine.go b/node/execution/ceremony/ceremony_execution_engine.go new file mode 100644 index 0000000..6610fae --- /dev/null +++ b/node/execution/ceremony/ceremony_execution_engine.go @@ -0,0 +1,1016 @@ +package ceremony + +import ( + "bytes" + "crypto" + "crypto/rand" + "encoding/binary" + "encoding/hex" + "strings" + "sync" + + "github.com/iden3/go-iden3-crypto/poseidon" + "github.com/pkg/errors" + "go.uber.org/zap" + "golang.org/x/sync/errgroup" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + "source.quilibrium.com/quilibrium/monorepo/node/config" + "source.quilibrium.com/quilibrium/monorepo/node/consensus/ceremony" + qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/execution" + "source.quilibrium.com/quilibrium/monorepo/node/execution/ceremony/application" + "source.quilibrium.com/quilibrium/monorepo/node/keys" + "source.quilibrium.com/quilibrium/monorepo/node/p2p" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" + "source.quilibrium.com/quilibrium/monorepo/node/store" +) + +type CeremonyExecutionEngine struct { + logger *zap.Logger + clock *ceremony.CeremonyDataClockConsensusEngine + clockStore store.ClockStore + keyStore store.KeyStore + keyManager keys.KeyManager + engineConfig *config.EngineConfig + pubSub p2p.PubSub + provingKey crypto.Signer + proverPublicKey []byte + provingKeyAddress []byte + participantMx sync.Mutex + peerChannels map[string]*p2p.PublicP2PChannel + activeSecrets []curves.Scalar + activeClockFrame *protobufs.ClockFrame + alreadyPublishedShare bool + alreadyPublishedTranscript bool +} + +func NewCeremonyExecutionEngine( + logger *zap.Logger, + clock *ceremony.CeremonyDataClockConsensusEngine, + engineConfig *config.EngineConfig, + keyManager keys.KeyManager, + pubSub p2p.PubSub, + clockStore store.ClockStore, + keyStore store.KeyStore, +) *CeremonyExecutionEngine { + if logger == nil { + panic(errors.New("logger is nil")) + } + + e := &CeremonyExecutionEngine{ + logger: logger, + clock: clock, + engineConfig: engineConfig, + keyManager: keyManager, + clockStore: clockStore, + keyStore: keyStore, + pubSub: pubSub, + participantMx: sync.Mutex{}, + peerChannels: map[string]*p2p.PublicP2PChannel{}, + alreadyPublishedShare: false, + } + + provingKey, _, publicKeyBytes, provingKeyAddress := e.clock.GetProvingKey( + engineConfig, + ) + e.provingKey = provingKey + e.proverPublicKey = publicKeyBytes + e.provingKeyAddress = provingKeyAddress + + return e +} + +var _ execution.ExecutionEngine = (*CeremonyExecutionEngine)(nil) + +// GetName implements ExecutionEngine +func (*CeremonyExecutionEngine) GetName() string { + return "ceremony" +} + +// GetSupportedApplications implements ExecutionEngine +func ( + *CeremonyExecutionEngine, +) GetSupportedApplications() []*protobufs.Application { + return []*protobufs.Application{ + { + Address: application.CEREMONY_ADDRESS, + ExecutionContext: protobufs.ExecutionContext_EXECUTION_CONTEXT_INTRINSIC, + }, + } +} + +// Start implements ExecutionEngine +func (e *CeremonyExecutionEngine) Start() <-chan error { + errChan := make(chan error) + + e.logger.Info("ceremony data loaded", zap.Binary( + "g2_power", + qcrypto.CeremonyBLS48581G2[1].ToAffineCompressed(), + )) + + go func() { + seed, err := hex.DecodeString(e.engineConfig.GenesisSeed) + if err != nil { + panic(err) + } + + err = <-e.clock.Start( + application.CEREMONY_ADDRESS, + seed, + ) + if err != nil { + panic(err) + } + + err = <-e.clock.RegisterExecutor(e, 0) + if err != nil { + panic(err) + } + + go func() { + e.RunWorker() + }() + + errChan <- nil + }() + + return errChan +} + +// Stop implements ExecutionEngine +func (*CeremonyExecutionEngine) Stop(force bool) <-chan error { + errChan := make(chan error) + + go func() { + errChan <- nil + }() + + return errChan +} + +// ProcessMessage implements ExecutionEngine +func (e *CeremonyExecutionEngine) ProcessMessage( + address []byte, + message *protobufs.Message, +) ([]*protobufs.Message, error) { + if bytes.Equal(address, e.GetSupportedApplications()[0].Address) { + e.logger.Info("processing execution message") + any := &anypb.Any{} + if err := proto.Unmarshal(message.Payload, any); err != nil { + return nil, errors.Wrap(err, "process message") + } + + switch any.TypeUrl { + case protobufs.ClockFrameType: + frame := &protobufs.ClockFrame{} + if err := any.UnmarshalTo(frame); err != nil { + return nil, errors.Wrap(err, "process message") + } + + if frame.FrameNumber < e.clock.GetFrame() { + return nil, nil + } + + if err := frame.VerifyDataClockFrame(); err != nil { + return nil, errors.Wrap(err, "process message") + } + + if err := e.VerifyExecution(frame); err != nil { + return nil, errors.Wrap(err, "process message") + } + case protobufs.CeremonyLobbyJoinType: + fallthrough + case protobufs.CeremonySeenProverAttestationType: + fallthrough + case protobufs.CeremonyDroppedProverAttestationType: + fallthrough + case protobufs.CeremonyTranscriptCommitType: + fallthrough + case protobufs.CeremonyTranscriptShareType: + fallthrough + case protobufs.CeremonyTranscriptType: + frame := e.activeClockFrame + if e.clock.IsInProverTrie(e.proverPublicKey) { + app, err := application.MaterializeApplicationFromFrame(frame) + if err != nil { + return nil, errors.Wrap(err, "process message") + } + proposedTransition := &protobufs.CeremonyLobbyStateTransition{ + TypeUrls: []string{any.TypeUrl}, + TransitionInputs: [][]byte{ + any.Value, + }, + } + + _, err = app.ApplyTransition(frame.FrameNumber, proposedTransition) + if err != nil { + return nil, errors.Wrap(err, "process message") + } + + any := &anypb.Any{} + if err := any.MarshalFrom(proposedTransition); err != nil { + return nil, errors.Wrap(err, "process message") + } + + any.TypeUrl = strings.Replace( + any.TypeUrl, + "type.googleapis.com", + "types.quilibrium.com", + 1, + ) + + payload, err := proto.Marshal(any) + if err != nil { + return nil, errors.Wrap(err, "process message") + } + + h, err := poseidon.HashBytes(payload) + if err != nil { + return nil, errors.Wrap(err, "process message") + } + + msg := &protobufs.Message{ + Hash: h.Bytes(), + Address: e.provingKeyAddress, + Payload: payload, + } + return []*protobufs.Message{ + msg, + }, nil + } + } + } + + return nil, nil +} + +func (e *CeremonyExecutionEngine) RunWorker() { + frameChan := e.clock.GetFrameChannel() + for { + frameFromBuffer := <-frameChan + frame := e.clock.GetActiveFrame() + e.activeClockFrame = frame + e.logger.Info( + "evaluating next frame", + zap.Int( + "last_run_took_frames", + int(frame.FrameNumber)-int(frameFromBuffer.FrameNumber), + ), + ) + app, err := application.MaterializeApplicationFromFrame(frame) + if err != nil { + e.logger.Error( + "error while materializing application from frame", + zap.Error(err), + ) + panic(err) + } + + _, _, reward := app.RewardTrie.Get(e.provingKeyAddress) + e.logger.Info( + "current application state", + zap.Uint64("my_balance", reward), + zap.String("lobby_state", app.LobbyState.String()), + ) + + switch app.LobbyState { + case application.CEREMONY_APPLICATION_STATE_OPEN: + e.logger.Info( + "lobby open for joins", + zap.Any("lobby_joins", app.LobbyJoins), + zap.Any("preferred_participants", app.NextRoundPreferredParticipants), + zap.Uint64("state_count", app.StateCount), + ) + e.alreadyPublishedShare = false + e.alreadyPublishedTranscript = false + alreadyJoined := false + for _, join := range app.LobbyJoins { + if bytes.Equal( + join.PublicKeySignatureEd448.PublicKey.KeyValue, + e.proverPublicKey, + ) { + alreadyJoined = true + break + } + } + + if !alreadyJoined { + e.logger.Info( + "joining lobby", + zap.Binary("proving_key", e.proverPublicKey), + ) + if err := e.announceJoin(frame); err != nil { + e.logger.Error( + "failed to announce join", + zap.Error(err), + ) + } + + e.logger.Info("preparing contribution") + // Calculate this now after announcing, this gives 10 frames of buffer + e.ensureSecrets(app) + } + case application.CEREMONY_APPLICATION_STATE_IN_PROGRESS: + e.logger.Info( + "round in progress", + zap.Any("participants", app.ActiveParticipants), + zap.Any("current_seen_attestations", app.LatestSeenProverAttestations), + zap.Any( + "current_dropped_attestations", + app.DroppedParticipantAttestations, + ), + zap.Any( + "preferred_participants_for_next_round", + app.NextRoundPreferredParticipants, + ), + zap.Uint64("current_round", app.RoundCount), + ) + + e.ensureSecrets(app) + + shouldConnect := false + position := 0 + if len(e.peerChannels) == 0 && app.RoundCount == 1 && + len(app.ActiveParticipants) > 1 { + for i, p := range app.ActiveParticipants { + if bytes.Equal(p.KeyValue, e.proverPublicKey) { + shouldConnect = true + position = i + } + } + } + + if shouldConnect { + e.logger.Info( + "connecting to peers", + zap.Any("participants", app.ActiveParticipants), + ) + err := e.connectToActivePeers(app, position) + if err != nil { + e.logger.Error("error while connecting to peers", zap.Error(err)) + continue + } + } + + if len(e.peerChannels) != 0 { + done := false + rounds := app.TranscriptRoundAdvanceCommits + if len(rounds) != 0 { + for _, c := range rounds[app.RoundCount-1].Commits { + if bytes.Equal( + c.ProverSignature.PublicKey.KeyValue, + e.proverPublicKey, + ) { + done = true + } + } + } + + if !done { + e.logger.Info( + "participating in round", + zap.Any("participants", app.ActiveParticipants), + zap.Uint64("current_round", app.RoundCount), + ) + err := e.participateRound(app) + if err != nil { + e.logger.Error("error while participating in round", zap.Error(err)) + } + } + } else if len(app.ActiveParticipants) == 1 && + bytes.Equal(app.ActiveParticipants[0].KeyValue, e.proverPublicKey) { + if err = e.commitRound(e.activeSecrets); err != nil { + e.logger.Error("error while participating in round", zap.Error(err)) + } + } + case application.CEREMONY_APPLICATION_STATE_FINALIZING: + e.logger.Info( + "round contribution finalizing", + zap.Any("participants", app.ActiveParticipants), + zap.Any("current_seen_attestations", app.LatestSeenProverAttestations), + zap.Any( + "current_dropped_attestations", + app.DroppedParticipantAttestations, + ), + zap.Any( + "preferred_participants_for_next_round", + app.NextRoundPreferredParticipants, + ), + zap.Int("finalized_shares", len(app.TranscriptShares)), + ) + + for _, s := range app.TranscriptShares { + if bytes.Equal( + s.ProverSignature.PublicKey.KeyValue, + e.proverPublicKey, + ) { + e.alreadyPublishedShare = true + } + } + + if !e.alreadyPublishedShare { + err := e.publishTranscriptShare(app) + if err != nil { + e.logger.Error( + "error while publishing transcript share", + zap.Error(err), + ) + } + } + case application.CEREMONY_APPLICATION_STATE_VALIDATING: + e.logger.Info("round contribution validating") + // Do a best effort to clear – Go's GC is noisy and unenforceable, but + // this should at least mark it as dead space + e.activeSecrets = []curves.Scalar{} + for _, c := range e.peerChannels { + c.Close() + } + + e.peerChannels = map[string]*p2p.PublicP2PChannel{} + if app.UpdatedTranscript != nil && !e.alreadyPublishedTranscript { + if err := e.publishTranscript(app); err != nil { + e.logger.Error( + "error while publishing transcript", + zap.Error(err), + ) + } + } + } + } +} + +func (e *CeremonyExecutionEngine) publishMessage( + filter []byte, + message proto.Message, +) error { + any := &anypb.Any{} + if err := any.MarshalFrom(message); err != nil { + return errors.Wrap(err, "publish message") + } + + any.TypeUrl = strings.Replace( + any.TypeUrl, + "type.googleapis.com", + "types.quilibrium.com", + 1, + ) + + payload, err := proto.Marshal(any) + if err != nil { + return errors.Wrap(err, "publish message") + } + + h, err := poseidon.HashBytes(payload) + if err != nil { + return errors.Wrap(err, "publish message") + } + + msg := &protobufs.Message{ + Hash: h.Bytes(), + Address: application.CEREMONY_ADDRESS, + Payload: payload, + } + data, err := proto.Marshal(msg) + if err != nil { + return errors.Wrap(err, "publish message") + } + return e.pubSub.PublishToBitmask(filter, data) +} + +func (e *CeremonyExecutionEngine) announceJoin( + frame *protobufs.ClockFrame, +) error { + idk, err := e.keyManager.GetAgreementKey("q-ratchet-idk") + if err != nil { + return errors.Wrap(err, "announce join") + } + spk, err := e.keyManager.GetAgreementKey("q-ratchet-spk") + if err != nil { + return errors.Wrap(err, "announce join") + } + + g := curves.ED448().Point.Generator() + + join := &protobufs.CeremonyLobbyJoin{ + FrameNumber: frame.FrameNumber, + IdentityKey: &protobufs.X448PublicKey{ + KeyValue: g.Mul(idk).ToAffineCompressed(), + }, + SignedPreKey: &protobufs.X448PublicKey{ + KeyValue: g.Mul(spk).ToAffineCompressed(), + }, + } + sig, err := join.SignWithProverKey(e.provingKey) + if err != nil { + return errors.Wrap(err, "announce join") + } + + join.PublicKeySignatureEd448 = &protobufs.Ed448Signature{ + Signature: sig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: e.proverPublicKey, + }, + } + + return errors.Wrap( + e.publishMessage( + application.CEREMONY_ADDRESS, + join, + ), + "announce join", + ) +} + +func (e *CeremonyExecutionEngine) connectToActivePeers( + app *application.CeremonyApplication, + position int, +) error { + idk, err := e.keyManager.GetAgreementKey("q-ratchet-idk") + if err != nil { + return errors.Wrap(err, "connect to active peers") + } + spk, err := e.keyManager.GetAgreementKey("q-ratchet-spk") + if err != nil { + return errors.Wrap(err, "connect to active peers") + } + + for i, p := range app.ActiveParticipants { + if !bytes.Equal(p.KeyValue, e.proverPublicKey) { + ic, err := e.keyStore.GetLatestKeyBundle(p.KeyValue) + if err != nil { + return errors.Wrap(err, "connect to active peers") + } + + var kba *protobufs.KeyBundleAnnouncement + switch ic.TypeUrl { + case protobufs.KeyBundleAnnouncementType: + kba = &protobufs.KeyBundleAnnouncement{} + if err := proto.Unmarshal( + ic.Data, + kba, + ); err != nil { + return errors.Wrap(err, "connect to active peers") + } + } + + receiverIdk, err := curves.ED448().Point.FromAffineCompressed( + kba.IdentityKey.GetPublicKeySignatureEd448().PublicKey.KeyValue, + ) + if err != nil { + return errors.Wrap(err, "connect to active peers") + } + + receiverSpk, err := curves.ED448().Point.FromAffineCompressed( + kba.SignedPreKey.GetPublicKeySignatureEd448().PublicKey.KeyValue, + ) + if err != nil { + return errors.Wrap(err, "connect to active peers") + } + + e.peerChannels[string(p.KeyValue)], err = p2p.NewPublicP2PChannel( + e.proverPublicKey, + p.KeyValue, + i > position, + idk, + spk, + receiverIdk, + receiverSpk, + curves.ED448(), + e.keyManager, + e.pubSub, + ) + if err != nil { + return errors.Wrap(err, "connect to active peers") + } + } + } + + return nil +} + +func (e *CeremonyExecutionEngine) participateRound( + app *application.CeremonyApplication, +) error { + idk, err := e.keyManager.GetAgreementKey("q-ratchet-idk") + if err != nil { + return errors.Wrap(err, "participate round") + } + + idkPoint := curves.ED448().Point.Generator().Mul(idk) + idks := []curves.Point{} + for _, p := range app.ActiveParticipants { + if !bytes.Equal(p.KeyValue, e.proverPublicKey) { + ic, err := e.keyStore.GetLatestKeyBundle(p.KeyValue) + if err != nil { + return errors.Wrap(err, "participate round") + } + + var kba *protobufs.KeyBundleAnnouncement + switch ic.TypeUrl { + case protobufs.KeyBundleAnnouncementType: + kba = &protobufs.KeyBundleAnnouncement{} + if err := proto.Unmarshal( + ic.Data, + kba, + ); err != nil { + return errors.Wrap(err, "participate round") + } + } + + receiverIdk, err := curves.ED448().Point.FromAffineCompressed( + kba.IdentityKey.GetPublicKeySignatureEd448().PublicKey.KeyValue, + ) + if err != nil { + return errors.Wrap(err, "participate round") + } + idks = append(idks, receiverIdk) + } else { + idks = append(idks, idkPoint) + } + } + + pubKeys := [][]byte{} + for _, p := range app.ActiveParticipants { + pubKeys = append(pubKeys, p.KeyValue) + } + + newSecrets, err := application.ProcessRound( + e.proverPublicKey, + idk, + int(app.RoundCount), + pubKeys, + idks, + e.activeSecrets, + curves.BLS48581G1(), + func(i int, filter, msg []byte) error { + return e.peerChannels[string(filter[len(e.proverPublicKey):])].Send(msg) + }, + func(i int, filter []byte) ([]byte, error) { + msg, err := e.peerChannels[string( + filter[:len(e.proverPublicKey)], + )].Receive() + if err != nil { + e.publishDroppedParticipant(filter[:len(e.proverPublicKey)]) + return nil, err + } else { + if i == 0 { + e.publishLastSeenParticipant(filter[:len(e.proverPublicKey)]) + } + return msg, nil + } + }, + app.LatestTranscript.G1Powers[1].KeyValue, + ) + if err != nil { + return errors.Wrap(err, "participate round") + } + + return errors.Wrap(e.commitRound(newSecrets), "participate round") +} + +func (e *CeremonyExecutionEngine) commitRound(secrets []curves.Scalar) error { + g2Pub := curves.BLS48581G2().Point.Generator().Mul(secrets[0]) + + sig, err := application.SignProverKeyForCommit( + e.proverPublicKey, + secrets[0], + ) + if err != nil { + return errors.Wrap(err, "commit round") + } + + proverSig, err := e.provingKey.Sign( + rand.Reader, + g2Pub.ToAffineCompressed(), + crypto.Hash(0), + ) + if err != nil { + return errors.Wrap(err, "commit round") + } + + advance := &protobufs.CeremonyTranscriptCommit{ + ProverSignature: &protobufs.Ed448Signature{ + Signature: proverSig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: e.proverPublicKey, + }, + }, + ContributionSignature: &protobufs.BLS48581Signature{ + Signature: sig, + PublicKey: &protobufs.BLS48581G2PublicKey{ + KeyValue: g2Pub.ToAffineCompressed(), + }, + }, + } + + if err := e.publishMessage( + application.CEREMONY_ADDRESS, + advance, + ); err != nil { + return errors.Wrap(err, "commit round") + } + + e.activeSecrets = secrets + return nil +} + +// Publishes a dropped participant attestation, logs any errors but does not +// forward them on. +func (e *CeremonyExecutionEngine) publishDroppedParticipant( + participant []byte, +) { + frameNumber := e.clock.GetFrame() + + b := binary.BigEndian.AppendUint64([]byte("dropped"), frameNumber) + b = append(b, participant...) + sig, err := e.provingKey.Sign(rand.Reader, b, crypto.Hash(0)) + if err != nil { + e.logger.Error( + "error while signing dropped participant attestation", + zap.Error(err), + ) + return + } + + dropped := &protobufs.CeremonyDroppedProverAttestation{ + DroppedProverKey: &protobufs.Ed448PublicKey{ + KeyValue: participant, + }, + LastSeenFrame: frameNumber, + ProverSignature: &protobufs.Ed448Signature{ + Signature: sig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: e.proverPublicKey, + }, + }, + } + + err = e.publishMessage( + application.CEREMONY_ADDRESS, + dropped, + ) + if err != nil { + e.logger.Error( + "error while publishing dropped participant attestation", + zap.Error(err), + ) + return + } +} + +// Publishes a last seen participant attestation, logs any errors but does not +// forward them on. +func (e *CeremonyExecutionEngine) publishLastSeenParticipant( + participant []byte, +) { + frameNumber := e.clock.GetFrame() + + b := binary.BigEndian.AppendUint64([]byte("lastseen"), frameNumber) + b = append(b, participant...) + sig, err := e.provingKey.Sign(rand.Reader, b, crypto.Hash(0)) + if err != nil { + e.logger.Error( + "error while signing last seen participant attestation", + zap.Error(err), + ) + return + } + + seen := &protobufs.CeremonySeenProverAttestation{ + SeenProverKey: &protobufs.Ed448PublicKey{ + KeyValue: participant, + }, + LastSeenFrame: frameNumber, + ProverSignature: &protobufs.Ed448Signature{ + Signature: sig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: e.proverPublicKey, + }, + }, + } + err = e.publishMessage( + application.CEREMONY_ADDRESS, + seen, + ) + if err != nil { + e.logger.Error( + "error while publishing dropped participant attestation", + zap.Error(err), + ) + return + } +} + +func (e *CeremonyExecutionEngine) publishTranscriptShare( + app *application.CeremonyApplication, +) error { + transcriptShare := &protobufs.CeremonyTranscriptShare{} + transcriptShare.AdditiveG1Powers = make( + []*protobufs.BLS48581G1PublicKey, + len(e.activeSecrets), + ) + transcriptShare.AdditiveG2Powers = make( + []*protobufs.BLS48581G2PublicKey, + len(app.LatestTranscript.G2Powers)-1, + ) + + eg := errgroup.Group{} + eg.SetLimit(100) + e.logger.Info("creating transcript share") + for i, s := range e.activeSecrets { + i := i + s := s + eg.Go(func() error { + if i%100 == 0 { + e.logger.Info( + "writing transcript share chunk", + zap.Int("chunk_start", i), + ) + } + + basisG1, err := curves.BLS48581G1().Point.FromAffineCompressed( + app.LatestTranscript.G1Powers[i+1].KeyValue, + ) + if err != nil { + return errors.Wrap(err, "publish transcript share") + } + + transcriptShare.AdditiveG1Powers[i] = &protobufs.BLS48581G1PublicKey{ + KeyValue: basisG1.Mul(s).ToAffineCompressed(), + } + + if i+1 < len(app.LatestTranscript.G2Powers) { + basisG2, err := curves.BLS48581G2().Point.FromAffineCompressed( + app.LatestTranscript.G2Powers[i+1].KeyValue, + ) + if err != nil { + return errors.Wrap(err, "publish transcript share") + } + + transcriptShare.AdditiveG2Powers[i] = &protobufs.BLS48581G2PublicKey{ + KeyValue: basisG2.Mul(s).ToAffineCompressed(), + } + } + return nil + }) + } + + if err := eg.Wait(); err != nil { + return err + } + + e.logger.Info( + "done writing transcript chunks, adding witnesses and signing", + ) + + transcriptShare.AdditiveG1_256Witness = &protobufs.BLS48581G1PublicKey{ + KeyValue: curves.BLS48581G1().Point.Generator().Mul( + e.activeSecrets[len(app.LatestTranscript.G2Powers)-2], + ).ToAffineCompressed(), + } + + transcriptShare.AdditiveG2_256Witness = &protobufs.BLS48581G2PublicKey{ + KeyValue: curves.BLS48581G2().Point.Generator().Mul( + e.activeSecrets[len(app.LatestTranscript.G2Powers)-2], + ).ToAffineCompressed(), + } + + sig, err := transcriptShare.SignWithProverKey(e.provingKey) + if err != nil { + errors.Wrap(err, "publish transcript share") + } + + transcriptShare.ProverSignature = &protobufs.Ed448Signature{ + Signature: sig, + PublicKey: &protobufs.Ed448PublicKey{ + KeyValue: e.proverPublicKey, + }, + } + + err = errors.Wrap( + e.publishMessage( + application.CEREMONY_ADDRESS, + transcriptShare, + ), + "publish transcript share", + ) + if err != nil { + return err + } else { + e.alreadyPublishedShare = true + return nil + } +} + +func (e *CeremonyExecutionEngine) VerifyExecution( + frame *protobufs.ClockFrame, +) error { + if e.clock.GetFrame() != frame.FrameNumber-1 { + return nil + } + + if len(frame.AggregateProofs) > 0 { + for _, proofs := range frame.AggregateProofs { + for _, inclusion := range proofs.InclusionCommitments { + if inclusion.TypeUrl == protobufs.IntrinsicExecutionOutputType { + transition, _, err := application.GetOutputsFromClockFrame(frame) + if err != nil { + return errors.Wrap(err, "verify execution") + } + + parent, err := e.clockStore.GetParentDataClockFrame( + application.CEREMONY_ADDRESS, + frame.FrameNumber-1, + frame.ParentSelector, + ) + if err != nil && !errors.Is(err, store.ErrNotFound) { + return errors.Wrap(err, "verify execution") + } + + if parent == nil { + return errors.Wrap( + errors.New("missing parent frame"), + "verify execution", + ) + } + + a, err := application.MaterializeApplicationFromFrame(parent) + if err != nil { + return errors.Wrap(err, "verify execution") + } + + a, err = a.ApplyTransition(frame.FrameNumber, transition) + if err != nil { + return errors.Wrap(err, "verify execution") + } + + a2, err := application.MaterializeApplicationFromFrame(frame) + if err != nil { + return errors.Wrap(err, "verify execution") + } + + if !a.Equals(a2) { + return errors.Wrap( + application.ErrInvalidStateTransition, + "verify execution", + ) + } + + return nil + } + } + } + } + + return nil +} + +func (e *CeremonyExecutionEngine) publishTranscript( + app *application.CeremonyApplication, +) error { + e.logger.Info("publishing updated transcript") + e.alreadyPublishedTranscript = true + err := errors.Wrap( + e.publishMessage( + application.CEREMONY_ADDRESS, + app.UpdatedTranscript, + ), + "publish transcript share", + ) + if err != nil { + e.alreadyPublishedTranscript = false + return err + } else { + return nil + } +} + +func (e *CeremonyExecutionEngine) ensureSecrets( + app *application.CeremonyApplication, +) { + if len(e.activeSecrets) == 0 { + e.activeSecrets = []curves.Scalar{} + t := curves.BLS48581G1().Scalar.Random(rand.Reader) + x := t.Clone() + + for i := 0; i < len(app.LatestTranscript.G1Powers)-1; i++ { + if i%1000 == 0 { + e.logger.Info( + "calculating secrets for contribution", + zap.Int("secrets_calculated", i), + zap.Int("total_secrets", len(app.LatestTranscript.G1Powers)-1), + ) + } + e.activeSecrets = append(e.activeSecrets, x) + x = x.Mul(t) + } + + e.logger.Info( + "done preparing contribution", + zap.Int("secrets_calculated", len(e.activeSecrets)), + ) + } +} diff --git a/node/execution/nop/nop_execution_engine.go b/node/execution/nop/nop_execution_engine.go deleted file mode 100644 index 32cbf9f..0000000 --- a/node/execution/nop/nop_execution_engine.go +++ /dev/null @@ -1,95 +0,0 @@ -package nop - -import ( - "github.com/pkg/errors" - "go.uber.org/zap" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/anypb" - - "source.quilibrium.com/quilibrium/monorepo/node/execution" - "source.quilibrium.com/quilibrium/monorepo/node/protobufs" -) - -type NopExecutionEngine struct { - logger *zap.Logger -} - -func NewNopExecutionEngine( - logger *zap.Logger, -) *NopExecutionEngine { - if logger == nil { - panic(errors.New("logger is nil")) - } - - return &NopExecutionEngine{ - logger: logger, - } -} - -var _ execution.ExecutionEngine = (*NopExecutionEngine)(nil) - -// GetName implements ExecutionEngine -func (*NopExecutionEngine) GetName() string { - return "nop" -} - -// GetSupportedApplications implements ExecutionEngine -func ( - *NopExecutionEngine, -) GetSupportedApplications() []*protobufs.Application { - return []*protobufs.Application{ - { - Address: []byte{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }, - ExecutionContext: protobufs.ExecutionContext_EXECUTION_CONTEXT_INTRINSIC, - }, - } -} - -// Start implements ExecutionEngine -func (e *NopExecutionEngine) Start() <-chan error { - errChan := make(chan error) - - go func() { - errChan <- nil - }() - - return errChan -} - -// Stop implements ExecutionEngine -func (*NopExecutionEngine) Stop(force bool) <-chan error { - errChan := make(chan error) - - go func() { - errChan <- nil - }() - - return errChan -} - -// ProcessMessage implements ExecutionEngine -func (e *NopExecutionEngine) ProcessMessage( - address []byte, - message *protobufs.Message, -) ([]*protobufs.Message, error) { - any := &anypb.Any{} - if err := proto.Unmarshal(message.Payload, any); err != nil { - return nil, errors.Wrap(err, "could not unmarshal message") - } - - if any.TypeUrl == protobufs.ClockFrameType { - frame := &protobufs.ClockFrame{} - if err := any.UnmarshalTo(frame); err != nil { - return nil, errors.Wrap(err, "could not unmarshal clock frame") - } - - e.logger.Info("nop") - } - - return nil, nil -} diff --git a/node/go.mod b/node/go.mod index f474d5b..854e94e 100644 --- a/node/go.mod +++ b/node/go.mod @@ -32,8 +32,10 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/gorilla/websocket v1.5.0 // indirect + github.com/gtank/merlin v0.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect + github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect github.com/multiformats/go-multiaddr v0.10.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/node/go.sum b/node/go.sum index 1190da0..1342d26 100644 --- a/node/go.sum +++ b/node/go.sum @@ -214,6 +214,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= +github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -357,6 +359,8 @@ github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUM github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= diff --git a/node/keys/file.go b/node/keys/file.go index f6b07ac..c3633a6 100644 --- a/node/keys/file.go +++ b/node/keys/file.go @@ -24,7 +24,7 @@ type FileKeyManager struct { } var UnsupportedKeyTypeErr = errors.New("unsupported key type") -var KeyNotFoundErr = errors.New("unsupported key type") +var KeyNotFoundErr = errors.New("key not found") func NewFileKeyManager( keyStoreConfig *config.KeyConfig, diff --git a/node/main.go b/node/main.go index fea4e21..44e5479 100644 --- a/node/main.go +++ b/node/main.go @@ -4,8 +4,10 @@ import ( "encoding/hex" "flag" "fmt" + "io/fs" "os" "os/signal" + "path/filepath" "syscall" "github.com/libp2p/go-libp2p/core/crypto" @@ -13,6 +15,7 @@ import ( "github.com/pkg/errors" "source.quilibrium.com/quilibrium/monorepo/node/app" "source.quilibrium.com/quilibrium/monorepo/node/config" + qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto" ) var ( @@ -58,6 +61,8 @@ func main() { panic(err) } + clearIfTestData(*configDirectory, nodeConfig) + if *dbConsole { console, err := app.NewDBConsole(nodeConfig) if err != nil { @@ -68,6 +73,9 @@ func main() { return } + fmt.Println("Loading ceremony state and starting node...") + qcrypto.Init() + node, err := app.NewNode(nodeConfig) if err != nil { panic(err) @@ -78,6 +86,36 @@ func main() { node.Stop() } +func clearIfTestData(configDir string, nodeConfig *config.Config) { + _, err := os.Stat(filepath.Join(configDir, "RELEASE_VERSION")) + if os.IsNotExist(err) { + fmt.Println("Clearing test data...") + err := os.RemoveAll(nodeConfig.DB.Path) + if err != nil { + panic(err) + } + + versionFile, err := os.OpenFile( + filepath.Join(configDir, "RELEASE_VERSION"), + os.O_CREATE|os.O_RDWR, + fs.FileMode(0700), + ) + if err != nil { + panic(err) + } + + _, err = versionFile.Write([]byte{0x01, 0x00, 0x00}) + if err != nil { + panic(err) + } + + err = versionFile.Close() + if err != nil { + panic(err) + } + } +} + func printPeerID(p2pConfig *config.P2PConfig) { peerPrivKey, err := hex.DecodeString(p2pConfig.PeerPrivKey) if err != nil { @@ -135,5 +173,5 @@ func printLogo() { func printVersion() { fmt.Println(" ") - fmt.Println(" Quilibrium Node - v1.0.0 – DHT Verification") + fmt.Println(" Quilibrium Node - v1.0.0 – Dawn") } diff --git a/node/p2p/blossomsub.go b/node/p2p/blossomsub.go index 3b14d47..3c5cf54 100644 --- a/node/p2p/blossomsub.go +++ b/node/p2p/blossomsub.go @@ -4,8 +4,10 @@ import ( "context" "crypto/rand" "encoding/hex" + "fmt" "math/big" "sync" + "time" "github.com/libp2p/go-libp2p" dht "github.com/libp2p/go-libp2p-kad-dht" @@ -76,12 +78,14 @@ func NewBlossomSub( go discoverPeers(p2pConfig, ctx, logger, h) + // TODO: turn into an option flag for console logging, this is too noisy for + // default logging behavior var tracer *blossomsub.JSONTracer if p2pConfig.TraceLogFile == "" { - tracer, err = blossomsub.NewStdoutJSONTracer() - if err != nil { - panic(errors.Wrap(err, "error building stdout tracer")) - } + // tracer, err = blossomsub.NewStdoutJSONTracer() + // if err != nil { + // panic(errors.Wrap(err, "error building stdout tracer")) + // } } else { tracer, err = blossomsub.NewJSONTracer(p2pConfig.TraceLogFile) if err != nil { @@ -89,8 +93,9 @@ func NewBlossomSub( } } - blossomOpts := []blossomsub.Option{ - blossomsub.WithEventTracer(tracer), + blossomOpts := []blossomsub.Option{} + if tracer != nil { + blossomOpts = append(blossomOpts, blossomsub.WithEventTracer(tracer)) } params := mergeDefaults(p2pConfig) @@ -236,30 +241,62 @@ func initDHT( if err = kademliaDHT.Bootstrap(ctx); err != nil { panic(err) } - var wg sync.WaitGroup - logger.Info("connecting to bootstrap", zap.String("peer_id", h.ID().String())) + reconnect := func() { + var wg sync.WaitGroup - defaultBootstrapPeers := p2pConfig.BootstrapPeers + logger.Info("connecting to bootstrap", zap.String("peer_id", h.ID().String())) - for _, peerAddr := range defaultBootstrapPeers { - peerinfo, err := peer.AddrInfoFromString(peerAddr) - if err != nil { - panic(err) - } - wg.Add(1) - go func() { - defer wg.Done() - if err := h.Connect(ctx, *peerinfo); err != nil { - logger.Warn("error while connecting to dht peer", zap.Error(err)) + defaultBootstrapPeers := p2pConfig.BootstrapPeers + + for _, peerAddr := range defaultBootstrapPeers { + peerinfo, err := peer.AddrInfoFromString(peerAddr) + if err != nil { + panic(err) } - }() + wg.Add(1) + go func() { + defer wg.Done() + if err := h.Connect(ctx, *peerinfo); err != nil { + logger.Warn("error while connecting to dht peer", zap.Error(err)) + } + }() + } + wg.Wait() } - wg.Wait() + + reconnect() + + go func() { + for { + time.Sleep(30 * time.Second) + if len(h.Network().Peers()) == 0 { + logger.Info("reconnecting to peers") + reconnect() + } + } + }() return kademliaDHT } +func (b *BlossomSub) GetBitmaskPeers() map[string][]string { + peers := map[string][]string{} + + for _, k := range b.bitmaskMap { + peers[fmt.Sprintf("%+x", k.Bitmask())] = []string{} + + for _, p := range k.ListPeers() { + peers[fmt.Sprintf("%+x", k.Bitmask())] = append( + peers[fmt.Sprintf("%+x", k.Bitmask())], + p.String(), + ) + } + } + + return peers +} + func (b *BlossomSub) GetPeerstoreCount() int { return len(b.h.Peerstore().Peers()) } diff --git a/node/p2p/public_channel.go b/node/p2p/public_channel.go new file mode 100644 index 0000000..1be180f --- /dev/null +++ b/node/p2p/public_channel.go @@ -0,0 +1,194 @@ +package p2p + +import ( + "crypto/rand" + "encoding/binary" + "sync" + "time" + + "github.com/pkg/errors" + "google.golang.org/protobuf/proto" + "source.quilibrium.com/quilibrium/monorepo/go-libp2p-blossomsub/pb" + "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" + "source.quilibrium.com/quilibrium/monorepo/node/crypto" + "source.quilibrium.com/quilibrium/monorepo/node/keys" + "source.quilibrium.com/quilibrium/monorepo/node/protobufs" +) + +// A simplified P2P channel – the pair of actors communicating is public +// knowledge, even though the data itself is encrypted. +type PublicP2PChannel struct { + participant *crypto.DoubleRatchetParticipant + sendMap map[uint64][]byte + receiveMap map[uint64][]byte + pubSub PubSub + sendFilter []byte + receiveFilter []byte + initiator bool + senderSeqNo uint64 + receiverSeqNo uint64 + receiveChan chan []byte + receiveMx sync.Mutex +} + +func NewPublicP2PChannel( + senderIdentifier, receiverIdentifier []byte, + initiator bool, + sendingIdentityPrivateKey curves.Scalar, + sendingSignedPrePrivateKey curves.Scalar, + receivingIdentityKey curves.Point, + receivingSignedPreKey curves.Point, + curve *curves.Curve, + keyManager keys.KeyManager, + pubSub PubSub, +) (*PublicP2PChannel, error) { + sendFilter := append( + append([]byte{}, senderIdentifier...), + receiverIdentifier..., + ) + receiveFilter := append( + append([]byte{}, receiverIdentifier...), + senderIdentifier..., + ) + + channel := &PublicP2PChannel{ + sendMap: map[uint64][]byte{}, + receiveMap: map[uint64][]byte{}, + initiator: initiator, + sendFilter: sendFilter, + receiveFilter: receiveFilter, + pubSub: pubSub, + senderSeqNo: 0, + receiverSeqNo: 0, + receiveChan: make(chan []byte), + } + + var err error + var participant *crypto.DoubleRatchetParticipant + if initiator { + sendingEphemeralPrivateKey := curve.Scalar.Random( + rand.Reader, + ) + x3dh := crypto.SenderX3DH( + sendingIdentityPrivateKey, + sendingSignedPrePrivateKey, + receivingIdentityKey, + receivingSignedPreKey, + 96, + ) + participant, err = crypto.NewDoubleRatchetParticipant( + x3dh[:32], + x3dh[32:64], + x3dh[64:], + true, + sendingEphemeralPrivateKey, + receivingSignedPreKey, + curve, + keyManager, + ) + if err != nil { + return nil, errors.Wrap(err, "new public p2p channel") + } + } else { + x3dh := crypto.SenderX3DH( + sendingIdentityPrivateKey, + sendingSignedPrePrivateKey, + receivingIdentityKey, + receivingSignedPreKey, + 96, + ) + participant, err = crypto.NewDoubleRatchetParticipant( + x3dh[:32], + x3dh[32:64], + x3dh[64:], + false, + sendingSignedPrePrivateKey, + nil, + curve, + keyManager, + ) + if err != nil { + return nil, errors.Wrap(err, "new public p2p channel") + } + } + + channel.participant = participant + + pubSub.Subscribe( + sendFilter, + func(message *pb.Message) error { return nil }, + true, + ) + + pubSub.Subscribe( + receiveFilter, + channel.handleReceive, + true, + ) + + return channel, nil +} + +func (c *PublicP2PChannel) handleReceive(message *pb.Message) error { + envelope := &protobufs.P2PChannelEnvelope{} + if err := proto.Unmarshal(message.Data, envelope); err != nil { + return errors.Wrap(err, "handle receive") + } + + c.receiveMx.Lock() + rawData, err := c.participant.RatchetDecrypt(envelope) + c.receiveMx.Unlock() + if err != nil { + return errors.Wrap(err, "handle receive") + } + + seqNo := binary.BigEndian.Uint64(rawData[:8]) + + if seqNo == c.receiverSeqNo { + c.receiveChan <- rawData[8:] + } else { + c.receiveMx.Lock() + c.receiveMap[seqNo] = rawData[8:] + c.receiveMx.Unlock() + } + + return nil +} + +func (c *PublicP2PChannel) Send(message []byte) error { + c.senderSeqNo++ + message = append( + binary.BigEndian.AppendUint64(nil, c.senderSeqNo), + message..., + ) + + envelope, err := c.participant.RatchetEncrypt(message) + if err != nil { + return errors.Wrap(err, "send") + } + + rawBytes, err := proto.Marshal(envelope) + if err != nil { + return errors.Wrap(err, "send") + } + + c.sendMap[c.senderSeqNo] = rawBytes + + return errors.Wrap(c.pubSub.PublishToBitmask(c.sendFilter, rawBytes), "send") +} + +func (c *PublicP2PChannel) Receive() ([]byte, error) { + c.receiverSeqNo++ + after := time.After(20 * time.Second) + select { + case msg := <-c.receiveChan: + return msg, nil + case <-after: + return nil, errors.Wrap(errors.New("timed out"), "receive") + } +} + +func (c *PublicP2PChannel) Close() { + c.pubSub.Unsubscribe(c.sendFilter, true) + c.pubSub.Unsubscribe(c.receiveFilter, true) +} diff --git a/node/p2p/pubsub.go b/node/p2p/pubsub.go index 6687534..f9d6e76 100644 --- a/node/p2p/pubsub.go +++ b/node/p2p/pubsub.go @@ -10,6 +10,7 @@ type PubSub interface { Subscribe(bitmask []byte, handler func(message *pb.Message) error, raw bool) Unsubscribe(bitmask []byte, raw bool) GetPeerID() []byte + GetBitmaskPeers() map[string][]string GetPeerstoreCount() int GetNetworkPeersCount() int GetRandomPeer(bitmask []byte) ([]byte, error) diff --git a/node/protobufs/ceremony.go b/node/protobufs/ceremony.go new file mode 100644 index 0000000..8f55390 --- /dev/null +++ b/node/protobufs/ceremony.go @@ -0,0 +1,91 @@ +package protobufs + +import ( + "crypto" + "crypto/rand" + "encoding/binary" + + "github.com/cloudflare/circl/sign/ed448" + "github.com/pkg/errors" + "golang.org/x/crypto/sha3" +) + +func (j *CeremonyLobbyJoin) VerifySignature() error { + b := binary.BigEndian.AppendUint64([]byte("join"), j.FrameNumber) + b = append(b, j.IdentityKey.KeyValue...) + b = append(b, j.SignedPreKey.KeyValue...) + + if !ed448.Verify( + j.PublicKeySignatureEd448.PublicKey.KeyValue, + b, + j.PublicKeySignatureEd448.Signature, + "", + ) { + return errors.Wrap(errors.New("invalid signature"), "sign with prover key") + } + + return nil +} + +func (j *CeremonyLobbyJoin) SignWithProverKey( + signer crypto.Signer, +) ([]byte, error) { + b := binary.BigEndian.AppendUint64([]byte("join"), j.FrameNumber) + b = append(b, j.IdentityKey.KeyValue...) + b = append(b, j.SignedPreKey.KeyValue...) + + // Non edwards signing variants need support to specify hash, edwards variants + // demand Hash(0) because it does SHA512 under the hood. + sig, err := signer.Sign(rand.Reader, b, crypto.Hash(0)) + return sig, errors.Wrap(err, "sign with prover key") +} + +func (t *CeremonyTranscriptShare) VerifySignature() error { + hash := sha3.New256() + + for _, g1 := range t.AdditiveG1Powers { + if _, err := hash.Write(g1.KeyValue); err != nil { + return errors.Wrap(err, "verify signature") + } + } + + for _, g2 := range t.AdditiveG2Powers { + if _, err := hash.Write(g2.KeyValue); err != nil { + return errors.Wrap(err, "verify signature") + } + } + + if _, err := hash.Write(t.AdditiveG1_256Witness.KeyValue); err != nil { + return errors.Wrap(err, "verify signature") + } + + return errors.Wrap( + t.ProverSignature.Verify(hash.Sum(nil)), + "verify signature", + ) +} + +func (t *CeremonyTranscriptShare) SignWithProverKey( + signer crypto.Signer, +) ([]byte, error) { + hash := sha3.New256() + + for _, g1 := range t.AdditiveG1Powers { + if _, err := hash.Write(g1.KeyValue); err != nil { + return nil, errors.Wrap(err, "sign with prover key") + } + } + + for _, g2 := range t.AdditiveG2Powers { + if _, err := hash.Write(g2.KeyValue); err != nil { + return nil, errors.Wrap(err, "sign with prover key") + } + } + + if _, err := hash.Write(t.AdditiveG1_256Witness.KeyValue); err != nil { + return nil, errors.Wrap(err, "sign with prover key") + } + + signature, err := signer.Sign(rand.Reader, hash.Sum(nil), crypto.Hash(0)) + return signature, errors.Wrap(err, "sign with prover key") +} diff --git a/node/protobufs/ceremony.pb.go b/node/protobufs/ceremony.pb.go index fc904b1..8a06c18 100644 --- a/node/protobufs/ceremony.pb.go +++ b/node/protobufs/ceremony.pb.go @@ -116,6 +116,862 @@ func (x *CeremonyTranscript) GetRunningG2_256Powers() []*BLS48581G2PublicKey { return nil } +type CeremonyLobbyState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LobbyState int32 `protobuf:"varint,1,opt,name=lobby_state,json=lobbyState,proto3" json:"lobby_state,omitempty"` + // Types that are assignable to CeremonyState: + // + // *CeremonyLobbyState_CeremonyOpenState + // *CeremonyLobbyState_CeremonyInProgressState + // *CeremonyLobbyState_CeremonyFinalizingState + // *CeremonyLobbyState_CeremonyValidatingState + CeremonyState isCeremonyLobbyState_CeremonyState `protobuf_oneof:"ceremony_state"` + LatestTranscript *CeremonyTranscript `protobuf:"bytes,6,opt,name=latest_transcript,json=latestTranscript,proto3" json:"latest_transcript,omitempty"` + RewardTrie []byte `protobuf:"bytes,7,opt,name=reward_trie,json=rewardTrie,proto3" json:"reward_trie,omitempty"` +} + +func (x *CeremonyLobbyState) Reset() { + *x = CeremonyLobbyState{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyLobbyState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyLobbyState) ProtoMessage() {} + +func (x *CeremonyLobbyState) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyLobbyState.ProtoReflect.Descriptor instead. +func (*CeremonyLobbyState) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{1} +} + +func (x *CeremonyLobbyState) GetLobbyState() int32 { + if x != nil { + return x.LobbyState + } + return 0 +} + +func (m *CeremonyLobbyState) GetCeremonyState() isCeremonyLobbyState_CeremonyState { + if m != nil { + return m.CeremonyState + } + return nil +} + +func (x *CeremonyLobbyState) GetCeremonyOpenState() *CeremonyOpenState { + if x, ok := x.GetCeremonyState().(*CeremonyLobbyState_CeremonyOpenState); ok { + return x.CeremonyOpenState + } + return nil +} + +func (x *CeremonyLobbyState) GetCeremonyInProgressState() *CeremonyInProgressState { + if x, ok := x.GetCeremonyState().(*CeremonyLobbyState_CeremonyInProgressState); ok { + return x.CeremonyInProgressState + } + return nil +} + +func (x *CeremonyLobbyState) GetCeremonyFinalizingState() *CeremonyFinalizingState { + if x, ok := x.GetCeremonyState().(*CeremonyLobbyState_CeremonyFinalizingState); ok { + return x.CeremonyFinalizingState + } + return nil +} + +func (x *CeremonyLobbyState) GetCeremonyValidatingState() *CeremonyValidatingState { + if x, ok := x.GetCeremonyState().(*CeremonyLobbyState_CeremonyValidatingState); ok { + return x.CeremonyValidatingState + } + return nil +} + +func (x *CeremonyLobbyState) GetLatestTranscript() *CeremonyTranscript { + if x != nil { + return x.LatestTranscript + } + return nil +} + +func (x *CeremonyLobbyState) GetRewardTrie() []byte { + if x != nil { + return x.RewardTrie + } + return nil +} + +type isCeremonyLobbyState_CeremonyState interface { + isCeremonyLobbyState_CeremonyState() +} + +type CeremonyLobbyState_CeremonyOpenState struct { + CeremonyOpenState *CeremonyOpenState `protobuf:"bytes,2,opt,name=ceremony_open_state,json=ceremonyOpenState,proto3,oneof"` +} + +type CeremonyLobbyState_CeremonyInProgressState struct { + CeremonyInProgressState *CeremonyInProgressState `protobuf:"bytes,3,opt,name=ceremony_in_progress_state,json=ceremonyInProgressState,proto3,oneof"` +} + +type CeremonyLobbyState_CeremonyFinalizingState struct { + CeremonyFinalizingState *CeremonyFinalizingState `protobuf:"bytes,4,opt,name=ceremony_finalizing_state,json=ceremonyFinalizingState,proto3,oneof"` +} + +type CeremonyLobbyState_CeremonyValidatingState struct { + CeremonyValidatingState *CeremonyValidatingState `protobuf:"bytes,5,opt,name=ceremony_validating_state,json=ceremonyValidatingState,proto3,oneof"` +} + +func (*CeremonyLobbyState_CeremonyOpenState) isCeremonyLobbyState_CeremonyState() {} + +func (*CeremonyLobbyState_CeremonyInProgressState) isCeremonyLobbyState_CeremonyState() {} + +func (*CeremonyLobbyState_CeremonyFinalizingState) isCeremonyLobbyState_CeremonyState() {} + +func (*CeremonyLobbyState_CeremonyValidatingState) isCeremonyLobbyState_CeremonyState() {} + +type CeremonySeenProverAttestation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SeenProverKey *Ed448PublicKey `protobuf:"bytes,1,opt,name=seen_prover_key,json=seenProverKey,proto3" json:"seen_prover_key,omitempty"` + LastSeenFrame uint64 `protobuf:"varint,2,opt,name=last_seen_frame,json=lastSeenFrame,proto3" json:"last_seen_frame,omitempty"` + ProverSignature *Ed448Signature `protobuf:"bytes,3,opt,name=prover_signature,json=proverSignature,proto3" json:"prover_signature,omitempty"` +} + +func (x *CeremonySeenProverAttestation) Reset() { + *x = CeremonySeenProverAttestation{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonySeenProverAttestation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonySeenProverAttestation) ProtoMessage() {} + +func (x *CeremonySeenProverAttestation) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonySeenProverAttestation.ProtoReflect.Descriptor instead. +func (*CeremonySeenProverAttestation) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{2} +} + +func (x *CeremonySeenProverAttestation) GetSeenProverKey() *Ed448PublicKey { + if x != nil { + return x.SeenProverKey + } + return nil +} + +func (x *CeremonySeenProverAttestation) GetLastSeenFrame() uint64 { + if x != nil { + return x.LastSeenFrame + } + return 0 +} + +func (x *CeremonySeenProverAttestation) GetProverSignature() *Ed448Signature { + if x != nil { + return x.ProverSignature + } + return nil +} + +type CeremonyDroppedProverAttestation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DroppedProverKey *Ed448PublicKey `protobuf:"bytes,1,opt,name=dropped_prover_key,json=droppedProverKey,proto3" json:"dropped_prover_key,omitempty"` + LastSeenFrame uint64 `protobuf:"varint,2,opt,name=last_seen_frame,json=lastSeenFrame,proto3" json:"last_seen_frame,omitempty"` + ProverSignature *Ed448Signature `protobuf:"bytes,3,opt,name=prover_signature,json=proverSignature,proto3" json:"prover_signature,omitempty"` +} + +func (x *CeremonyDroppedProverAttestation) Reset() { + *x = CeremonyDroppedProverAttestation{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyDroppedProverAttestation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyDroppedProverAttestation) ProtoMessage() {} + +func (x *CeremonyDroppedProverAttestation) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyDroppedProverAttestation.ProtoReflect.Descriptor instead. +func (*CeremonyDroppedProverAttestation) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{3} +} + +func (x *CeremonyDroppedProverAttestation) GetDroppedProverKey() *Ed448PublicKey { + if x != nil { + return x.DroppedProverKey + } + return nil +} + +func (x *CeremonyDroppedProverAttestation) GetLastSeenFrame() uint64 { + if x != nil { + return x.LastSeenFrame + } + return 0 +} + +func (x *CeremonyDroppedProverAttestation) GetProverSignature() *Ed448Signature { + if x != nil { + return x.ProverSignature + } + return nil +} + +type CeremonyTranscriptShare struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AdditiveG1Powers []*BLS48581G1PublicKey `protobuf:"bytes,1,rep,name=additive_g1_powers,json=additiveG1Powers,proto3" json:"additive_g1_powers,omitempty"` + AdditiveG2Powers []*BLS48581G2PublicKey `protobuf:"bytes,2,rep,name=additive_g2_powers,json=additiveG2Powers,proto3" json:"additive_g2_powers,omitempty"` + AdditiveG1_256Witness *BLS48581G1PublicKey `protobuf:"bytes,3,opt,name=additive_g1_256_witness,json=additiveG1256Witness,proto3" json:"additive_g1_256_witness,omitempty"` + AdditiveG2_256Witness *BLS48581G2PublicKey `protobuf:"bytes,4,opt,name=additive_g2_256_witness,json=additiveG2256Witness,proto3" json:"additive_g2_256_witness,omitempty"` + ProverSignature *Ed448Signature `protobuf:"bytes,5,opt,name=prover_signature,json=proverSignature,proto3" json:"prover_signature,omitempty"` +} + +func (x *CeremonyTranscriptShare) Reset() { + *x = CeremonyTranscriptShare{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyTranscriptShare) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyTranscriptShare) ProtoMessage() {} + +func (x *CeremonyTranscriptShare) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyTranscriptShare.ProtoReflect.Descriptor instead. +func (*CeremonyTranscriptShare) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{4} +} + +func (x *CeremonyTranscriptShare) GetAdditiveG1Powers() []*BLS48581G1PublicKey { + if x != nil { + return x.AdditiveG1Powers + } + return nil +} + +func (x *CeremonyTranscriptShare) GetAdditiveG2Powers() []*BLS48581G2PublicKey { + if x != nil { + return x.AdditiveG2Powers + } + return nil +} + +func (x *CeremonyTranscriptShare) GetAdditiveG1_256Witness() *BLS48581G1PublicKey { + if x != nil { + return x.AdditiveG1_256Witness + } + return nil +} + +func (x *CeremonyTranscriptShare) GetAdditiveG2_256Witness() *BLS48581G2PublicKey { + if x != nil { + return x.AdditiveG2_256Witness + } + return nil +} + +func (x *CeremonyTranscriptShare) GetProverSignature() *Ed448Signature { + if x != nil { + return x.ProverSignature + } + return nil +} + +// Describes the required proof to commit to a transcript to advance a round, +// and as a proof to move to the verification state +type CeremonyTranscriptCommit struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Prover key signature over the G1 point of the additive share of the first + // power. + ProverSignature *Ed448Signature `protobuf:"bytes,1,opt,name=prover_signature,json=proverSignature,proto3" json:"prover_signature,omitempty"` + // BLS short signature over the Ed448 prover public key, using the additive + // share of the first power. + ContributionSignature *BLS48581Signature `protobuf:"bytes,2,opt,name=contribution_signature,json=contributionSignature,proto3" json:"contribution_signature,omitempty"` +} + +func (x *CeremonyTranscriptCommit) Reset() { + *x = CeremonyTranscriptCommit{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyTranscriptCommit) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyTranscriptCommit) ProtoMessage() {} + +func (x *CeremonyTranscriptCommit) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyTranscriptCommit.ProtoReflect.Descriptor instead. +func (*CeremonyTranscriptCommit) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{5} +} + +func (x *CeremonyTranscriptCommit) GetProverSignature() *Ed448Signature { + if x != nil { + return x.ProverSignature + } + return nil +} + +func (x *CeremonyTranscriptCommit) GetContributionSignature() *BLS48581Signature { + if x != nil { + return x.ContributionSignature + } + return nil +} + +type CeremonyAdvanceRound struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Commits []*CeremonyTranscriptCommit `protobuf:"bytes,1,rep,name=commits,proto3" json:"commits,omitempty"` +} + +func (x *CeremonyAdvanceRound) Reset() { + *x = CeremonyAdvanceRound{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyAdvanceRound) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyAdvanceRound) ProtoMessage() {} + +func (x *CeremonyAdvanceRound) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyAdvanceRound.ProtoReflect.Descriptor instead. +func (*CeremonyAdvanceRound) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{6} +} + +func (x *CeremonyAdvanceRound) GetCommits() []*CeremonyTranscriptCommit { + if x != nil { + return x.Commits + } + return nil +} + +type CeremonyLobbyJoin struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FrameNumber uint64 `protobuf:"varint,1,opt,name=frame_number,json=frameNumber,proto3" json:"frame_number,omitempty"` + IdentityKey *X448PublicKey `protobuf:"bytes,2,opt,name=identity_key,json=identityKey,proto3" json:"identity_key,omitempty"` + SignedPreKey *X448PublicKey `protobuf:"bytes,3,opt,name=signed_pre_key,json=signedPreKey,proto3" json:"signed_pre_key,omitempty"` + PublicKeySignatureEd448 *Ed448Signature `protobuf:"bytes,4,opt,name=public_key_signature_ed448,json=publicKeySignatureEd448,proto3" json:"public_key_signature_ed448,omitempty"` +} + +func (x *CeremonyLobbyJoin) Reset() { + *x = CeremonyLobbyJoin{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyLobbyJoin) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyLobbyJoin) ProtoMessage() {} + +func (x *CeremonyLobbyJoin) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyLobbyJoin.ProtoReflect.Descriptor instead. +func (*CeremonyLobbyJoin) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{7} +} + +func (x *CeremonyLobbyJoin) GetFrameNumber() uint64 { + if x != nil { + return x.FrameNumber + } + return 0 +} + +func (x *CeremonyLobbyJoin) GetIdentityKey() *X448PublicKey { + if x != nil { + return x.IdentityKey + } + return nil +} + +func (x *CeremonyLobbyJoin) GetSignedPreKey() *X448PublicKey { + if x != nil { + return x.SignedPreKey + } + return nil +} + +func (x *CeremonyLobbyJoin) GetPublicKeySignatureEd448() *Ed448Signature { + if x != nil { + return x.PublicKeySignatureEd448 + } + return nil +} + +type CeremonyLobbyStateTransition struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeUrls []string `protobuf:"bytes,1,rep,name=type_urls,json=typeUrls,proto3" json:"type_urls,omitempty"` + TransitionInputs [][]byte `protobuf:"bytes,2,rep,name=transition_inputs,json=transitionInputs,proto3" json:"transition_inputs,omitempty"` +} + +func (x *CeremonyLobbyStateTransition) Reset() { + *x = CeremonyLobbyStateTransition{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyLobbyStateTransition) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyLobbyStateTransition) ProtoMessage() {} + +func (x *CeremonyLobbyStateTransition) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyLobbyStateTransition.ProtoReflect.Descriptor instead. +func (*CeremonyLobbyStateTransition) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{8} +} + +func (x *CeremonyLobbyStateTransition) GetTypeUrls() []string { + if x != nil { + return x.TypeUrls + } + return nil +} + +func (x *CeremonyLobbyStateTransition) GetTransitionInputs() [][]byte { + if x != nil { + return x.TransitionInputs + } + return nil +} + +type CeremonyOpenState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + JoinedParticipants []*CeremonyLobbyJoin `protobuf:"bytes,1,rep,name=joined_participants,json=joinedParticipants,proto3" json:"joined_participants,omitempty"` + PreferredParticipants []*Ed448PublicKey `protobuf:"bytes,2,rep,name=preferred_participants,json=preferredParticipants,proto3" json:"preferred_participants,omitempty"` +} + +func (x *CeremonyOpenState) Reset() { + *x = CeremonyOpenState{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyOpenState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyOpenState) ProtoMessage() {} + +func (x *CeremonyOpenState) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyOpenState.ProtoReflect.Descriptor instead. +func (*CeremonyOpenState) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{9} +} + +func (x *CeremonyOpenState) GetJoinedParticipants() []*CeremonyLobbyJoin { + if x != nil { + return x.JoinedParticipants + } + return nil +} + +func (x *CeremonyOpenState) GetPreferredParticipants() []*Ed448PublicKey { + if x != nil { + return x.PreferredParticipants + } + return nil +} + +type CeremonyInProgressState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ActiveParticipants []*Ed448PublicKey `protobuf:"bytes,1,rep,name=active_participants,json=activeParticipants,proto3" json:"active_participants,omitempty"` + LatestSeenProverAttestations []*CeremonySeenProverAttestation `protobuf:"bytes,2,rep,name=latest_seen_prover_attestations,json=latestSeenProverAttestations,proto3" json:"latest_seen_prover_attestations,omitempty"` + DroppedParticipantAttestations []*CeremonyDroppedProverAttestation `protobuf:"bytes,3,rep,name=dropped_participant_attestations,json=droppedParticipantAttestations,proto3" json:"dropped_participant_attestations,omitempty"` + TranscriptRoundAdvanceCommits []*CeremonyAdvanceRound `protobuf:"bytes,4,rep,name=transcript_round_advance_commits,json=transcriptRoundAdvanceCommits,proto3" json:"transcript_round_advance_commits,omitempty"` + NextRoundParticipants []*Ed448PublicKey `protobuf:"bytes,5,rep,name=next_round_participants,json=nextRoundParticipants,proto3" json:"next_round_participants,omitempty"` +} + +func (x *CeremonyInProgressState) Reset() { + *x = CeremonyInProgressState{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyInProgressState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyInProgressState) ProtoMessage() {} + +func (x *CeremonyInProgressState) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyInProgressState.ProtoReflect.Descriptor instead. +func (*CeremonyInProgressState) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{10} +} + +func (x *CeremonyInProgressState) GetActiveParticipants() []*Ed448PublicKey { + if x != nil { + return x.ActiveParticipants + } + return nil +} + +func (x *CeremonyInProgressState) GetLatestSeenProverAttestations() []*CeremonySeenProverAttestation { + if x != nil { + return x.LatestSeenProverAttestations + } + return nil +} + +func (x *CeremonyInProgressState) GetDroppedParticipantAttestations() []*CeremonyDroppedProverAttestation { + if x != nil { + return x.DroppedParticipantAttestations + } + return nil +} + +func (x *CeremonyInProgressState) GetTranscriptRoundAdvanceCommits() []*CeremonyAdvanceRound { + if x != nil { + return x.TranscriptRoundAdvanceCommits + } + return nil +} + +func (x *CeremonyInProgressState) GetNextRoundParticipants() []*Ed448PublicKey { + if x != nil { + return x.NextRoundParticipants + } + return nil +} + +type CeremonyFinalizingState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ActiveParticipants []*Ed448PublicKey `protobuf:"bytes,1,rep,name=active_participants,json=activeParticipants,proto3" json:"active_participants,omitempty"` + LatestSeenProverAttestations []*CeremonySeenProverAttestation `protobuf:"bytes,2,rep,name=latest_seen_prover_attestations,json=latestSeenProverAttestations,proto3" json:"latest_seen_prover_attestations,omitempty"` + DroppedParticipantAttestations []*CeremonyDroppedProverAttestation `protobuf:"bytes,3,rep,name=dropped_participant_attestations,json=droppedParticipantAttestations,proto3" json:"dropped_participant_attestations,omitempty"` + Commits []*CeremonyTranscriptCommit `protobuf:"bytes,4,rep,name=commits,proto3" json:"commits,omitempty"` + Shares []*CeremonyTranscriptShare `protobuf:"bytes,5,rep,name=shares,proto3" json:"shares,omitempty"` + NextRoundParticipants []*Ed448PublicKey `protobuf:"bytes,6,rep,name=next_round_participants,json=nextRoundParticipants,proto3" json:"next_round_participants,omitempty"` +} + +func (x *CeremonyFinalizingState) Reset() { + *x = CeremonyFinalizingState{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyFinalizingState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyFinalizingState) ProtoMessage() {} + +func (x *CeremonyFinalizingState) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyFinalizingState.ProtoReflect.Descriptor instead. +func (*CeremonyFinalizingState) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{11} +} + +func (x *CeremonyFinalizingState) GetActiveParticipants() []*Ed448PublicKey { + if x != nil { + return x.ActiveParticipants + } + return nil +} + +func (x *CeremonyFinalizingState) GetLatestSeenProverAttestations() []*CeremonySeenProverAttestation { + if x != nil { + return x.LatestSeenProverAttestations + } + return nil +} + +func (x *CeremonyFinalizingState) GetDroppedParticipantAttestations() []*CeremonyDroppedProverAttestation { + if x != nil { + return x.DroppedParticipantAttestations + } + return nil +} + +func (x *CeremonyFinalizingState) GetCommits() []*CeremonyTranscriptCommit { + if x != nil { + return x.Commits + } + return nil +} + +func (x *CeremonyFinalizingState) GetShares() []*CeremonyTranscriptShare { + if x != nil { + return x.Shares + } + return nil +} + +func (x *CeremonyFinalizingState) GetNextRoundParticipants() []*Ed448PublicKey { + if x != nil { + return x.NextRoundParticipants + } + return nil +} + +type CeremonyValidatingState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Commits []*CeremonyTranscriptCommit `protobuf:"bytes,1,rep,name=commits,proto3" json:"commits,omitempty"` + UpdatedTranscript *CeremonyTranscript `protobuf:"bytes,2,opt,name=updated_transcript,json=updatedTranscript,proto3" json:"updated_transcript,omitempty"` + NextRoundParticipants []*Ed448PublicKey `protobuf:"bytes,3,rep,name=next_round_participants,json=nextRoundParticipants,proto3" json:"next_round_participants,omitempty"` +} + +func (x *CeremonyValidatingState) Reset() { + *x = CeremonyValidatingState{} + if protoimpl.UnsafeEnabled { + mi := &file_ceremony_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CeremonyValidatingState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CeremonyValidatingState) ProtoMessage() {} + +func (x *CeremonyValidatingState) ProtoReflect() protoreflect.Message { + mi := &file_ceremony_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CeremonyValidatingState.ProtoReflect.Descriptor instead. +func (*CeremonyValidatingState) Descriptor() ([]byte, []int) { + return file_ceremony_proto_rawDescGZIP(), []int{12} +} + +func (x *CeremonyValidatingState) GetCommits() []*CeremonyTranscriptCommit { + if x != nil { + return x.Commits + } + return nil +} + +func (x *CeremonyValidatingState) GetUpdatedTranscript() *CeremonyTranscript { + if x != nil { + return x.UpdatedTranscript + } + return nil +} + +func (x *CeremonyValidatingState) GetNextRoundParticipants() []*Ed448PublicKey { + if x != nil { + return x.NextRoundParticipants + } + return nil +} + var File_ceremony_proto protoreflect.FileDescriptor var file_ceremony_proto_rawDesc = []byte{ @@ -145,12 +1001,270 @@ var file_ceremony_proto_rawDesc = []byte{ 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x47, 0x32, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x12, 0x72, 0x75, 0x6e, 0x6e, - 0x69, 0x6e, 0x67, 0x47, 0x32, 0x32, 0x35, 0x36, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x42, 0x3a, - 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, - 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, - 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x69, 0x6e, 0x67, 0x47, 0x32, 0x32, 0x35, 0x36, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x22, 0x85, + 0x05, 0x0a, 0x12, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x4c, 0x6f, 0x62, 0x62, 0x79, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x62, 0x62, 0x79, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6c, 0x6f, 0x62, 0x62, + 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x60, 0x0a, 0x13, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, + 0x6e, 0x79, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, + 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x11, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x4f, + 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x73, 0x0a, 0x1a, 0x63, 0x65, 0x72, 0x65, + 0x6d, 0x6f, 0x6e, 0x79, 0x5f, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, + 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, + 0x6f, 0x6e, 0x79, 0x49, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x48, 0x00, 0x52, 0x17, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x49, 0x6e, + 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x72, 0x0a, + 0x19, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x5f, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, + 0x7a, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x34, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x69, 0x6e, + 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x17, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, + 0x6e, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x72, 0x0a, 0x19, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x5f, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, + 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x17, 0x63, 0x65, + 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x5c, 0x0a, 0x11, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x52, 0x10, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x74, 0x72, + 0x69, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, + 0x54, 0x72, 0x69, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xec, 0x01, 0x0a, 0x1d, 0x43, 0x65, 0x72, 0x65, 0x6d, + 0x6f, 0x6e, 0x79, 0x53, 0x65, 0x65, 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4f, 0x0a, 0x0f, 0x73, 0x65, 0x65, 0x6e, + 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, + 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x0d, 0x73, 0x65, 0x65, 0x6e, + 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x61, 0x73, + 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x46, 0x72, 0x61, 0x6d, + 0x65, 0x12, 0x52, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, + 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x20, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, + 0x6e, 0x79, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x41, + 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, 0x0a, 0x12, 0x64, 0x72, + 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, + 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, + 0x10, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x65, + 0x79, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x66, + 0x72, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6c, 0x61, 0x73, 0x74, + 0x53, 0x65, 0x65, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x52, 0x0a, 0x10, 0x70, 0x72, 0x6f, + 0x76, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, + 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0f, 0x70, 0x72, + 0x6f, 0x76, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xef, 0x03, + 0x0a, 0x17, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x53, 0x68, 0x61, 0x72, 0x65, 0x12, 0x5a, 0x0a, 0x12, 0x61, 0x64, 0x64, + 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x67, 0x31, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, + 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x47, 0x31, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x52, 0x10, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x76, 0x65, 0x47, 0x31, 0x50, + 0x6f, 0x77, 0x65, 0x72, 0x73, 0x12, 0x5a, 0x0a, 0x12, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x76, + 0x65, 0x5f, 0x67, 0x32, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, + 0x38, 0x35, 0x38, 0x31, 0x47, 0x32, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, + 0x10, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x76, 0x65, 0x47, 0x32, 0x50, 0x6f, 0x77, 0x65, 0x72, + 0x73, 0x12, 0x63, 0x0a, 0x17, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x67, 0x31, + 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x77, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, + 0x34, 0x38, 0x35, 0x38, 0x31, 0x47, 0x31, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x52, 0x14, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x76, 0x65, 0x47, 0x31, 0x32, 0x35, 0x36, 0x57, + 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x12, 0x63, 0x0a, 0x17, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x5f, 0x67, 0x32, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x77, 0x69, 0x74, 0x6e, 0x65, 0x73, + 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, + 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x47, 0x32, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x14, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x76, 0x65, 0x47, + 0x32, 0x32, 0x35, 0x36, 0x57, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x12, 0x52, 0x0a, 0x10, 0x70, + 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x0f, + 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, + 0xd1, 0x01, 0x0a, 0x18, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x52, 0x0a, 0x10, + 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, + 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, + 0x0f, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x12, 0x61, 0x0a, 0x16, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, + 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, + 0x35, 0x38, 0x31, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x15, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x22, 0x67, 0x0a, 0x14, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x41, + 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x4f, 0x0a, 0x07, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x71, + 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, + 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, + 0x6f, 0x6e, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x22, 0xb5, 0x02, 0x0a, + 0x11, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x4c, 0x6f, 0x62, 0x62, 0x79, 0x4a, 0x6f, + 0x69, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x4e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x49, 0x0a, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, + 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x58, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, + 0x12, 0x4c, 0x0a, 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x65, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, + 0x70, 0x62, 0x2e, 0x58, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, + 0x52, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x72, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x64, + 0x0a, 0x1a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x65, 0x64, 0x34, 0x34, 0x38, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, + 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, + 0x34, 0x38, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x17, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x45, + 0x64, 0x34, 0x34, 0x38, 0x22, 0x68, 0x0a, 0x1c, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, + 0x4c, 0x6f, 0x62, 0x62, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x75, 0x72, 0x6c, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x55, 0x72, 0x6c, + 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x22, 0xd4, + 0x01, 0x0a, 0x11, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x4f, 0x70, 0x65, 0x6e, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x5f, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x70, + 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2e, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, 0x62, 0x2e, + 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x4c, 0x6f, 0x62, 0x62, 0x79, 0x4a, 0x6f, 0x69, + 0x6e, 0x52, 0x12, 0x6a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, + 0x70, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x5e, 0x0a, 0x16, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, + 0x65, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x15, + 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, + 0x70, 0x61, 0x6e, 0x74, 0x73, 0x22, 0xde, 0x04, 0x0a, 0x17, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, + 0x6e, 0x79, 0x49, 0x6e, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x58, 0x0a, 0x13, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x74, + 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, + 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x12, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x50, + 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x81, 0x01, 0x0a, 0x1f, + 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x76, + 0x65, 0x72, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, + 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, + 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x53, 0x65, 0x65, 0x6e, + 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x1c, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x50, 0x72, 0x6f, + 0x76, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x87, 0x01, 0x0a, 0x20, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x74, + 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, + 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, + 0x79, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1e, 0x64, 0x72, 0x6f, 0x70, 0x70, + 0x65, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x7a, 0x0a, 0x20, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x61, 0x64, + 0x76, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, + 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x41, 0x64, 0x76, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x1d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x41, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x5f, 0x0a, 0x17, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x72, 0x6f, + 0x75, 0x6e, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, + 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, + 0x15, 0x6e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, + 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x22, 0x81, 0x05, 0x0a, 0x17, 0x43, 0x65, 0x72, 0x65, 0x6d, + 0x6f, 0x6e, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x58, 0x0a, 0x13, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72, + 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, + 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x12, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x81, 0x01, 0x0a, + 0x1f, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x70, 0x72, 0x6f, + 0x76, 0x65, 0x72, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, + 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, + 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x53, 0x65, 0x65, + 0x6e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x1c, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x50, 0x72, + 0x6f, 0x76, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x87, 0x01, 0x0a, 0x20, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x72, + 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, + 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, + 0x6e, 0x79, 0x44, 0x72, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x41, + 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1e, 0x64, 0x72, 0x6f, 0x70, + 0x70, 0x65, 0x64, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x41, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4f, 0x0a, 0x07, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, + 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, + 0x6e, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x4c, 0x0a, 0x06, 0x73, + 0x68, 0x61, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x71, 0x75, + 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, + 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, + 0x6e, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x68, 0x61, 0x72, + 0x65, 0x52, 0x06, 0x73, 0x68, 0x61, 0x72, 0x65, 0x73, 0x12, 0x5f, 0x0a, 0x17, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, + 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, + 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x52, 0x15, 0x6e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x61, + 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x22, 0xab, 0x02, 0x0a, 0x17, 0x43, + 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6e, + 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x4f, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, + 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, + 0x6e, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x07, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x5e, 0x0a, 0x12, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, + 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x63, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x2e, 0x70, + 0x62, 0x2e, 0x43, 0x65, 0x72, 0x65, 0x6d, 0x6f, 0x6e, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x52, 0x11, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x5f, 0x0a, 0x17, 0x6e, 0x65, 0x78, 0x74, 0x5f, + 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, + 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, + 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, + 0x70, 0x62, 0x2e, 0x45, 0x64, 0x34, 0x34, 0x38, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x52, 0x15, 0x6e, 0x65, 0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x61, 0x72, 0x74, + 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, 0x6f, 0x6e, + 0x6f, 0x72, 0x65, 0x70, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -165,22 +1279,74 @@ func file_ceremony_proto_rawDescGZIP() []byte { return file_ceremony_proto_rawDescData } -var file_ceremony_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_ceremony_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_ceremony_proto_goTypes = []interface{}{ - (*CeremonyTranscript)(nil), // 0: quilibrium.node.ceremony.pb.CeremonyTranscript - (*BLS48581G1PublicKey)(nil), // 1: quilibrium.node.keys.pb.BLS48581G1PublicKey - (*BLS48581G2PublicKey)(nil), // 2: quilibrium.node.keys.pb.BLS48581G2PublicKey + (*CeremonyTranscript)(nil), // 0: quilibrium.node.ceremony.pb.CeremonyTranscript + (*CeremonyLobbyState)(nil), // 1: quilibrium.node.ceremony.pb.CeremonyLobbyState + (*CeremonySeenProverAttestation)(nil), // 2: quilibrium.node.ceremony.pb.CeremonySeenProverAttestation + (*CeremonyDroppedProverAttestation)(nil), // 3: quilibrium.node.ceremony.pb.CeremonyDroppedProverAttestation + (*CeremonyTranscriptShare)(nil), // 4: quilibrium.node.ceremony.pb.CeremonyTranscriptShare + (*CeremonyTranscriptCommit)(nil), // 5: quilibrium.node.ceremony.pb.CeremonyTranscriptCommit + (*CeremonyAdvanceRound)(nil), // 6: quilibrium.node.ceremony.pb.CeremonyAdvanceRound + (*CeremonyLobbyJoin)(nil), // 7: quilibrium.node.ceremony.pb.CeremonyLobbyJoin + (*CeremonyLobbyStateTransition)(nil), // 8: quilibrium.node.ceremony.pb.CeremonyLobbyStateTransition + (*CeremonyOpenState)(nil), // 9: quilibrium.node.ceremony.pb.CeremonyOpenState + (*CeremonyInProgressState)(nil), // 10: quilibrium.node.ceremony.pb.CeremonyInProgressState + (*CeremonyFinalizingState)(nil), // 11: quilibrium.node.ceremony.pb.CeremonyFinalizingState + (*CeremonyValidatingState)(nil), // 12: quilibrium.node.ceremony.pb.CeremonyValidatingState + (*BLS48581G1PublicKey)(nil), // 13: quilibrium.node.keys.pb.BLS48581G1PublicKey + (*BLS48581G2PublicKey)(nil), // 14: quilibrium.node.keys.pb.BLS48581G2PublicKey + (*Ed448PublicKey)(nil), // 15: quilibrium.node.keys.pb.Ed448PublicKey + (*Ed448Signature)(nil), // 16: quilibrium.node.keys.pb.Ed448Signature + (*BLS48581Signature)(nil), // 17: quilibrium.node.keys.pb.BLS48581Signature + (*X448PublicKey)(nil), // 18: quilibrium.node.keys.pb.X448PublicKey } var file_ceremony_proto_depIdxs = []int32{ - 1, // 0: quilibrium.node.ceremony.pb.CeremonyTranscript.g1_powers:type_name -> quilibrium.node.keys.pb.BLS48581G1PublicKey - 2, // 1: quilibrium.node.ceremony.pb.CeremonyTranscript.g2_powers:type_name -> quilibrium.node.keys.pb.BLS48581G2PublicKey - 1, // 2: quilibrium.node.ceremony.pb.CeremonyTranscript.running_g1_256_witnesses:type_name -> quilibrium.node.keys.pb.BLS48581G1PublicKey - 2, // 3: quilibrium.node.ceremony.pb.CeremonyTranscript.running_g2_256_powers:type_name -> quilibrium.node.keys.pb.BLS48581G2PublicKey - 4, // [4:4] is the sub-list for method output_type - 4, // [4:4] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 13, // 0: quilibrium.node.ceremony.pb.CeremonyTranscript.g1_powers:type_name -> quilibrium.node.keys.pb.BLS48581G1PublicKey + 14, // 1: quilibrium.node.ceremony.pb.CeremonyTranscript.g2_powers:type_name -> quilibrium.node.keys.pb.BLS48581G2PublicKey + 13, // 2: quilibrium.node.ceremony.pb.CeremonyTranscript.running_g1_256_witnesses:type_name -> quilibrium.node.keys.pb.BLS48581G1PublicKey + 14, // 3: quilibrium.node.ceremony.pb.CeremonyTranscript.running_g2_256_powers:type_name -> quilibrium.node.keys.pb.BLS48581G2PublicKey + 9, // 4: quilibrium.node.ceremony.pb.CeremonyLobbyState.ceremony_open_state:type_name -> quilibrium.node.ceremony.pb.CeremonyOpenState + 10, // 5: quilibrium.node.ceremony.pb.CeremonyLobbyState.ceremony_in_progress_state:type_name -> quilibrium.node.ceremony.pb.CeremonyInProgressState + 11, // 6: quilibrium.node.ceremony.pb.CeremonyLobbyState.ceremony_finalizing_state:type_name -> quilibrium.node.ceremony.pb.CeremonyFinalizingState + 12, // 7: quilibrium.node.ceremony.pb.CeremonyLobbyState.ceremony_validating_state:type_name -> quilibrium.node.ceremony.pb.CeremonyValidatingState + 0, // 8: quilibrium.node.ceremony.pb.CeremonyLobbyState.latest_transcript:type_name -> quilibrium.node.ceremony.pb.CeremonyTranscript + 15, // 9: quilibrium.node.ceremony.pb.CeremonySeenProverAttestation.seen_prover_key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 16, // 10: quilibrium.node.ceremony.pb.CeremonySeenProverAttestation.prover_signature:type_name -> quilibrium.node.keys.pb.Ed448Signature + 15, // 11: quilibrium.node.ceremony.pb.CeremonyDroppedProverAttestation.dropped_prover_key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 16, // 12: quilibrium.node.ceremony.pb.CeremonyDroppedProverAttestation.prover_signature:type_name -> quilibrium.node.keys.pb.Ed448Signature + 13, // 13: quilibrium.node.ceremony.pb.CeremonyTranscriptShare.additive_g1_powers:type_name -> quilibrium.node.keys.pb.BLS48581G1PublicKey + 14, // 14: quilibrium.node.ceremony.pb.CeremonyTranscriptShare.additive_g2_powers:type_name -> quilibrium.node.keys.pb.BLS48581G2PublicKey + 13, // 15: quilibrium.node.ceremony.pb.CeremonyTranscriptShare.additive_g1_256_witness:type_name -> quilibrium.node.keys.pb.BLS48581G1PublicKey + 14, // 16: quilibrium.node.ceremony.pb.CeremonyTranscriptShare.additive_g2_256_witness:type_name -> quilibrium.node.keys.pb.BLS48581G2PublicKey + 16, // 17: quilibrium.node.ceremony.pb.CeremonyTranscriptShare.prover_signature:type_name -> quilibrium.node.keys.pb.Ed448Signature + 16, // 18: quilibrium.node.ceremony.pb.CeremonyTranscriptCommit.prover_signature:type_name -> quilibrium.node.keys.pb.Ed448Signature + 17, // 19: quilibrium.node.ceremony.pb.CeremonyTranscriptCommit.contribution_signature:type_name -> quilibrium.node.keys.pb.BLS48581Signature + 5, // 20: quilibrium.node.ceremony.pb.CeremonyAdvanceRound.commits:type_name -> quilibrium.node.ceremony.pb.CeremonyTranscriptCommit + 18, // 21: quilibrium.node.ceremony.pb.CeremonyLobbyJoin.identity_key:type_name -> quilibrium.node.keys.pb.X448PublicKey + 18, // 22: quilibrium.node.ceremony.pb.CeremonyLobbyJoin.signed_pre_key:type_name -> quilibrium.node.keys.pb.X448PublicKey + 16, // 23: quilibrium.node.ceremony.pb.CeremonyLobbyJoin.public_key_signature_ed448:type_name -> quilibrium.node.keys.pb.Ed448Signature + 7, // 24: quilibrium.node.ceremony.pb.CeremonyOpenState.joined_participants:type_name -> quilibrium.node.ceremony.pb.CeremonyLobbyJoin + 15, // 25: quilibrium.node.ceremony.pb.CeremonyOpenState.preferred_participants:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 15, // 26: quilibrium.node.ceremony.pb.CeremonyInProgressState.active_participants:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 2, // 27: quilibrium.node.ceremony.pb.CeremonyInProgressState.latest_seen_prover_attestations:type_name -> quilibrium.node.ceremony.pb.CeremonySeenProverAttestation + 3, // 28: quilibrium.node.ceremony.pb.CeremonyInProgressState.dropped_participant_attestations:type_name -> quilibrium.node.ceremony.pb.CeremonyDroppedProverAttestation + 6, // 29: quilibrium.node.ceremony.pb.CeremonyInProgressState.transcript_round_advance_commits:type_name -> quilibrium.node.ceremony.pb.CeremonyAdvanceRound + 15, // 30: quilibrium.node.ceremony.pb.CeremonyInProgressState.next_round_participants:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 15, // 31: quilibrium.node.ceremony.pb.CeremonyFinalizingState.active_participants:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 2, // 32: quilibrium.node.ceremony.pb.CeremonyFinalizingState.latest_seen_prover_attestations:type_name -> quilibrium.node.ceremony.pb.CeremonySeenProverAttestation + 3, // 33: quilibrium.node.ceremony.pb.CeremonyFinalizingState.dropped_participant_attestations:type_name -> quilibrium.node.ceremony.pb.CeremonyDroppedProverAttestation + 5, // 34: quilibrium.node.ceremony.pb.CeremonyFinalizingState.commits:type_name -> quilibrium.node.ceremony.pb.CeremonyTranscriptCommit + 4, // 35: quilibrium.node.ceremony.pb.CeremonyFinalizingState.shares:type_name -> quilibrium.node.ceremony.pb.CeremonyTranscriptShare + 15, // 36: quilibrium.node.ceremony.pb.CeremonyFinalizingState.next_round_participants:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 5, // 37: quilibrium.node.ceremony.pb.CeremonyValidatingState.commits:type_name -> quilibrium.node.ceremony.pb.CeremonyTranscriptCommit + 0, // 38: quilibrium.node.ceremony.pb.CeremonyValidatingState.updated_transcript:type_name -> quilibrium.node.ceremony.pb.CeremonyTranscript + 15, // 39: quilibrium.node.ceremony.pb.CeremonyValidatingState.next_round_participants:type_name -> quilibrium.node.keys.pb.Ed448PublicKey + 40, // [40:40] is the sub-list for method output_type + 40, // [40:40] is the sub-list for method input_type + 40, // [40:40] is the sub-list for extension type_name + 40, // [40:40] is the sub-list for extension extendee + 0, // [0:40] is the sub-list for field type_name } func init() { file_ceremony_proto_init() } @@ -202,6 +1368,156 @@ func file_ceremony_proto_init() { return nil } } + file_ceremony_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyLobbyState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonySeenProverAttestation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyDroppedProverAttestation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyTranscriptShare); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyTranscriptCommit); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyAdvanceRound); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyLobbyJoin); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyLobbyStateTransition); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyOpenState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyInProgressState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyFinalizingState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ceremony_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CeremonyValidatingState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_ceremony_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*CeremonyLobbyState_CeremonyOpenState)(nil), + (*CeremonyLobbyState_CeremonyInProgressState)(nil), + (*CeremonyLobbyState_CeremonyFinalizingState)(nil), + (*CeremonyLobbyState_CeremonyValidatingState)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -209,7 +1525,7 @@ func file_ceremony_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_ceremony_proto_rawDesc, NumEnums: 0, - NumMessages: 1, + NumMessages: 13, NumExtensions: 0, NumServices: 0, }, diff --git a/node/protobufs/ceremony.proto b/node/protobufs/ceremony.proto index 1b26f88..8876337 100644 --- a/node/protobufs/ceremony.proto +++ b/node/protobufs/ceremony.proto @@ -36,4 +36,91 @@ message CeremonyTranscript { // The running s^256 G2 powers – see notes on running_g1_256_witnesses for why // we do this. repeated quilibrium.node.keys.pb.BLS48581G2PublicKey running_g2_256_powers = 4; +} + +message CeremonyLobbyState { + int32 lobby_state = 1; + oneof ceremony_state { + CeremonyOpenState ceremony_open_state = 2; + CeremonyInProgressState ceremony_in_progress_state = 3; + CeremonyFinalizingState ceremony_finalizing_state = 4; + CeremonyValidatingState ceremony_validating_state = 5; + } + CeremonyTranscript latest_transcript = 6; + bytes reward_trie = 7; +} + +message CeremonySeenProverAttestation { + quilibrium.node.keys.pb.Ed448PublicKey seen_prover_key = 1; + uint64 last_seen_frame = 2; + quilibrium.node.keys.pb.Ed448Signature prover_signature = 3; +} + +message CeremonyDroppedProverAttestation { + quilibrium.node.keys.pb.Ed448PublicKey dropped_prover_key = 1; + uint64 last_seen_frame = 2; + quilibrium.node.keys.pb.Ed448Signature prover_signature = 3; +} + +message CeremonyTranscriptShare { + repeated quilibrium.node.keys.pb.BLS48581G1PublicKey additive_g1_powers = 1; + repeated quilibrium.node.keys.pb.BLS48581G2PublicKey additive_g2_powers = 2; + quilibrium.node.keys.pb.BLS48581G1PublicKey additive_g1_256_witness = 3; + quilibrium.node.keys.pb.BLS48581G2PublicKey additive_g2_256_witness = 4; + quilibrium.node.keys.pb.Ed448Signature prover_signature = 5; +} + +// Describes the required proof to commit to a transcript to advance a round, +// and as a proof to move to the verification state +message CeremonyTranscriptCommit { + // Prover key signature over the G1 point of the additive share of the first + // power. + quilibrium.node.keys.pb.Ed448Signature prover_signature = 1; + // BLS short signature over the Ed448 prover public key, using the additive + // share of the first power. + quilibrium.node.keys.pb.BLS48581Signature contribution_signature = 2; +} + +message CeremonyAdvanceRound { + repeated CeremonyTranscriptCommit commits = 1; +} + +message CeremonyLobbyJoin { + uint64 frame_number = 1; + quilibrium.node.keys.pb.X448PublicKey identity_key = 2; + quilibrium.node.keys.pb.X448PublicKey signed_pre_key = 3; + quilibrium.node.keys.pb.Ed448Signature public_key_signature_ed448 = 4; +} + +message CeremonyLobbyStateTransition { + repeated string type_urls = 1; + repeated bytes transition_inputs = 2; +} + +message CeremonyOpenState { + repeated CeremonyLobbyJoin joined_participants = 1; + repeated quilibrium.node.keys.pb.Ed448PublicKey preferred_participants = 2; +} + +message CeremonyInProgressState { + repeated quilibrium.node.keys.pb.Ed448PublicKey active_participants = 1; + repeated CeremonySeenProverAttestation latest_seen_prover_attestations = 2; + repeated CeremonyDroppedProverAttestation dropped_participant_attestations = 3; + repeated CeremonyAdvanceRound transcript_round_advance_commits = 4; + repeated quilibrium.node.keys.pb.Ed448PublicKey next_round_participants = 5; +} + +message CeremonyFinalizingState { + repeated quilibrium.node.keys.pb.Ed448PublicKey active_participants = 1; + repeated CeremonySeenProverAttestation latest_seen_prover_attestations = 2; + repeated CeremonyDroppedProverAttestation dropped_participant_attestations = 3; + repeated CeremonyTranscriptCommit commits = 4; + repeated CeremonyTranscriptShare shares = 5; + repeated quilibrium.node.keys.pb.Ed448PublicKey next_round_participants = 6; +} + +message CeremonyValidatingState { + repeated CeremonyTranscriptCommit commits = 1; + CeremonyTranscript updated_transcript = 2; + repeated quilibrium.node.keys.pb.Ed448PublicKey next_round_participants = 3; } \ No newline at end of file diff --git a/node/protobufs/clock.go b/node/protobufs/clock.go index f7e7a10..1bf62d9 100644 --- a/node/protobufs/clock.go +++ b/node/protobufs/clock.go @@ -1,15 +1,19 @@ package protobufs import ( + "crypto" + "crypto/rand" "encoding/binary" "math/big" "time" + "github.com/cloudflare/circl/sign/ed448" "github.com/iden3/go-iden3-crypto/ff" "github.com/iden3/go-iden3-crypto/poseidon" "github.com/pkg/errors" "golang.org/x/crypto/sha3" "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/vdf" + "source.quilibrium.com/quilibrium/monorepo/node/keys" ) func ProveMasterClockFrame( @@ -137,7 +141,7 @@ func (frame *ClockFrame) GetParentSelectorAndDistance() ( parentSelector := new(big.Int).SetBytes(frame.ParentSelector) - pubkey := []byte{} + var pubkey []byte ed448PublicKey := frame.GetPublicKeySignatureEd448() if ed448PublicKey != nil { pubkey = ed448PublicKey.PublicKey.KeyValue @@ -179,7 +183,7 @@ func (frame *ClockFrame) GetPublicKey() ([]byte, error) { if frame.FrameNumber == 0 { return make([]byte, 32), nil } - pubkey := []byte{} + var pubkey []byte ed448PublicKey := frame.GetPublicKeySignatureEd448() if ed448PublicKey != nil { pubkey = ed448PublicKey.PublicKey.KeyValue @@ -197,7 +201,7 @@ func (frame *ClockFrame) GetAddress() ([]byte, error) { if frame.FrameNumber == 0 { return make([]byte, 32), nil } - pubkey := []byte{} + var pubkey []byte ed448PublicKey := frame.GetPublicKeySignatureEd448() if ed448PublicKey != nil { pubkey = ed448PublicKey.PublicKey.KeyValue @@ -217,3 +221,196 @@ func (frame *ClockFrame) GetAddress() ([]byte, error) { return addressBytes, nil } + +func ProveDataClockFrame( + previousFrame *ClockFrame, + commitments [][]byte, + aggregateProofs []*InclusionAggregateProof, + provingKey crypto.Signer, + difficulty uint32, +) (*ClockFrame, error) { + var pubkey []byte + pubkeyType := keys.KeyTypeEd448 + ed448PublicKey, ok := provingKey.Public().(ed448.PublicKey) + if ok { + pubkey = []byte(ed448PublicKey) + } else { + return nil, errors.Wrap( + errors.New("no valid signature provided"), + "prove clock frame", + ) + } + + h, err := poseidon.HashBytes(pubkey) + if err != nil { + return nil, errors.Wrap( + errors.New("could not hash proving key"), + "prove clock frame", + ) + } + + address := h.Bytes() + timestamp := time.Now().UnixMilli() + input := []byte{} + input = append(input, previousFrame.Filter...) + input = binary.BigEndian.AppendUint64(input, previousFrame.FrameNumber+1) + input = binary.BigEndian.AppendUint64(input, uint64(timestamp)) + input = binary.BigEndian.AppendUint32(input, difficulty) + input = append(input, address...) + input = append(input, previousFrame.Output[:]...) + + commitmentInput := []byte{} + for _, commitment := range commitments { + commitmentInput = append(commitmentInput, commitment...) + } + + input = append(input, commitmentInput...) + + b := sha3.Sum256(input) + v := vdf.New(difficulty, b) + + v.Execute() + o := v.GetOutput() + + // TODO: make this configurable for signing algorithms that allow + // user-supplied hash functions + signature, err := provingKey.Sign( + rand.Reader, + append(append([]byte{}, b[:]...), o[:]...), + crypto.Hash(0), + ) + if err != nil { + return nil, errors.Wrap( + err, + "prove", + ) + } + + previousSelectorBytes := [516]byte{} + copy(previousSelectorBytes[:], previousFrame.Output[:516]) + + parent, err := poseidon.HashBytes(previousSelectorBytes[:]) + if err != nil { + return nil, errors.Wrap(err, "prove clock frame") + } + + frame := &ClockFrame{ + Filter: previousFrame.Filter, + FrameNumber: previousFrame.FrameNumber + 1, + Timestamp: timestamp, + Difficulty: difficulty, + ParentSelector: parent.Bytes(), + Input: append( + append([]byte{}, previousFrame.Output...), + commitmentInput..., + ), + AggregateProofs: aggregateProofs, + Output: o[:], + } + + switch pubkeyType { + case keys.KeyTypeEd448: + frame.PublicKeySignature = &ClockFrame_PublicKeySignatureEd448{ + PublicKeySignatureEd448: &Ed448Signature{ + Signature: signature, + PublicKey: &Ed448PublicKey{ + KeyValue: pubkey, + }, + }, + } + default: + return nil, errors.Wrap( + errors.New("unsupported proving key"), + "prove clock frame", + ) + } + + return frame, nil +} + +func (frame *ClockFrame) VerifyDataClockFrame() error { + var pubkey []byte + var signature []byte + pubkeyType := keys.KeyTypeEd448 + ed448PublicKey := frame.GetPublicKeySignatureEd448() + if ed448PublicKey != nil { + pubkey = ed448PublicKey.PublicKey.KeyValue + signature = ed448PublicKey.Signature + } else { + return errors.Wrap( + errors.New("no valid signature provided"), + "verify clock frame", + ) + } + + h, err := poseidon.HashBytes(pubkey) + if err != nil { + return errors.Wrap( + errors.New("could not hash proving key"), + "verify clock frame", + ) + } + + address := h.Bytes() + + input := []byte{} + input = append(input, frame.Filter...) + input = binary.BigEndian.AppendUint64(input, frame.FrameNumber) + input = binary.BigEndian.AppendUint64(input, uint64(frame.Timestamp)) + input = binary.BigEndian.AppendUint32(input, frame.Difficulty) + input = append(input, address...) + input = append(input, frame.Input...) + + if len(frame.Input) < 516 { + return errors.Wrap( + errors.New("invalid input"), + "verify clock frame", + ) + } + + b := sha3.Sum256(input) + v := vdf.New(frame.Difficulty, b) + proof := [516]byte{} + copy(proof[:], frame.Output) + + // TODO: make this configurable for signing algorithms that allow + // user-supplied hash functions + switch pubkeyType { + case keys.KeyTypeEd448: + if len(pubkey) != 57 || len(signature) != 114 || !ed448.VerifyAny( + pubkey, + append(append([]byte{}, b[:]...), frame.Output...), + signature, + crypto.Hash(0), + ) { + return errors.Wrap( + errors.New("invalid signature for issuer"), + "verify clock frame", + ) + } + } + if !v.Verify(proof) { + return errors.Wrap( + errors.New("invalid proof"), + "verify clock frame", + ) + } + + previousSelectorBytes := [516]byte{} + copy(previousSelectorBytes[:], frame.Input[:516]) + + parent, err := poseidon.HashBytes(previousSelectorBytes[:]) + if err != nil { + return errors.Wrap(err, "verify clock frame") + } + + selector := new(big.Int).SetBytes(frame.ParentSelector) + if parent.Cmp(selector) != 0 { + return errors.Wrap( + errors.New("selector did not match input"), + "verify clock frame", + ) + } + + return nil +} diff --git a/node/protobufs/keys.pb.go b/node/protobufs/keys.pb.go index 4e27e33..9c17b57 100644 --- a/node/protobufs/keys.pb.go +++ b/node/protobufs/keys.pb.go @@ -598,6 +598,62 @@ func (x *BLS48581G2PrivateKey) GetPublicKey() *BLS48581G2PublicKey { return nil } +// Describes a raw BLS48-581 signature, minimal signature size variant +type BLS48581Signature struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` // 74 byte value + PublicKey *BLS48581G2PublicKey `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` +} + +func (x *BLS48581Signature) Reset() { + *x = BLS48581Signature{} + if protoimpl.UnsafeEnabled { + mi := &file_keys_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BLS48581Signature) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BLS48581Signature) ProtoMessage() {} + +func (x *BLS48581Signature) ProtoReflect() protoreflect.Message { + mi := &file_keys_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BLS48581Signature.ProtoReflect.Descriptor instead. +func (*BLS48581Signature) Descriptor() ([]byte, []int) { + return file_keys_proto_rawDescGZIP(), []int{11} +} + +func (x *BLS48581Signature) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +func (x *BLS48581Signature) GetPublicKey() *BLS48581G2PublicKey { + if x != nil { + return x.PublicKey + } + return nil +} + var File_keys_proto protoreflect.FileDescriptor var file_keys_proto_rawDesc = []byte{ @@ -664,6 +720,14 @@ var file_keys_proto_rawDesc = []byte{ 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x47, 0x32, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, + 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x7e, 0x0a, 0x11, 0x42, 0x4c, + 0x53, 0x34, 0x38, 0x35, 0x38, 0x31, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x4b, 0x0a, + 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x4c, 0x53, 0x34, + 0x38, 0x35, 0x38, 0x31, 0x47, 0x32, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x3a, 0x5a, 0x38, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x69, 0x6c, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x6d, @@ -683,7 +747,7 @@ func file_keys_proto_rawDescGZIP() []byte { return file_keys_proto_rawDescData } -var file_keys_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_keys_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_keys_proto_goTypes = []interface{}{ (*Ed448PublicKey)(nil), // 0: quilibrium.node.keys.pb.Ed448PublicKey (*Ed448PrivateKey)(nil), // 1: quilibrium.node.keys.pb.Ed448PrivateKey @@ -696,6 +760,7 @@ var file_keys_proto_goTypes = []interface{}{ (*BLS48581G1PrivateKey)(nil), // 8: quilibrium.node.keys.pb.BLS48581G1PrivateKey (*BLS48581G2PublicKey)(nil), // 9: quilibrium.node.keys.pb.BLS48581G2PublicKey (*BLS48581G2PrivateKey)(nil), // 10: quilibrium.node.keys.pb.BLS48581G2PrivateKey + (*BLS48581Signature)(nil), // 11: quilibrium.node.keys.pb.BLS48581Signature } var file_keys_proto_depIdxs = []int32{ 0, // 0: quilibrium.node.keys.pb.Ed448PrivateKey.public_key:type_name -> quilibrium.node.keys.pb.Ed448PublicKey @@ -704,11 +769,12 @@ var file_keys_proto_depIdxs = []int32{ 5, // 3: quilibrium.node.keys.pb.PCASPrivateKey.public_key:type_name -> quilibrium.node.keys.pb.PCASPublicKey 7, // 4: quilibrium.node.keys.pb.BLS48581G1PrivateKey.public_key:type_name -> quilibrium.node.keys.pb.BLS48581G1PublicKey 9, // 5: quilibrium.node.keys.pb.BLS48581G2PrivateKey.public_key:type_name -> quilibrium.node.keys.pb.BLS48581G2PublicKey - 6, // [6:6] is the sub-list for method output_type - 6, // [6:6] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 9, // 6: quilibrium.node.keys.pb.BLS48581Signature.public_key:type_name -> quilibrium.node.keys.pb.BLS48581G2PublicKey + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_keys_proto_init() } @@ -849,6 +915,18 @@ func file_keys_proto_init() { return nil } } + file_keys_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BLS48581Signature); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -856,7 +934,7 @@ func file_keys_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_keys_proto_rawDesc, NumEnums: 0, - NumMessages: 11, + NumMessages: 12, NumExtensions: 0, NumServices: 0, }, diff --git a/node/protobufs/keys.proto b/node/protobufs/keys.proto index c511564..681430a 100644 --- a/node/protobufs/keys.proto +++ b/node/protobufs/keys.proto @@ -66,3 +66,9 @@ message BLS48581G2PrivateKey { bytes key_value = 1; // 73 byte value BLS48581G2PublicKey public_key = 2; } + +// Describes a raw BLS48-581 signature, minimal signature size variant +message BLS48581Signature { + bytes signature = 1; // 74 byte value + BLS48581G2PublicKey public_key = 2; +} \ No newline at end of file diff --git a/node/protobufs/protobufs.go b/node/protobufs/protobufs.go index cc56321..df5ad38 100644 --- a/node/protobufs/protobufs.go +++ b/node/protobufs/protobufs.go @@ -1,38 +1,51 @@ package protobufs const ( - TypeUrlPrefix = "types.quilibrium.com" - NamespacePrefix = TypeUrlPrefix + "/quilibrium.node." - AppPrefix = NamespacePrefix + "application.pb." - ChannelPrefix = NamespacePrefix + "channel.pb." - ClockPrefix = NamespacePrefix + "clock.pb." - KeysPrefix = NamespacePrefix + "keys.pb." - CeremonyPrefix = NamespacePrefix + "ceremony.pb." - CeremonyTranscriptType = CeremonyPrefix + "CeremonyTranscript" - ApplicationType = AppPrefix + "Application" - ExecutionContextType = AppPrefix + "ExecutionContext" - MessageType = AppPrefix + "Message" - P2PChannelEnvelopeType = ChannelPrefix + "P2PChannelEnvelope" - MessageCiphertextType = ChannelPrefix + "MessageCiphertext" - ProvingKeyAnnouncementType = ChannelPrefix + "ProvingKeyAnnouncement" - ProvingKeyRequestType = ChannelPrefix + "ProvingKeyRequest" - InclusionAggregateProofType = ChannelPrefix + "InclusionAggregateProof" - InclusionCommitmentType = ChannelPrefix + "InclusionCommitment" - KeyBundleAnnouncementType = ChannelPrefix + "KeyBundleAnnouncement" - IdentityKeyType = ChannelPrefix + "IdentityKey" - SignedPreKeyType = ChannelPrefix + "SignedPreKey" - ClockFrameType = ClockPrefix + "ClockFrame" - ClockFramesRequestType = ClockPrefix + "ClockFramesRequest" - ClockFramesResponseType = ClockPrefix + "ClockFramesResponse" - Ed448PublicKeyType = KeysPrefix + "Ed448PublicKey" - Ed448PrivateKeyType = KeysPrefix + "Ed448PrivateKey" - Ed448SignatureType = KeysPrefix + "Ed448Signature" - X448PublicKeyType = KeysPrefix + "X448PublicKey" - X448PrivateKeyType = KeysPrefix + "X448PrivateKey" - PCASPublicKeyType = KeysPrefix + "PCASPublicKey" - PCASPrivateKeyType = KeysPrefix + "PCASPrivateKey" - BLS48581G1PublicKeyType = KeysPrefix + "BLS48581G1PublicKey" - BLS48581G1PrivateKeyType = KeysPrefix + "BLS48581G1PrivateKey" - BLS48581G2PublicKeyType = KeysPrefix + "BLS48581G2PublicKey" - BLS48581G2PrivateKeyType = KeysPrefix + "BLS48581G2PrivateKey" + TypeUrlPrefix = "types.quilibrium.com" + NamespacePrefix = TypeUrlPrefix + "/quilibrium.node." + AppPrefix = NamespacePrefix + "application.pb." + ChannelPrefix = NamespacePrefix + "channel.pb." + ClockPrefix = NamespacePrefix + "clock.pb." + KeysPrefix = NamespacePrefix + "keys.pb." + CeremonyPrefix = NamespacePrefix + "ceremony.pb." + CeremonyTranscriptType = CeremonyPrefix + "CeremonyTranscript" + CeremonyLobbyStateType = CeremonyPrefix + "CeremonyLobbyState" + CeremonySeenProverAttestationType = CeremonyPrefix + "CeremonySeenProverAttestation" + CeremonyDroppedProverAttestationType = CeremonyPrefix + "CeremonyDroppedProverAttestation" + CeremonyTranscriptShareType = CeremonyPrefix + "CeremonyTranscriptShare" + CeremonyTranscriptCommitType = CeremonyPrefix + "CeremonyTranscriptCommit" + CeremonyAdvanceRoundType = CeremonyPrefix + "CeremonyAdvanceRound" + CeremonyLobbyJoinType = CeremonyPrefix + "CeremonyLobbyJoin" + CeremonyLobbyStateTransitionType = CeremonyPrefix + "CeremonyLobbyStateTransition" + CeremonyOpenStateType = CeremonyPrefix + "CeremonyOpenState" + CeremonyInProgressStateType = CeremonyPrefix + "CeremonyInProgressState" + CeremonyFinalizingStateType = CeremonyPrefix + "CeremonyFinalizingState" + CeremonyValidatingStateType = CeremonyPrefix + "CeremonyValidatingState" + ApplicationType = AppPrefix + "Application" + ExecutionContextType = AppPrefix + "ExecutionContext" + MessageType = AppPrefix + "Message" + IntrinsicExecutionOutputType = AppPrefix + "IntrinsicExecutionOutput" + P2PChannelEnvelopeType = ChannelPrefix + "P2PChannelEnvelope" + MessageCiphertextType = ChannelPrefix + "MessageCiphertext" + ProvingKeyAnnouncementType = ChannelPrefix + "ProvingKeyAnnouncement" + ProvingKeyRequestType = ChannelPrefix + "ProvingKeyRequest" + InclusionAggregateProofType = ChannelPrefix + "InclusionAggregateProof" + InclusionCommitmentType = ChannelPrefix + "InclusionCommitment" + KeyBundleAnnouncementType = ChannelPrefix + "KeyBundleAnnouncement" + IdentityKeyType = ChannelPrefix + "IdentityKey" + SignedPreKeyType = ChannelPrefix + "SignedPreKey" + ClockFrameType = ClockPrefix + "ClockFrame" + ClockFramesRequestType = ClockPrefix + "ClockFramesRequest" + ClockFramesResponseType = ClockPrefix + "ClockFramesResponse" + Ed448PublicKeyType = KeysPrefix + "Ed448PublicKey" + Ed448PrivateKeyType = KeysPrefix + "Ed448PrivateKey" + Ed448SignatureType = KeysPrefix + "Ed448Signature" + X448PublicKeyType = KeysPrefix + "X448PublicKey" + X448PrivateKeyType = KeysPrefix + "X448PrivateKey" + PCASPublicKeyType = KeysPrefix + "PCASPublicKey" + PCASPrivateKeyType = KeysPrefix + "PCASPrivateKey" + BLS48581G1PublicKeyType = KeysPrefix + "BLS48581G1PublicKey" + BLS48581G1PrivateKeyType = KeysPrefix + "BLS48581G1PrivateKey" + BLS48581G2PublicKeyType = KeysPrefix + "BLS48581G2PublicKey" + BLS48581G2PrivateKeyType = KeysPrefix + "BLS48581G2PrivateKey" ) diff --git a/node/store/clock.go b/node/store/clock.go index 2391fd1..4d77316 100644 --- a/node/store/clock.go +++ b/node/store/clock.go @@ -34,7 +34,7 @@ type ClockStore interface { GetDataClockFrame( filter []byte, frameNumber uint64, - ) (*protobufs.ClockFrame, error) + ) (*protobufs.ClockFrame, *tries.RollingFrecencyCritbitTrie, error) RangeDataClockFrames( filter []byte, startFrameNumber uint64, @@ -52,6 +52,10 @@ type ClockStore interface { frame *protobufs.ClockFrame, txn Transaction, ) error + GetCandidateDataClockFrames( + filter []byte, + frameNumber uint64, + ) ([]*protobufs.ClockFrame, error) GetParentDataClockFrame( filter []byte, frameNumber uint64, @@ -510,26 +514,39 @@ func (p *PebbleClockStore) PutMasterClockFrame( func (p *PebbleClockStore) GetDataClockFrame( filter []byte, frameNumber uint64, -) (*protobufs.ClockFrame, error) { +) (*protobufs.ClockFrame, *tries.RollingFrecencyCritbitTrie, error) { value, closer, err := p.db.Get(clockDataFrameKey(filter, frameNumber)) if err != nil { if errors.Is(err, pebble.ErrNotFound) { - return nil, ErrNotFound + return nil, nil, ErrNotFound } - return nil, errors.Wrap(err, "get data clock frame") + return nil, nil, errors.Wrap(err, "get data clock frame") } defer closer.Close() frame := &protobufs.ClockFrame{} if err := proto.Unmarshal(value, frame); err != nil { - return nil, errors.Wrap( + return nil, nil, errors.Wrap( errors.Wrap(err, ErrInvalidData.Error()), "get data clock frame", ) } - return frame, nil + proverTrie := &tries.RollingFrecencyCritbitTrie{} + + trieData, closer, err := p.db.Get(clockProverTrieKey(filter, frameNumber)) + if err != nil { + return nil, nil, errors.Wrap(err, "get latest data clock frame") + } + + defer closer.Close() + + if err := proverTrie.Deserialize(trieData); err != nil { + return nil, nil, errors.Wrap(err, "get latest data clock frame") + } + + return frame, proverTrie, nil } // GetEarliestDataClockFrame implements ClockStore. @@ -547,7 +564,7 @@ func (p *PebbleClockStore) GetEarliestDataClockFrame( defer closer.Close() frameNumber := binary.BigEndian.Uint64(idxValue) - frame, err := p.GetDataClockFrame(filter, frameNumber) + frame, _, err := p.GetDataClockFrame(filter, frameNumber) if err != nil { return nil, errors.Wrap(err, "get earliest data clock frame") } @@ -570,7 +587,7 @@ func (p *PebbleClockStore) GetLatestDataClockFrame( } frameNumber := binary.BigEndian.Uint64(idxValue) - frame, err := p.GetDataClockFrame(filter, frameNumber) + frame, _, err := p.GetDataClockFrame(filter, frameNumber) if err != nil { return nil, errors.Wrap(err, "get latest data clock frame") } @@ -743,6 +760,66 @@ func (p *PebbleClockStore) PutDataClockFrame( return nil } +// GetCandidateDataClockFrames implements ClockStore. +// Distance is 32-byte aligned, so we just use a 0x00 * 32 -> 0xff * 32 range +func (p *PebbleClockStore) GetCandidateDataClockFrames( + filter []byte, + frameNumber uint64, +) ([]*protobufs.ClockFrame, error) { + iter := p.db.NewIter(&pebble.IterOptions{ + LowerBound: clockDataCandidateFrameKey( + filter, + frameNumber, + []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + ), + UpperBound: clockDataCandidateFrameKey( + filter, + frameNumber, + []byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + []byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + ), + }) + + frames := []*protobufs.ClockFrame{} + i := &PebbleCandidateClockIterator{i: iter} + + for i.First(); i.Valid(); i.Next() { + value, err := i.Value() + if err != nil { + return nil, errors.Wrap(err, "get candidate data clock frames") + } + + frames = append(frames, value) + } + + if err := i.Close(); err != nil { + return nil, errors.Wrap(err, "get candidate data clock frames") + } + + return frames, nil +} + // RangeCandidateDataClockFrames implements ClockStore. // Distance is 32-byte aligned, so we just use a 0x00 * 32 -> 0xff * 32 range func (p *PebbleClockStore) RangeCandidateDataClockFrames( diff --git a/node/tries/reward_critbit_trie.go b/node/tries/reward_critbit_trie.go new file mode 100644 index 0000000..a418f8e --- /dev/null +++ b/node/tries/reward_critbit_trie.go @@ -0,0 +1,301 @@ +package tries + +import ( + "bytes" + "encoding/gob" + "encoding/hex" + "strings" + "sync" + + "github.com/pkg/errors" +) + +type RewardNode struct { + Internal *RewardInternalNode + External *RewardExternalNode +} + +type RewardInternalNode struct { + Child [2]RewardNode + ByteNumber uint32 + Bits byte +} + +type RewardExternalNode struct { + Key []byte + EarliestFrame uint64 + LatestFrame uint64 + Total uint64 +} + +type RewardCritbitTrie struct { + Root *RewardNode + mu sync.RWMutex +} + +func (t *RewardCritbitTrie) Serialize() ([]byte, error) { + t.mu.RLock() + defer t.mu.RUnlock() + + var b bytes.Buffer + enc := gob.NewEncoder(&b) + + if err := enc.Encode(t.Root); err != nil { + return nil, errors.Wrap(err, "serialize") + } + + return b.Bytes(), nil +} + +func (t *RewardCritbitTrie) Deserialize(buf []byte) error { + t.mu.Lock() + defer t.mu.Unlock() + + var b bytes.Buffer + b.Write(buf) + dec := gob.NewDecoder(&b) + + if err := dec.Decode(&t.Root); err != nil { + return errors.Wrap(err, "deserialize") + } + + return nil +} + +func (t *RewardCritbitTrie) Contains(address []byte) bool { + t.mu.RLock() + defer t.mu.RUnlock() + p := t.findNearest(address) + return p != nil && + p.External != nil && + bytes.Equal(p.External.Key, address) +} + +func (t *RewardCritbitTrie) Get( + address []byte, +) (earliestFrame uint64, latestFrame uint64, total uint64) { + t.mu.RLock() + defer t.mu.RUnlock() + p := t.findNearest(address) + + if p != nil && + p.External != nil && + bytes.Equal(p.External.Key, address) { + return p.External.EarliestFrame, p.External.LatestFrame, p.External.Total + } + + return 0, 0, 0 +} + +func (t *RewardCritbitTrie) findNearest( + address []byte, +) *RewardNode { + blen := uint32(len(address)) + p := t.Root + + if p == nil { + return nil + } + + for p.Internal != nil { + right := p.Internal.ByteNumber < blen && + address[p.Internal.ByteNumber]&p.Internal.Bits != 0 + if right { + p = &p.Internal.Child[1] + } else { + p = &p.Internal.Child[0] + } + } + + return p +} + +func (t *RewardCritbitTrie) Add( + address []byte, + latestFrame uint64, + reward uint64, +) { + t.mu.Lock() + defer t.mu.Unlock() + if t.Root == nil { + t.Root = &RewardNode{ + External: &RewardExternalNode{ + Key: address, + EarliestFrame: latestFrame, + LatestFrame: latestFrame, + Total: reward, + }, + } + return + } + + p := t.findNearest(address) + byteNumber, bits := p.critBit(address) + if byteNumber < 0 { + if p.External.LatestFrame < latestFrame { + p.External.LatestFrame = latestFrame + } + if p.External.EarliestFrame > latestFrame { + p.External.EarliestFrame = latestFrame + } + p.External.Total += reward + return + } + + node := &RewardInternalNode{ + ByteNumber: uint32(byteNumber), + Bits: bits, + } + + blen := uint32(len(address)) + right := node.ByteNumber < blen && + address[node.ByteNumber]&node.Bits != 0 + e := &RewardExternalNode{ + Key: address, + EarliestFrame: latestFrame, + LatestFrame: latestFrame, + Total: reward, + } + if right { + node.Child[1].External = e + } else { + node.Child[0].External = e + } + + p = t.Root + for m := p.Internal; m != nil; m = p.Internal { + if m.ByteNumber > uint32(byteNumber) || + m.ByteNumber == uint32(byteNumber) && m.Bits < bits { + break + } + + if m.ByteNumber < blen && address[m.ByteNumber]&m.Bits != 0 { + p = &m.Child[1] + } else { + p = &m.Child[0] + } + } + + if p.Internal != nil { + // inverse the direction + if right { + node.Child[0].Internal = p.Internal + } else { + node.Child[1].Internal = p.Internal + } + } else { + if right { + node.Child[0].External = p.External + } else { + node.Child[1].External = p.External + p.External = nil + } + } + + p.Internal = node +} + +func (t *RewardCritbitTrie) Remove(address []byte) { + t.mu.Lock() + defer t.mu.Unlock() + + if t.Root == nil { + return + } + + blen := uint32(len(address)) + var gp *RewardNode + p := t.Root + var right bool + + for m := p.Internal; m != nil; m = p.Internal { + right = p.Internal.ByteNumber < blen && + address[p.Internal.ByteNumber]&p.Internal.Bits != 0 + if right { + gp, p = p, &m.Child[1] + } else { + gp, p = p, &m.Child[0] + } + } + + if !bytes.Equal(p.External.Key, address) { + return + } + + if gp == nil { + p.External = nil + } else { + if right { + gp.External, gp.Internal = gp.Internal.Child[0].External, + gp.Internal.Child[0].Internal + } else { + gp.External, gp.Internal = gp.Internal.Child[1].External, + gp.Internal.Child[1].Internal + } + } +} + +func (n *RewardNode) String() string { + if n.External != nil { + return hex.EncodeToString(n.External.Key) + } else { + nodes := []string{} + for i := range n.Internal.Child { + nodes = append(nodes, n.Internal.Child[i].String()) + } + return strings.Join(nodes, ",") + } +} + +func (n *RewardNode) Bits() []byte { + if n.External != nil { + return n.External.Key + } else { + return nil + } +} + +func (n *RewardNode) Info() (latestFrame uint64, total uint64) { + if n.External != nil { + return n.External.LatestFrame, n.External.Total + } else { + return 0, 0 + } +} + +func (n *RewardNode) critBit( + address []byte, +) (byteNumber int, bits byte) { + smallestLen := len(n.External.Key) + if len(address) < smallestLen { + smallestLen = len(address) + } + + for byteNumber = 0; byteNumber < smallestLen; byteNumber++ { + if l, r := address[byteNumber], n.External.Key[byteNumber]; l != r { + b := l ^ r + b |= b >> 1 + b |= b >> 2 + b |= b >> 4 + bits = b &^ (b >> 1) + return + } + } + + if len(n.External.Key) < len(address) { + b := address[byteNumber] + b |= b >> 1 + b |= b >> 2 + b |= b >> 4 + bits = b &^ (b >> 1) + } else if len(n.External.Key) > len(address) { + b := n.External.Key[byteNumber] + b |= b >> 1 + b |= b >> 2 + b |= b >> 4 + bits = b &^ (b >> 1) + } else { + byteNumber = -1 + } + return +}