From cf2698c62e2f95d66382d956af4ecd0e3d180bd3 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Tue, 4 Apr 2023 16:40:32 +0200 Subject: [PATCH 01/34] structural change so DKG can accept reencryption commands --- dkg/dkg.go | 1 + dkg/pedersen/controller/action.go | 71 +++++++++++++++++++++++++-- dkg/pedersen/controller/controller.go | 14 ++++++ dkg/pedersen/pedersen.go | 25 ++++++++++ 4 files changed, 108 insertions(+), 3 deletions(-) diff --git a/dkg/dkg.go b/dkg/dkg.go index 141286a98..6f4c80857 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -26,6 +26,7 @@ type Actor interface { Encrypt(message []byte) (K, C kyber.Point, remainder []byte, err error) Decrypt(K, C kyber.Point) ([]byte, error) + EncryptWithPublicKey(message []byte, pk kyber.Point) (K, C kyber.Point, remainder []byte, err error) Reshare(co crypto.CollectiveAuthority, newThreshold int) error diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index b0b62aedd..3e7278653 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -81,14 +81,14 @@ type listenAction struct { } func (a listenAction) Execute(ctx node.Context) error { - var dkg dkg.DKG + var d dkg.DKG - err := ctx.Injector.Resolve(&dkg) + err := ctx.Injector.Resolve(&d) if err != nil { return xerrors.Errorf("failed to resolve dkg: %v", err) } - actor, err := dkg.Listen() + actor, err := d.Listen() if err != nil { return xerrors.Errorf("failed to listen: %v", err) } @@ -230,6 +230,71 @@ func (a decryptAction) Execute(ctx node.Context) error { return nil } +type reencryptAction struct{} + +func (a reencryptAction) Execute(ctx node.Context) error { + var actor dkg.Actor + + err := ctx.Injector.Resolve(&actor) + if err != nil { + return xerrors.Errorf(resolveActorFailed, err) + } + + // first, let's decrypt the given data + encrypted := ctx.Flags.String("encrypted") + + k, c, err := decodeEncrypted(encrypted) + if err != nil { + return xerrors.Errorf("failed to decode encrypted str: %v", err) + } + + decrypted, err := actor.Decrypt(k, c) + if err != nil { + return xerrors.Errorf("failed to decrypt: %v", err) + } + + fmt.Fprint(ctx.Out, hex.EncodeToString(decrypted)) + + // second, let's encrypt 'decrypted' with the given public key + publickey := ctx.Flags.String("publickey") + + pk, err := decodePublickey(publickey) + if err != nil { + return xerrors.Errorf("failed to decode public key str: %v", err) + } + + k, c, remainder, err := actor.EncryptWithPublicKey(decrypted, pk) + if err != nil { + return xerrors.Errorf("failed to reencrypt: %v", err) + } + + outStr, err := encodeEncrypted(k, c, remainder) + if err != nil { + return xerrors.Errorf("failed to generate output: %v", err) + } + + fmt.Fprint(ctx.Out, outStr) + + return nil +} + +func decodePublickey(str string) (pk kyber.Point, err error) { + // Decode public key + publickey, err := hex.DecodeString(str) + if err != nil { + return nil, xerrors.Errorf("failed to decode pk: %v", err) + } + + pk = suite.Point() + + err = pk.UnmarshalBinary(publickey) + if err != nil { + return nil, xerrors.Errorf("failed to unmarshal pk point: %v", err) + } + + return pk, nil +} + func encodeEncrypted(k, c kyber.Point, remainder []byte) (string, error) { kbuff, err := k.MarshalBinary() if err != nil { diff --git a/dkg/pedersen/controller/controller.go b/dkg/pedersen/controller/controller.go index c23897e27..65febdd02 100644 --- a/dkg/pedersen/controller/controller.go +++ b/dkg/pedersen/controller/controller.go @@ -67,6 +67,20 @@ func (m minimal) SetCommands(builder node.Builder) { ) sub.SetAction(builder.MakeAction(decryptAction{})) + sub = cmd.SetSubCommand("reencrypt") + sub.SetDescription("reencrypt a message") + sub.SetFlags( + cli.StringFlag{ + Name: "encrypted", + Usage: "the encrypted string, as :", + }, + cli.StringFlag{ + Name: "publickey", + Usage: "the new public key to reencrypt the message, as ", + }, + ) + sub.SetAction(builder.MakeAction(reencryptAction{})) + sub = cmd.SetSubCommand("verifiableEncrypt") sub.SetDescription("encrypt a message and provides a proof. " + "Outputs :::::") diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index c8d3142ef..1a17d68dc 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -212,6 +212,31 @@ func (a *Actor) Encrypt(message []byte) (K, C kyber.Point, remainder []byte, return K, C, remainder, nil } +// EncryptWithPublicKey implements dkg.Actor. It uses the given public key +// to encrypt a message. +func (a *Actor) EncryptWithPublicKey(message []byte, pk kyber.Point) (K, C kyber.Point, remainder []byte, err error) { + if !a.startRes.Done() { + return nil, nil, nil, xerrors.Errorf(initDkgFirst) + } + + // Embed the message (or as much of it as will fit) into a curve point. + M := suite.Point().Embed(message, random.New()) + max := suite.Point().EmbedLen() + if max > len(message) { + max = len(message) + } + remainder = message[max:] + + //TODO: make calculate re-encryption correctly + // ElGamal-encrypt the point to produce ciphertext (K,C). + k := suite.Scalar().Pick(random.New()) // ephemeral private key + K = suite.Point().Mul(k, nil) // ephemeral DH public key + S := suite.Point().Mul(k, pk) // ephemeral DH shared secret + C = S.Add(S, M) // message blinded with secret + + return K, C, remainder, nil +} + // VerifiableEncrypt implements dkg.Actor. It uses the DKG public key to encrypt // a message and provide a zero knowledge proof that the encryption is done by // this person. From 5c1580746ae6c1343f08a39b5aebb1ab7f2f96b0 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 12 Apr 2023 15:02:54 +0200 Subject: [PATCH 02/34] attempt to tidy up the encryption code with the help of OCS --- dkg/dkg.go | 2 +- dkg/pedersen/controller/action.go | 12 +-- dkg/pedersen/dkg.go | 68 +++++++++++++++++ dkg/pedersen/pedersen.go | 119 +++++++++++++++++++++++++++++- dkg/pedersen/types/messages.go | 62 ++++++++++++++++ 5 files changed, 248 insertions(+), 15 deletions(-) diff --git a/dkg/dkg.go b/dkg/dkg.go index 6f4c80857..1c120d76f 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -26,7 +26,7 @@ type Actor interface { Encrypt(message []byte) (K, C kyber.Point, remainder []byte, err error) Decrypt(K, C kyber.Point) ([]byte, error) - EncryptWithPublicKey(message []byte, pk kyber.Point) (K, C kyber.Point, remainder []byte, err error) + Reencrypt(k, c, pk kyber.Point) (K, C kyber.Point, remainder []byte, err error) Reshare(co crypto.CollectiveAuthority, newThreshold int) error diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index 3e7278653..bb8f752b8 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -240,7 +240,7 @@ func (a reencryptAction) Execute(ctx node.Context) error { return xerrors.Errorf(resolveActorFailed, err) } - // first, let's decrypt the given data + // first, let's reencrypt the given data encrypted := ctx.Flags.String("encrypted") k, c, err := decodeEncrypted(encrypted) @@ -248,14 +248,6 @@ func (a reencryptAction) Execute(ctx node.Context) error { return xerrors.Errorf("failed to decode encrypted str: %v", err) } - decrypted, err := actor.Decrypt(k, c) - if err != nil { - return xerrors.Errorf("failed to decrypt: %v", err) - } - - fmt.Fprint(ctx.Out, hex.EncodeToString(decrypted)) - - // second, let's encrypt 'decrypted' with the given public key publickey := ctx.Flags.String("publickey") pk, err := decodePublickey(publickey) @@ -263,7 +255,7 @@ func (a reencryptAction) Execute(ctx node.Context) error { return xerrors.Errorf("failed to decode public key str: %v", err) } - k, c, remainder, err := actor.EncryptWithPublicKey(decrypted, pk) + k, c, remainder, err := actor.Reencrypt(k, c, pk) if err != nil { return xerrors.Errorf("failed to reencrypt: %v", err) } diff --git a/dkg/pedersen/dkg.go b/dkg/pedersen/dkg.go index 3902a3eb2..37646a238 100644 --- a/dkg/pedersen/dkg.go +++ b/dkg/pedersen/dkg.go @@ -2,6 +2,7 @@ package pedersen import ( "context" + "crypto/sha256" "strconv" "sync" @@ -174,6 +175,22 @@ func (s *instance) handleMessage(ctx context.Context, msg serde.Message, from mi return s.handleVerifiableDecrypt(out, msg, from) + case types.ReencryptRequest: + err := s.startRes.checkState(certified) + if err != nil { + return xerrors.Errorf(badState, err) + } + + return s.handleReencryptRequest(out, msg, from) + + case types.ReencryptReply: + err := s.startRes.checkState(certified) + if err != nil { + return xerrors.Errorf(badState, err) + } + + return s.handleReencryptReply(out, msg, from) + default: return xerrors.Errorf("expected Start message, decrypt request or "+ "Deal as first message, got: %T", msg) @@ -789,6 +806,57 @@ func (s *instance) handleDecrypt(out mino.Sender, msg types.DecryptRequest, return nil } +func (s *instance) handleReencryptRequest(out mino.Sender, msg types.ReencryptRequest, + from mino.Address) error { + + if !s.startRes.Done() { + return xerrors.Errorf("you must first initialize DKG. Did you call setup() first?") + } + + ui := s.getUI(msg.U, msg.Pk) + + // Calculating proofs + si := suite.Scalar().Pick(suite().RandomStream()) + uiHat := suite.Point().Mul(si, suite.Point().Add(msg.U, msg.Pk)) + hiHat := suite.Point().Mul(si, nil) + hash := sha256.New() + ui.V.MarshalTo(hash) + uiHat.MarshalTo(hash) + hiHat.MarshalTo(hash) + ei := suite.Scalar().SetBytes(hash.Sum(nil)) + fi := suite.Scalar().Add(si, suite.Scalar().Mul(ei, s.privShare.V)) + + response := types.NewReencryptReply(ui, ei, fi) + + errs := out.Send(response, from) + err := <-errs + if err != nil { + return xerrors.Errorf("got an error while sending the decrypt reply: %v", err) + } + + return nil +} + +func (s *instance) getUI(U, Xc kyber.Point) *share.PubShare { + v := suite.Point().Mul(s.privShare.V, U) + v.Add(v, suite.Point().Mul(s.privShare.V, Xc)) + return &share.PubShare{ + I: s.privShare.I, + V: v, + } +} + +func (s *instance) handleReencryptReply(out mino.Sender, msg types.ReencryptReply, + from mino.Address) error { + + if !s.startRes.Done() { + return xerrors.Errorf("you must first initialize DKG. Did you call setup() first?") + } + + //TODO: to be continued... + return nil +} + func (s *instance) handleVerifiableDecrypt(out mino.Sender, msg types.VerifiableDecryptRequest, from mino.Address) error { diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 1a17d68dc..c89f1f30d 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -43,6 +43,9 @@ var ( // protocolNameDecrypt denotes the value of the protocol span tag // associated with the `dkg-decrypt` protocol. protocolNameDecrypt = "dkg-decrypt" + // protocolNameReencrypt denotes the value of the protocol span tag + // associated with the `dkg-reencrypt` protocol. + protocolNameReencrypt = "dkg-reencrypt" // ProtocolNameResharing denotes the value of the protocol span tag // associated with the `dkg-resharing` protocol. protocolNameResharing = "dkg-resharing" @@ -53,6 +56,7 @@ var ( const ( setupTimeout = time.Minute * 50 decryptTimeout = time.Minute * 5 + reencryptTimeout = time.Minute * 5 resharingTimeout = time.Minute * 5 ) @@ -212,6 +216,114 @@ func (a *Actor) Encrypt(message []byte) (K, C kyber.Point, remainder []byte, return K, C, remainder, nil } +// Reencrypt implements dkg.Actor. It uses the given public key +// to reencrypt an encrypted message. +func (a *Actor) Reencrypt(k, c, pk kyber.Point) (K, C kyber.Point, remainder []byte, err error) { + if !a.startRes.Done() { + return nil, nil, []byte{}, xerrors.Errorf(initDkgFirst) + } + + ctx, cancel := context.WithTimeout(context.Background(), reencryptTimeout) + defer cancel() + ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameReencrypt) + + players := mino.NewAddresses(a.startRes.getParticipants()...) + + sender, receiver, err := a.rpc.Stream(ctx, players) + if err != nil { + return nil, nil, []byte{}, xerrors.Errorf(failedStreamCreation, err) + } + + iterator := players.AddressIterator() + addrs := make([]mino.Address, 0, players.Len()) + + for iterator.HasNext() { + addrs = append(addrs, iterator.GetNext()) + } + + //TODO: how to calculate (k, pk) in place of (U, Xc) ? + // seems correct, as in: + // type OCS struct { + // *onet.TreeNodeInstance + // Shared *dkgprotocol.SharedSecret // Shared represents the private key + // Poly *share.PubPoly // Represents all public keys + // U kyber.Point // U is the encrypted secret + // Xc kyber.Point // The client's public key + // Threshold int // How many replies are needed to re-create the secret + message := types.NewReencryptRequest(k, pk) + + err = <-sender.Send(message, addrs...) + if err != nil { + return nil, nil, []byte{}, xerrors.Errorf("failed to send decrypt request: %v", err) + } + + pubShares := make([]*share.PubShare, len(addrs)) + U := k + Xc := pk + pubShares[0] = a.getUI(k, pk) // TODO: verify that this getUI(U, Xc) call is correct + + for i := 0; i < len(addrs); i++ { + src, message, err := receiver.Recv(ctx) + if err != nil && i < a.startRes.threshold { + return nil, nil, []byte{}, xerrors.Errorf(unexpectedStreamStop, err) + } + + dela.Logger.Debug().Msgf("Received a reencryption reply from %v", src) + + r, ok := message.(types.ReencryptReply) + if !ok { + return nil, nil, []byte{}, xerrors.Errorf("got unexpected reply, expected "+ + "%T but got: %T", r, message) + } + + // Verify proofs + ufi := suite.Point().Mul(r.Fi, suite.Point().Add(U, Xc)) + uiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), r.Ui.V) + uiHat := suite.Point().Add(ufi, uiei) + + gfi := suite.Point().Mul(r.Fi, nil) + gxi := Poly.Eval(r.Ui.I).V //TODO: Poly *share.PubPoly // Represents all public keys + hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) + hiHat := suite.Point().Add(gfi, hiei) + hash := sha256.New() + r.Ui.V.MarshalTo(hash) + uiHat.MarshalTo(hash) + hiHat.MarshalTo(hash) + + e := suite.Scalar().SetBytes(hash.Sum(nil)) + if e.Equal(r.Ei) { + pubShares[r.Ui.I] = r.Ui + } else { + dela.Logger.Warn().Msgf("Received invalid share from node", r.Ui.I) + } + } + + res, err := share.RecoverCommit(suite, pubShares, len(addrs), len(addrs)) + if err != nil { + return nil, nil, []byte{}, xerrors.Errorf("failed to recover commit: %v", err) + } + + decryptedMessage, err := res.Data() + if err != nil { + return nil, nil, []byte{}, xerrors.Errorf("failed to get embedded data: %v", err) + } + + dela.Logger.Info().Msgf("Decrypted message: %v", decryptedMessage) + + // return new encrypted message, nil + return K, C, remainder, nil +} + +// TODO: not where to get this UI ? +func (a *Actor) getUI(U, Xc kyber.Point) *share.PubShare { + v := suite.Point().Mul(s.privShare.V, U) + v.Add(v, suite.Point().Mul(s.privShare.V, Xc)) + return &share.PubShare{ + I: s.privShare.I, + V: v, + } +} + // EncryptWithPublicKey implements dkg.Actor. It uses the given public key // to encrypt a message. func (a *Actor) EncryptWithPublicKey(message []byte, pk kyber.Point) (K, C kyber.Point, remainder []byte, err error) { @@ -302,21 +414,20 @@ func (a *Actor) Decrypt(K, C kyber.Point) ([]byte, error) { return nil, xerrors.Errorf(initDkgFirst) } - players := mino.NewAddresses(a.startRes.getParticipants()...) - ctx, cancel := context.WithTimeout(context.Background(), decryptTimeout) defer cancel() ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameDecrypt) + players := mino.NewAddresses(a.startRes.getParticipants()...) + sender, receiver, err := a.rpc.Stream(ctx, players) if err != nil { return nil, xerrors.Errorf(failedStreamCreation, err) } - players = mino.NewAddresses(a.startRes.getParticipants()...) iterator := players.AddressIterator() - addrs := make([]mino.Address, 0, players.Len()) + for iterator.HasNext() { addrs = append(addrs, iterator.GetNext()) } diff --git a/dkg/pedersen/types/messages.go b/dkg/pedersen/types/messages.go index 64fddc1bc..20b807209 100644 --- a/dkg/pedersen/types/messages.go +++ b/dkg/pedersen/types/messages.go @@ -5,6 +5,7 @@ import ( "go.dedis.ch/dela/serde" "go.dedis.ch/dela/serde/registry" "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/share" "golang.org/x/xerrors" ) @@ -439,6 +440,67 @@ func (req DecryptRequest) Serialize(ctx serde.Context) ([]byte, error) { return data, nil } +// ReencryptRequest is a message sent to request a reencryption. +// +// - implements serde.Message +type ReencryptRequest struct { + // U is the point from the write-request + U kyber.Point + // Pk is the public key of the reader + Pk kyber.Point + // VerificationData is optional and can be any slice of bytes, so that each + // node can verify if the reencryption request is valid or not. + VerificationData *[]byte +} + +// NewReencryptRequest creates a new decryption request. +func NewReencryptRequest(u, pk kyber.Point) ReencryptRequest { + return ReencryptRequest{ + U: u, + Pk: pk, + } +} + +// Serialize implements serde.Message. +func (req ReencryptRequest) Serialize(ctx serde.Context) ([]byte, error) { + format := msgFormats.Get(ctx.GetFormat()) + + data, err := format.Encode(ctx, req) + if err != nil { + return nil, xerrors.Errorf("couldn't encode decrypt request: %v", err) + } + + return data, nil +} + +// ReencryptReply returns the share to re-encrypt from one node +type ReencryptReply struct { + Ui *share.PubShare + Ei kyber.Scalar + Fi kyber.Scalar +} + +// NewReencryptReply creates a new decryption request. +func NewReencryptReply(ui *share.PubShare, ei, fi kyber.Scalar) ReencryptReply { + return ReencryptReply{ + Ui: ui, + Ei: ei, + Fi: fi, + } +} + +// Serialize implements serde.Message. +func (req ReencryptReply) Serialize(ctx serde.Context) ([]byte, error) { + format := msgFormats.Get(ctx.GetFormat()) + + data, err := format.Encode(ctx, req) + if err != nil { + return nil, xerrors.Errorf("couldn't encode decrypt request: %v", err) + } + + return data, nil +} + // VerifiableDecryptRequest is a message sent to request a verifiable // decryption. // From 9492b5b9f0a00a2d92fb21e131ed5e4ced815848 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Thu, 13 Apr 2023 21:51:00 +0200 Subject: [PATCH 03/34] created Pedersen reencryption scenario --- crypto/ed25519/ed25519.go | 10 +++ dkg/pedersen/dkg.go | 2 +- dkg/pedersen/dkg_test.go | 11 +++ dkg/pedersen/pedersen.go | 40 +++-------- dkg/pedersen/pedersen_test.go | 82 +++++++++++++++++++++ dkg/pedersen/state.go | 2 + dkg/pedersen/verifiable_test.go | 122 ++++++++++++++++++++++++++++++-- 7 files changed, 232 insertions(+), 37 deletions(-) diff --git a/crypto/ed25519/ed25519.go b/crypto/ed25519/ed25519.go index ea56b6c30..9ea18bb6d 100644 --- a/crypto/ed25519/ed25519.go +++ b/crypto/ed25519/ed25519.go @@ -328,3 +328,13 @@ func (s Signer) Sign(msg []byte) (crypto.Signature, error) { return Signature{data: sig}, nil } + +func ElGamalDecrypt(group kyber.Group, prikey kyber.Scalar, K, C kyber.Point) ( + message []byte, err error) { + + // ElGamal-decrypt the ciphertext (K,C) to reproduce the message. + S := group.Point().Mul(prikey, K) // regenerate shared secret + M := group.Point().Sub(C, S) // use to un-blind the message + message, err = M.Data() // extract the embedded data + return +} diff --git a/dkg/pedersen/dkg.go b/dkg/pedersen/dkg.go index 37646a238..f074c8f3c 100644 --- a/dkg/pedersen/dkg.go +++ b/dkg/pedersen/dkg.go @@ -816,7 +816,7 @@ func (s *instance) handleReencryptRequest(out mino.Sender, msg types.ReencryptRe ui := s.getUI(msg.U, msg.Pk) // Calculating proofs - si := suite.Scalar().Pick(suite().RandomStream()) + si := suite.Scalar().Pick(suite.RandomStream()) uiHat := suite.Point().Mul(si, suite.Point().Add(msg.U, msg.Pk)) hiHat := suite.Point().Mul(si, nil) hash := sha256.New() diff --git a/dkg/pedersen/dkg_test.go b/dkg/pedersen/dkg_test.go index 4c6892ce3..08d7c7843 100644 --- a/dkg/pedersen/dkg_test.go +++ b/dkg/pedersen/dkg_test.go @@ -117,6 +117,17 @@ func TestDKGInstance_HandleVerifiableDecryptRequestFail(t *testing.T) { require.EqualError(t, err, "bad state: unexpected state: UNKNOWN != one of [Certified]") } +func TestDKGInstance_HandleReencryptRequestFail(t *testing.T) { + s := instance{ + startRes: &state{dkgState: 0xaa}, + } + + err := s.handleMessage(context.TODO(), types.ReencryptRequest{}, + fake.NewAddress(0), nil) + + require.EqualError(t, err, "bad state: unexpected state: UNKNOWN != one of [Certified]") +} + func TestDKGInstance_HandleUnknown(t *testing.T) { s := instance{ startRes: &state{dkgState: 0xaa}, diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index c89f1f30d..25daa06ce 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -249,7 +249,8 @@ func (a *Actor) Reencrypt(k, c, pk kyber.Point) (K, C kyber.Point, remainder []b // Poly *share.PubPoly // Represents all public keys // U kyber.Point // U is the encrypted secret // Xc kyber.Point // The client's public key - // Threshold int // How many replies are needed to re-create the secret + // Threshold int // How many replies are needed + // to re-create the secret message := types.NewReencryptRequest(k, pk) err = <-sender.Send(message, addrs...) @@ -282,7 +283,7 @@ func (a *Actor) Reencrypt(k, c, pk kyber.Point) (K, C kyber.Point, remainder []b uiHat := suite.Point().Add(ufi, uiei) gfi := suite.Point().Mul(r.Fi, nil) - gxi := Poly.Eval(r.Ui.I).V //TODO: Poly *share.PubPoly // Represents all public keys + gxi := a.startRes.poly.Eval(r.Ui.I).V //TODO: Poly *share.PubPoly represents all public keys hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) hiHat := suite.Point().Add(gfi, hiei) hash := sha256.New() @@ -294,7 +295,7 @@ func (a *Actor) Reencrypt(k, c, pk kyber.Point) (K, C kyber.Point, remainder []b if e.Equal(r.Ei) { pubShares[r.Ui.I] = r.Ui } else { - dela.Logger.Warn().Msgf("Received invalid share from node", r.Ui.I) + dela.Logger.Warn().Msgf("Received invalid share %v from node", r.Ui.I) } } @@ -314,41 +315,16 @@ func (a *Actor) Reencrypt(k, c, pk kyber.Point) (K, C kyber.Point, remainder []b return K, C, remainder, nil } -// TODO: not where to get this UI ? +// TODO: where to get this UI ? func (a *Actor) getUI(U, Xc kyber.Point) *share.PubShare { - v := suite.Point().Mul(s.privShare.V, U) - v.Add(v, suite.Point().Mul(s.privShare.V, Xc)) + v := suite.Point().Mul(suite.Scalar().Zero(), U) + v.Add(v, suite.Point().Mul(suite.Scalar().Zero(), Xc)) return &share.PubShare{ - I: s.privShare.I, + I: 0, V: v, } } -// EncryptWithPublicKey implements dkg.Actor. It uses the given public key -// to encrypt a message. -func (a *Actor) EncryptWithPublicKey(message []byte, pk kyber.Point) (K, C kyber.Point, remainder []byte, err error) { - if !a.startRes.Done() { - return nil, nil, nil, xerrors.Errorf(initDkgFirst) - } - - // Embed the message (or as much of it as will fit) into a curve point. - M := suite.Point().Embed(message, random.New()) - max := suite.Point().EmbedLen() - if max > len(message) { - max = len(message) - } - remainder = message[max:] - - //TODO: make calculate re-encryption correctly - // ElGamal-encrypt the point to produce ciphertext (K,C). - k := suite.Scalar().Pick(random.New()) // ephemeral private key - K = suite.Point().Mul(k, nil) // ephemeral DH public key - S := suite.Point().Mul(k, pk) // ephemeral DH shared secret - C = S.Add(S, M) // message blinded with secret - - return K, C, remainder, nil -} - // VerifiableEncrypt implements dkg.Actor. It uses the DKG public key to encrypt // a message and provide a zero knowledge proof that the encryption is done by // this person. diff --git a/dkg/pedersen/pedersen_test.go b/dkg/pedersen/pedersen_test.go index 0bdc82fd6..d9594ad74 100644 --- a/dkg/pedersen/pedersen_test.go +++ b/dkg/pedersen/pedersen_test.go @@ -1,6 +1,7 @@ package pedersen import ( + "go.dedis.ch/kyber/v3/group/edwards25519" "testing" "github.com/rs/zerolog" @@ -225,6 +226,87 @@ func TestPedersen_Scenario(t *testing.T) { } } +func TestPedersen_ReencryptScenario(t *testing.T) { + oldLog := dela.Logger + defer func() { + dela.Logger = oldLog + }() + + dela.Logger = dela.Logger.Level(zerolog.DebugLevel) + + n := 7 + + minos := make([]mino.Mino, n) + dkgs := make([]dkg.DKG, n) + addrs := make([]mino.Address, n) + + for i := 0; i < n; i++ { + addr := minogrpc.ParseAddress("127.0.0.1", 0) + + m, err := minogrpc.NewMinogrpc(addr, nil, tree.NewRouter(minogrpc.NewAddressFactory())) + require.NoError(t, err) + + defer m.GracefulStop() + + minos[i] = m + addrs[i] = m.GetAddress() + } + + pubkeys := make([]kyber.Point, len(minos)) + + for i, mi := range minos { + for _, m := range minos { + mi.(*minogrpc.Minogrpc).GetCertificateStore().Store(m.GetAddress(), m.(*minogrpc.Minogrpc).GetCertificateChain()) + } + + d, pubkey := NewPedersen(mi.(*minogrpc.Minogrpc)) + + dkgs[i] = d + pubkeys[i] = pubkey + } + + fakeAuthority := NewAuthority(addrs, pubkeys) + + actors := make([]dkg.Actor, n) + for i := 0; i < n; i++ { + actor, err := dkgs[i].Listen() + require.NoError(t, err) + + actors[i] = actor + } + + // trying to call a reencrypt before a setup + _, _, _, err := actors[0].Reencrypt(nil, nil, nil) + require.EqualError(t, err, "you must first initialize DKG. Did you call setup() first?") + + _, err = actors[0].Setup(fakeAuthority, n) + require.NoError(t, err) + + suite := edwards25519.NewBlakeSHA256Ed25519() + + // Create a public/private keypair + privKey := suite.Scalar().Pick(suite.RandomStream()) + pubKey := suite.Point().Mul(privKey, nil) + + // every node should be able to encrypt/reencrypt with new PUBK/decrypt with new privk + for i := 0; i < n; i++ { + //TODO: generate random message + message := []byte("Hello world") + + K, C, remainder, err := actors[i].Encrypt(message) + require.NoError(t, err) + require.Len(t, remainder, 0) + + K, C, remainder, err = actors[i].Reencrypt(K, C, pubKey) + require.NoError(t, err) + require.Len(t, remainder, 0) + + decrypted, err := ed25519.ElGamalDecrypt(suite, privKey, K, C) + require.NoError(t, err) + require.Equal(t, message, decrypted) + } +} + func Test_Worker_BadProof(t *testing.T) { ct := types.Ciphertext{ K: suite.Point(), diff --git a/dkg/pedersen/state.go b/dkg/pedersen/state.go index 424f0262b..0490a5ebf 100644 --- a/dkg/pedersen/state.go +++ b/dkg/pedersen/state.go @@ -3,6 +3,7 @@ package pedersen import ( "go.dedis.ch/dela/mino" "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/share" "golang.org/x/xerrors" "sync" ) @@ -50,6 +51,7 @@ type state struct { // participants is set once a sharing or resharing starts participants []mino.Address pubkeys []kyber.Point + poly *share.PubPoly // TODO: is it the right place for reencrypt ? threshold int dkgState dkgState } diff --git a/dkg/pedersen/verifiable_test.go b/dkg/pedersen/verifiable_test.go index a802789ff..c0f5ee44b 100644 --- a/dkg/pedersen/verifiable_test.go +++ b/dkg/pedersen/verifiable_test.go @@ -2,6 +2,8 @@ package pedersen import ( "fmt" + "go.dedis.ch/dela/crypto/ed25519" + "go.dedis.ch/kyber/v3/group/edwards25519" "math/rand" "testing" "time" @@ -189,13 +191,13 @@ func Test_VerifiableEncDec_minogrpc(t *testing.T) { workerNum = numWorkersSlice[i] - keys := make([][29]byte, batchSize) + msg := make([][29]byte, batchSize) var ciphertexts []types.Ciphertext for i := 0; i < batchSize; i++ { - _, err = rand.Read(keys[i][:]) + _, err = rand.Read(msg[i][:]) require.NoError(t, err) - ciphertext, remainder, err := actors[0].VerifiableEncrypt(keys[i][:], GBar) + ciphertext, remainder, err := actors[0].VerifiableEncrypt(msg[i][:], GBar) require.NoError(t, err) require.Len(t, remainder, 0) @@ -210,7 +212,7 @@ func Test_VerifiableEncDec_minogrpc(t *testing.T) { require.NoError(t, err) for i := 0; i < batchSize; i++ { - require.Equal(t, keys[i][:], decrypted[i]) + require.Equal(t, msg[i][:], decrypted[i]) } t.Logf("n=%d, batchSize=%d, workerNum=%d, decryption time=%s, "+ @@ -219,6 +221,118 @@ func Test_VerifiableEncDec_minogrpc(t *testing.T) { } } +func Test_VerifiableReencrypt_minogrpc(t *testing.T) { + // we want to time the decryption for different batch sizes with different + // number of nodes + + numWorkersSlice := []int{8} + batchSizeSlice := []int{32} + + // setting up the dkg + n := 7 + threshold := n + + minos := make([]mino.Mino, n) + dkgs := make([]dkg.DKG, n) + addrs := make([]mino.Address, n) + + // Create GBar. We need a generator in order to follow the encryption and + // decryption protocol of https://arxiv.org/pdf/2205.08529.pdf. We take an + // agreed data among the participants and embed it as a point. The result is + // the generator that we are seeking. + agreedData := make([]byte, 32) + _, err := rand.Read(agreedData) + require.NoError(t, err) + GBar := suite.Point().Embed(agreedData, keccak.New(agreedData)) + + t.Log("initiating the dkg nodes ...") + + for i := 0; i < n; i++ { + addr := minogrpc.ParseAddress("127.0.0.1", 0) + + minogrpc, err := minogrpc.NewMinogrpc(addr, nil, tree.NewRouter(minogrpc.NewAddressFactory())) + require.NoError(t, err) + + defer minogrpc.GracefulStop() + + minos[i] = minogrpc + addrs[i] = minogrpc.GetAddress() + } + + pubkeys := make([]kyber.Point, n) + + for i, mino := range minos { + for _, m := range minos { + mino.(*minogrpc.Minogrpc).GetCertificateStore().Store(m.GetAddress(), + m.(*minogrpc.Minogrpc).GetCertificateChain()) + } + dkg, pubkey := NewPedersen(mino.(*minogrpc.Minogrpc)) + dkgs[i] = dkg + pubkeys[i] = pubkey + } + + fakeAuthority := NewAuthority(addrs, pubkeys) + + actors := make([]dkg.Actor, n) + for i := 0; i < n; i++ { + actor, err := dkgs[i].Listen() + require.NoError(t, err) + actors[i] = actor + } + + t.Log("setting up the dkg ...") + + start := time.Now() + _, err = actors[0].Setup(fakeAuthority, threshold) + require.NoError(t, err) + setupTime := time.Since(start) + + // generating random messages in batch and encrypt them + for i, batchSize := range batchSizeSlice { + t.Logf("=== starting the process with batch size = %d === \n", batchSize) + + workerNum = numWorkersSlice[i] + + msg := make([][29]byte, batchSize) + var ciphertexts []types.Ciphertext + for i := 0; i < batchSize; i++ { + _, err = rand.Read(msg[i][:]) + require.NoError(t, err) + + ciphertext, remainder, err := actors[0].VerifiableEncrypt(msg[i][:], GBar) + require.NoError(t, err) + require.Len(t, remainder, 0) + + ciphertexts = append(ciphertexts, ciphertext) + } + + t.Log("reencrypting the batch ...") + + // create pub/priv key pair + var suite = edwards25519.NewBlakeSHA256Ed25519() + privKey := suite.Scalar().Pick(suite.RandomStream()) + pubKey := suite.Point().Mul(privKey, nil) + + start = time.Now() + reencrypted, err := actors[0].VerifiableReencrypt(ciphertexts, pubKey) + reencryptionTime := time.Since(start) + require.NoError(t, err) + + for i := 0; i < batchSize; i++ { + //TODO: extract K,C from reencrypted ? + K := suite.Point() + C := suite.Point() + decrypted, err := ed25519.ElGamalDecrypt(suite, privKey, K, C) + require.NoError(t, err) + require.Equal(t, msg[i][:], decrypted[i]) + } + + t.Logf("n=%d, batchSize=%d, workerNum=%d, decryption time=%s, "+ + "throughput=%v[tx/s], dkg setup time=%s", n, batchSize, workerNum, + reencryptionTime, float64(batchSize)/reencryptionTime.Seconds(), setupTime) + } +} + func Test_VerifiableDecrypt_NotStarted(t *testing.T) { a := Actor{ startRes: &state{dkgState: initial}, From 7aa55f077df815042fd15cd0d493b0a5fcc6ad26 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Tue, 25 Apr 2023 17:05:05 +0200 Subject: [PATCH 04/34] temporary verifiable encrypt --- dkg/dkg.go | 3 +- dkg/pedersen/pedersen.go | 111 ++++++++++++++++++++++++++++++++ dkg/pedersen/verifiable_test.go | 9 +-- 3 files changed, 118 insertions(+), 5 deletions(-) diff --git a/dkg/dkg.go b/dkg/dkg.go index 1c120d76f..fecb96958 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -30,6 +30,7 @@ type Actor interface { Reshare(co crypto.CollectiveAuthority, newThreshold int) error - VerifiableDecrypt(ciphertexts []types.Ciphertext) ([][]byte, error) VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext types.Ciphertext, remainder []byte, err error) + VerifiableDecrypt(ciphertexts []types.Ciphertext) ([][]byte, error) + VerifiableReencrypt(ciphertexts []types.Ciphertext, pubk kyber.Point) (ciphertext []types.Ciphertext, remainder []byte, err error) } diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 25daa06ce..751620c12 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -1,5 +1,6 @@ package pedersen +import "C" import ( "crypto/sha256" "runtime" @@ -549,6 +550,116 @@ func (a *Actor) VerifiableDecrypt(ciphertexts []types.Ciphertext) ([][]byte, err return decryptedMessage, nil } +func (a *Actor) VerifiableReencrypt(cipher []types.Ciphertext, pubk kyber.Point) (ciphertext []types.Ciphertext, remainder []byte, err error) { + if !a.startRes.Done() { + return []types.Ciphertext{}, nil, xerrors.Errorf(initDkgFirst) + } + + ctx, cancel := context.WithTimeout(context.Background(), reencryptTimeout) + defer cancel() + ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameReencrypt) + + players := mino.NewAddresses(a.startRes.getParticipants()...) + + sender, receiver, err := a.rpc.Stream(ctx, players) + if err != nil { + return []types.Ciphertext{}, nil, xerrors.Errorf(failedStreamCreation, err) + } + + iterator := players.AddressIterator() + + addrs := make([]mino.Address, 0, players.Len()) + for iterator.HasNext() { + addrs = append(addrs, iterator.GetNext()) + } + + //TODO: how to calculate (k, pk) in place of (U, Xc) ? + // copied from cothority/calypso/protocol/ocs.go: + // type OCS struct { + // *onet.TreeNodeInstance + // Shared *dkgprotocol.SharedSecret // Shared represents the private key + // Poly *share.PubPoly // Represents all public keys + // U kyber.Point // U is the encrypted secret + // Xc kyber.Point // The client's public key + // Threshold int // How many replies are needed + // to re-create the secret + + //TODO is the following correct ??? + U := cipher[0].K + Xc := pubk + + batchsize := len(cipher) + + message := types.NewReencryptRequest(U, Xc) + + err = <-sender.Send(message, addrs...) + if err != nil { + return []types.Ciphertext{}, nil, xerrors.Errorf("failed to send decrypt request: %v", err) + } + + pubShares := make([]*share.PubShare, len(addrs)) + pubShares[0] = a.getUI(U, Xc) // TODO: verify that this getUI(U, Xc) call is correct + + for i := 0; i < len(addrs); i++ { + src, message, err := receiver.Recv(ctx) + if err != nil && i < a.startRes.threshold { + return []types.Ciphertext{}, nil, xerrors.Errorf(unexpectedStreamStop, err) + } + + dela.Logger.Debug().Msgf("Received a reencryption reply from %v", src) + + r, ok := message.(types.ReencryptReply) + if !ok { + return []types.Ciphertext{}, nil, xerrors.Errorf("got unexpected reply, expected "+ + "%T but got: %T", r, message) + } + + // Verify proofs + ufi := suite.Point().Mul(r.Fi, suite.Point().Add(U, Xc)) + uiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), r.Ui.V) + uiHat := suite.Point().Add(ufi, uiei) + + gfi := suite.Point().Mul(r.Fi, nil) + gxi := a.startRes.poly.Eval(r.Ui.I).V //TODO: Poly *share.PubPoly represents all public keys + hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) + hiHat := suite.Point().Add(gfi, hiei) + hash := sha256.New() + r.Ui.V.MarshalTo(hash) + uiHat.MarshalTo(hash) + hiHat.MarshalTo(hash) + + e := suite.Scalar().SetBytes(hash.Sum(nil)) + if e.Equal(r.Ei) { + pubShares[r.Ui.I] = r.Ui + } else { + dela.Logger.Warn().Msgf("Received invalid share %v from node", r.Ui.I) + } + } + + res, err := share.RecoverCommit(suite, pubShares, len(addrs), len(addrs)) + if err != nil { + return []types.Ciphertext{}, nil, xerrors.Errorf("failed to recover commit: %v", err) + } + + decryptedMessage, err := res.Data() + if err != nil { + return []types.Ciphertext{}, nil, xerrors.Errorf("failed to get embedded data: %v", err) + } + + dela.Logger.Info().Msgf("Decrypted message: %v", decryptedMessage) + + ciphertext = []types.Ciphertext{ + K: K, + C: C, + UBar: UBar, + E: E, + F: F, + GBar: GBar, + } + + return ciphertext, remainder, nil +} + func newWorker(numParticipants int, decryptedMessage [][]byte, responses []types.VerifiableDecryptReply, ciphertexts []types.Ciphertext) worker { diff --git a/dkg/pedersen/verifiable_test.go b/dkg/pedersen/verifiable_test.go index c0f5ee44b..5afad4bc2 100644 --- a/dkg/pedersen/verifiable_test.go +++ b/dkg/pedersen/verifiable_test.go @@ -314,14 +314,15 @@ func Test_VerifiableReencrypt_minogrpc(t *testing.T) { pubKey := suite.Point().Mul(privKey, nil) start = time.Now() - reencrypted, err := actors[0].VerifiableReencrypt(ciphertexts, pubKey) + reencrypted, rem, err := actors[0].VerifiableReencrypt(ciphertexts, pubKey) + //TODO what to do with rem here ? reencryptionTime := time.Since(start) require.NoError(t, err) for i := 0; i < batchSize; i++ { - //TODO: extract K,C from reencrypted ? - K := suite.Point() - C := suite.Point() + //TODO verify this extraction ? + K := reencrypted[i].K + C := reencrypted[i].C decrypted, err := ed25519.ElGamalDecrypt(suite, privKey, K, C) require.NoError(t, err) require.Equal(t, msg[i][:], decrypted[i]) From ec32b7f2a9320c0394102ffee4b30816a2c4330c Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 17 May 2023 16:05:43 +0200 Subject: [PATCH 05/34] pederson test to reencrypt some data - part1 --- dkg/dkg.go | 8 +- dkg/pedersen/dkg.go | 29 +- dkg/pedersen/json/json.go | 147 +++++++++ dkg/pedersen/pedersen.go | 511 ++++++++++++++++---------------- dkg/pedersen/pedersen_test.go | 87 +++--- dkg/pedersen/types/messages.go | 28 +- dkg/pedersen/verifiable_test.go | 115 ------- 7 files changed, 470 insertions(+), 455 deletions(-) diff --git a/dkg/dkg.go b/dkg/dkg.go index fecb96958..9308542a8 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -4,6 +4,7 @@ import ( "go.dedis.ch/dela/crypto" "go.dedis.ch/dela/dkg/pedersen/types" "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/share" ) // DKG defines the primitive to start a DKG protocol @@ -26,11 +27,14 @@ type Actor interface { Encrypt(message []byte) (K, C kyber.Point, remainder []byte, err error) Decrypt(K, C kyber.Point) ([]byte, error) - Reencrypt(k, c, pk kyber.Point) (K, C kyber.Point, remainder []byte, err error) Reshare(co crypto.CollectiveAuthority, newThreshold int) error VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext types.Ciphertext, remainder []byte, err error) VerifiableDecrypt(ciphertexts []types.Ciphertext) ([][]byte, error) - VerifiableReencrypt(ciphertexts []types.Ciphertext, pubk kyber.Point) (ciphertext []types.Ciphertext, remainder []byte, err error) + + EncryptSecret(message []byte) (U kyber.Point, Cs []kyber.Point) + ReencryptSecret(U kyber.Point, Pk kyber.Point) (Uis []*share.PubShare, err error) + + DecryptSecret(Cs []kyber.Point, XhatEnc kyber.Point, Sk kyber.Scalar) (message []byte, err error) } diff --git a/dkg/pedersen/dkg.go b/dkg/pedersen/dkg.go index f074c8f3c..596405b26 100644 --- a/dkg/pedersen/dkg.go +++ b/dkg/pedersen/dkg.go @@ -183,14 +183,6 @@ func (s *instance) handleMessage(ctx context.Context, msg serde.Message, from mi return s.handleReencryptRequest(out, msg, from) - case types.ReencryptReply: - err := s.startRes.checkState(certified) - if err != nil { - return xerrors.Errorf(badState, err) - } - - return s.handleReencryptReply(out, msg, from) - default: return xerrors.Errorf("expected Start message, decrypt request or "+ "Deal as first message, got: %T", msg) @@ -813,11 +805,11 @@ func (s *instance) handleReencryptRequest(out mino.Sender, msg types.ReencryptRe return xerrors.Errorf("you must first initialize DKG. Did you call setup() first?") } - ui := s.getUI(msg.U, msg.Pk) + ui := s.getUI(msg.U, msg.PubK) // Calculating proofs si := suite.Scalar().Pick(suite.RandomStream()) - uiHat := suite.Point().Mul(si, suite.Point().Add(msg.U, msg.Pk)) + uiHat := suite.Point().Mul(si, suite.Point().Add(msg.U, msg.PubK)) hiHat := suite.Point().Mul(si, nil) hash := sha256.New() ui.V.MarshalTo(hash) @@ -831,32 +823,21 @@ func (s *instance) handleReencryptRequest(out mino.Sender, msg types.ReencryptRe errs := out.Send(response, from) err := <-errs if err != nil { - return xerrors.Errorf("got an error while sending the decrypt reply: %v", err) + return xerrors.Errorf("got an error while sending the reencrypt reply: %v", err) } return nil } -func (s *instance) getUI(U, Xc kyber.Point) *share.PubShare { +func (s *instance) getUI(U, pubk kyber.Point) *share.PubShare { v := suite.Point().Mul(s.privShare.V, U) - v.Add(v, suite.Point().Mul(s.privShare.V, Xc)) + v.Add(v, suite.Point().Mul(s.privShare.V, pubk)) return &share.PubShare{ I: s.privShare.I, V: v, } } -func (s *instance) handleReencryptReply(out mino.Sender, msg types.ReencryptReply, - from mino.Address) error { - - if !s.startRes.Done() { - return xerrors.Errorf("you must first initialize DKG. Did you call setup() first?") - } - - //TODO: to be continued... - return nil -} - func (s *instance) handleVerifiableDecrypt(out mino.Sender, msg types.VerifiableDecryptRequest, from mino.Address) error { diff --git a/dkg/pedersen/json/json.go b/dkg/pedersen/json/json.go index ccc87d495..80bdd2205 100644 --- a/dkg/pedersen/json/json.go +++ b/dkg/pedersen/json/json.go @@ -5,6 +5,7 @@ import ( "go.dedis.ch/dela/mino" "go.dedis.ch/dela/serde" "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/share" "go.dedis.ch/kyber/v3/suites" "golang.org/x/xerrors" ) @@ -103,6 +104,19 @@ type VerifiableDecryptReply struct { Sp []ShareAndProof } +type ReencryptRequest struct { + U []byte + PubK PublicKey + VerificationData *[]byte +} + +type ReencryptReply struct { + PubK PublicKey + Ui *share.PubShare + Ei []byte + Fi []byte +} + type Message struct { Start *Start `json:",omitempty"` StartResharing *StartResharing `json:",omitempty"` @@ -114,6 +128,8 @@ type Message struct { DecryptReply *DecryptReply `json:",omitempty"` VerifiableDecryptReply *VerifiableDecryptReply `json:",omitempty"` VerifiableDecryptRequest *VerifiableDecryptRequest `json:",omitempty"` + ReencryptRequest *ReencryptRequest `json:",omitempty"` + ReencryptReply *ReencryptReply `json:",omitempty"` } // MsgFormat is the engine to encode and decode dkg messages in JSON format. @@ -177,6 +193,10 @@ func (f msgFormat) Encode(ctx serde.Context, msg serde.Message) ([]byte, error) m, err = encodeDecryptReply(in) case types.VerifiableDecryptReply: m, err = encodeVerifiableDecryptReply(in) + case types.ReencryptRequest: + m, err = encodeReencryptRequest(in) + case types.ReencryptReply: + m, err = encodeReencryptReply(in) default: return nil, xerrors.Errorf("unsupported message of type '%T'", msg) } @@ -253,6 +273,12 @@ func (f msgFormat) Decode(ctx serde.Context, data []byte) (serde.Message, error) case m.VerifiableDecryptReply != nil: return f.decodeVerifiableDecryptReply(ctx, m.VerifiableDecryptReply) + + case m.ReencryptRequest != nil: + return f.decodeReencryptRequest(ctx, m.ReencryptRequest) + + case m.ReencryptReply != nil: + return f.decodeReencryptReply(ctx, m.ReencryptReply) } return nil, xerrors.New("message is empty") @@ -538,6 +564,62 @@ func (f msgFormat) decodeDecryptRequest(ctx serde.Context, msg *DecryptRequest) return req, nil } +func encodeReencryptRequest(msg types.ReencryptRequest) (Message, error) { + u, err := msg.U.MarshalBinary() + if err != nil { + return Message{}, xerrors.Errorf("couldn't marshal U: %v", err) + } + + pubk, err := msg.PubK.MarshalBinary() + if err != nil { + return Message{}, xerrors.Errorf("couldn't marshal PubK: %v", err) + } + + v, err := msg.VerificationData.MarshalBinary() + if err != nil { + return Message{}, xerrors.Errorf("couldn't marshal PubK: %v", err) + } + + req := ReencryptRequest{ + U: u, + PubK: pubk, + VerificationData: v, + } + + return Message{ReencryptRequest: &req}, nil +} + +func encodeReencryptReply(msg types.ReencryptReply) (Message, error) { + pubk, err := msg.PubK.MarshalBinary() + if err != nil { + return Message{}, xerrors.Errorf("couldn't marshal PubK: %v", err) + } + + ui, err := msg.Ui.MarshalBinary() + if err != nil { + return Message{}, xerrors.Errorf("couldn't marshal Ui: %v", err) + } + + ei, err := msg.Ei.MarshalBinary() + if err != nil { + return Message{}, xerrors.Errorf("couldn't marshal Ei: %v", err) + } + + fi, err := msg.Fi.MarshalBinary() + if err != nil { + return Message{}, xerrors.Errorf("couldn't marshal Fi: %v", err) + } + + rep := ReencryptReply{ + PubK: pubk, + Ui: ui, + Ei: ei, + Fi: fi, + } + + return Message{ReencryptReply: &rep}, nil +} + func encodeVerifiableDecryptRequest(msg types.VerifiableDecryptRequest) (Message, error) { ciphertexts := msg.GetCiphertexts() var encodedCiphertexts []Ciphertext @@ -778,3 +860,68 @@ func (f msgFormat) decodeVerifiableDecryptReply(ctx serde.Context, return resp, nil } + +// TODO implement +func (f msgFormat) decodeReencryptRequest(ctx serde.Context, request *ReencryptRequest) (serde.Message, error) { + u := f.suite.Point() + err := u.UnmarshalBinary(request.U) + if err != nil { + return nil, xerrors.Errorf("couldn't unmarshal U: %v", err) + } + + pubk := f.suite.Point() + err = pubk.UnmarshalBinary(request.PubK) + if err != nil { + return nil, xerrors.Errorf("couldn't unmarshal PubK: %v", err) + } + + v := f.suite.Scalar() + err = v.UnmarshalBinary(request.VerificationData) + if err != nil { + return nil, xerrors.Errorf("couldn't marshal verification data: %v", err) + } + + resp := types.ReencryptRequest{ + U: u, + PubK: pubk, + VerificationData: v, + } + + return resp, nil +} + +// TODO implement +func (f msgFormat) decodeReencryptReply(ctx serde.Context, reply *ReencryptReply) (serde.Message, error) { + pubk := f.suite.Point() + err := pubk.UnmarshalBinary(reply.PubK) + if err != nil { + return nil, xerrors.Errorf("couldn't unmarshal PubK: %v", err) + } + + ui := f.suite.Point() + err = ui.UnmarshalBinary(reply.Ui) + if err != nil { + return nil, xerrors.Errorf("couldn't unmarshal Ui: %v", err) + } + + ei := f.suite.Scalar() + err = ei.UnmarshalBinary(reply.Ei) + if err != nil { + return nil, xerrors.Errorf("couldn't unmarshal Ei: %v", err) + } + + fi := f.suite.Scalar() + err = fi.UnmarshalBinary(reply.Fi) + if err != nil { + return nil, xerrors.Errorf("couldn't unmarshal Fi: %v", err) + } + + resp := types.ReencryptReply{ + PubK: pubk, + Ui: ui, + Ei: ei, + Fi: fi, + } + + return resp, nil +} diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 751620c12..21ce6da54 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -217,22 +217,23 @@ func (a *Actor) Encrypt(message []byte) (K, C kyber.Point, remainder []byte, return K, C, remainder, nil } -// Reencrypt implements dkg.Actor. It uses the given public key -// to reencrypt an encrypted message. -func (a *Actor) Reencrypt(k, c, pk kyber.Point) (K, C kyber.Point, remainder []byte, err error) { +// Decrypt implements dkg.Actor. It gets the private shares of the nodes and +// decrypt the message. +func (a *Actor) Decrypt(K, C kyber.Point) ([]byte, error) { + if !a.startRes.Done() { - return nil, nil, []byte{}, xerrors.Errorf(initDkgFirst) + return nil, xerrors.Errorf(initDkgFirst) } - ctx, cancel := context.WithTimeout(context.Background(), reencryptTimeout) + ctx, cancel := context.WithTimeout(context.Background(), decryptTimeout) defer cancel() - ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameReencrypt) + ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameDecrypt) players := mino.NewAddresses(a.startRes.getParticipants()...) sender, receiver, err := a.rpc.Stream(ctx, players) if err != nil { - return nil, nil, []byte{}, xerrors.Errorf(failedStreamCreation, err) + return nil, xerrors.Errorf(failedStreamCreation, err) } iterator := players.AddressIterator() @@ -242,88 +243,48 @@ func (a *Actor) Reencrypt(k, c, pk kyber.Point) (K, C kyber.Point, remainder []b addrs = append(addrs, iterator.GetNext()) } - //TODO: how to calculate (k, pk) in place of (U, Xc) ? - // seems correct, as in: - // type OCS struct { - // *onet.TreeNodeInstance - // Shared *dkgprotocol.SharedSecret // Shared represents the private key - // Poly *share.PubPoly // Represents all public keys - // U kyber.Point // U is the encrypted secret - // Xc kyber.Point // The client's public key - // Threshold int // How many replies are needed - // to re-create the secret - message := types.NewReencryptRequest(k, pk) + message := types.NewDecryptRequest(K, C) err = <-sender.Send(message, addrs...) if err != nil { - return nil, nil, []byte{}, xerrors.Errorf("failed to send decrypt request: %v", err) + return nil, xerrors.Errorf("failed to send decrypt request: %v", err) } pubShares := make([]*share.PubShare, len(addrs)) - U := k - Xc := pk - pubShares[0] = a.getUI(k, pk) // TODO: verify that this getUI(U, Xc) call is correct for i := 0; i < len(addrs); i++ { src, message, err := receiver.Recv(ctx) - if err != nil && i < a.startRes.threshold { - return nil, nil, []byte{}, xerrors.Errorf(unexpectedStreamStop, err) + if err != nil { + return []byte{}, xerrors.Errorf(unexpectedStreamStop, err) } - dela.Logger.Debug().Msgf("Received a reencryption reply from %v", src) + dela.Logger.Debug().Msgf("Received a decryption reply from %v", src) - r, ok := message.(types.ReencryptReply) + decryptReply, ok := message.(types.DecryptReply) if !ok { - return nil, nil, []byte{}, xerrors.Errorf("got unexpected reply, expected "+ - "%T but got: %T", r, message) + return []byte{}, xerrors.Errorf("got unexpected reply, expected "+ + "%T but got: %T", decryptReply, message) } - // Verify proofs - ufi := suite.Point().Mul(r.Fi, suite.Point().Add(U, Xc)) - uiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), r.Ui.V) - uiHat := suite.Point().Add(ufi, uiei) - - gfi := suite.Point().Mul(r.Fi, nil) - gxi := a.startRes.poly.Eval(r.Ui.I).V //TODO: Poly *share.PubPoly represents all public keys - hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) - hiHat := suite.Point().Add(gfi, hiei) - hash := sha256.New() - r.Ui.V.MarshalTo(hash) - uiHat.MarshalTo(hash) - hiHat.MarshalTo(hash) - - e := suite.Scalar().SetBytes(hash.Sum(nil)) - if e.Equal(r.Ei) { - pubShares[r.Ui.I] = r.Ui - } else { - dela.Logger.Warn().Msgf("Received invalid share %v from node", r.Ui.I) + pubShares[i] = &share.PubShare{ + I: int(decryptReply.I), + V: decryptReply.V, } } res, err := share.RecoverCommit(suite, pubShares, len(addrs), len(addrs)) if err != nil { - return nil, nil, []byte{}, xerrors.Errorf("failed to recover commit: %v", err) + return []byte{}, xerrors.Errorf("failed to recover commit: %v", err) } decryptedMessage, err := res.Data() if err != nil { - return nil, nil, []byte{}, xerrors.Errorf("failed to get embedded data: %v", err) + return []byte{}, xerrors.Errorf("failed to get embedded data: %v", err) } dela.Logger.Info().Msgf("Decrypted message: %v", decryptedMessage) - // return new encrypted message, nil - return K, C, remainder, nil -} - -// TODO: where to get this UI ? -func (a *Actor) getUI(U, Xc kyber.Point) *share.PubShare { - v := suite.Point().Mul(suite.Scalar().Zero(), U) - v.Add(v, suite.Point().Mul(suite.Scalar().Zero(), Xc)) - return &share.PubShare{ - I: 0, - V: v, - } + return decryptedMessage, nil } // VerifiableEncrypt implements dkg.Actor. It uses the DKG public key to encrypt @@ -349,31 +310,31 @@ func (a *Actor) VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext remainder = message[max:] - // ElGamal-encrypt the point to produce ciphertext (K,C). - k := suite.Scalar().Pick(random.New()) // ephemeral private key - K := suite.Point().Mul(k, nil) // ephemeral DH public key - S := suite.Point().Mul(k, a.startRes.getDistKey()) // ephemeral DH shared secret - C := S.Add(S, M) // message blinded with secret + // ElGamal-encrypt the point to produce ciphertext (localK,localC). + localk := suite.Scalar().Pick(random.New()) // ephemeral private key + localK := suite.Point().Mul(localk, nil) // ephemeral DH public key + localS := suite.Point().Mul(localk, a.startRes.getDistKey()) // ephemeral DH shared secret + localC := localS.Add(localS, M) // message blinded with secret // producing the zero knowledge proof - UBar := suite.Point().Mul(k, GBar) + UBar := suite.Point().Mul(localk, GBar) s := suite.Scalar().Pick(random.New()) W := suite.Point().Mul(s, nil) WBar := suite.Point().Mul(s, GBar) hash := sha256.New() - C.MarshalTo(hash) - K.MarshalTo(hash) + localC.MarshalTo(hash) + localK.MarshalTo(hash) UBar.MarshalTo(hash) W.MarshalTo(hash) WBar.MarshalTo(hash) E := suite.Scalar().SetBytes(hash.Sum(nil)) - F := suite.Scalar().Add(s, suite.Scalar().Mul(E, k)) + F := suite.Scalar().Add(s, suite.Scalar().Mul(E, localk)) ciphertext = types.Ciphertext{ - K: K, - C: C, + K: localK, + C: localC, UBar: UBar, E: E, F: F, @@ -383,76 +344,6 @@ func (a *Actor) VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext return ciphertext, remainder, nil } -// Decrypt implements dkg.Actor. It gets the private shares of the nodes and -// decrypt the message. -func (a *Actor) Decrypt(K, C kyber.Point) ([]byte, error) { - - if !a.startRes.Done() { - return nil, xerrors.Errorf(initDkgFirst) - } - - ctx, cancel := context.WithTimeout(context.Background(), decryptTimeout) - defer cancel() - ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameDecrypt) - - players := mino.NewAddresses(a.startRes.getParticipants()...) - - sender, receiver, err := a.rpc.Stream(ctx, players) - if err != nil { - return nil, xerrors.Errorf(failedStreamCreation, err) - } - - iterator := players.AddressIterator() - addrs := make([]mino.Address, 0, players.Len()) - - for iterator.HasNext() { - addrs = append(addrs, iterator.GetNext()) - } - - message := types.NewDecryptRequest(K, C) - - err = <-sender.Send(message, addrs...) - if err != nil { - return nil, xerrors.Errorf("failed to send decrypt request: %v", err) - } - - pubShares := make([]*share.PubShare, len(addrs)) - - for i := 0; i < len(addrs); i++ { - src, message, err := receiver.Recv(ctx) - if err != nil { - return []byte{}, xerrors.Errorf(unexpectedStreamStop, err) - } - - dela.Logger.Debug().Msgf("Received a decryption reply from %v", src) - - decryptReply, ok := message.(types.DecryptReply) - if !ok { - return []byte{}, xerrors.Errorf("got unexpected reply, expected "+ - "%T but got: %T", decryptReply, message) - } - - pubShares[i] = &share.PubShare{ - I: int(decryptReply.I), - V: decryptReply.V, - } - } - - res, err := share.RecoverCommit(suite, pubShares, len(addrs), len(addrs)) - if err != nil { - return []byte{}, xerrors.Errorf("failed to recover commit: %v", err) - } - - decryptedMessage, err := res.Data() - if err != nil { - return []byte{}, xerrors.Errorf("failed to get embedded data: %v", err) - } - - dela.Logger.Info().Msgf("Decrypted message: %v", decryptedMessage) - - return decryptedMessage, nil -} - // VerifiableDecrypt implements dkg.Actor. It does as Decrypt() but in addition // it checks whether the decryption proofs are valid. // @@ -550,116 +441,6 @@ func (a *Actor) VerifiableDecrypt(ciphertexts []types.Ciphertext) ([][]byte, err return decryptedMessage, nil } -func (a *Actor) VerifiableReencrypt(cipher []types.Ciphertext, pubk kyber.Point) (ciphertext []types.Ciphertext, remainder []byte, err error) { - if !a.startRes.Done() { - return []types.Ciphertext{}, nil, xerrors.Errorf(initDkgFirst) - } - - ctx, cancel := context.WithTimeout(context.Background(), reencryptTimeout) - defer cancel() - ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameReencrypt) - - players := mino.NewAddresses(a.startRes.getParticipants()...) - - sender, receiver, err := a.rpc.Stream(ctx, players) - if err != nil { - return []types.Ciphertext{}, nil, xerrors.Errorf(failedStreamCreation, err) - } - - iterator := players.AddressIterator() - - addrs := make([]mino.Address, 0, players.Len()) - for iterator.HasNext() { - addrs = append(addrs, iterator.GetNext()) - } - - //TODO: how to calculate (k, pk) in place of (U, Xc) ? - // copied from cothority/calypso/protocol/ocs.go: - // type OCS struct { - // *onet.TreeNodeInstance - // Shared *dkgprotocol.SharedSecret // Shared represents the private key - // Poly *share.PubPoly // Represents all public keys - // U kyber.Point // U is the encrypted secret - // Xc kyber.Point // The client's public key - // Threshold int // How many replies are needed - // to re-create the secret - - //TODO is the following correct ??? - U := cipher[0].K - Xc := pubk - - batchsize := len(cipher) - - message := types.NewReencryptRequest(U, Xc) - - err = <-sender.Send(message, addrs...) - if err != nil { - return []types.Ciphertext{}, nil, xerrors.Errorf("failed to send decrypt request: %v", err) - } - - pubShares := make([]*share.PubShare, len(addrs)) - pubShares[0] = a.getUI(U, Xc) // TODO: verify that this getUI(U, Xc) call is correct - - for i := 0; i < len(addrs); i++ { - src, message, err := receiver.Recv(ctx) - if err != nil && i < a.startRes.threshold { - return []types.Ciphertext{}, nil, xerrors.Errorf(unexpectedStreamStop, err) - } - - dela.Logger.Debug().Msgf("Received a reencryption reply from %v", src) - - r, ok := message.(types.ReencryptReply) - if !ok { - return []types.Ciphertext{}, nil, xerrors.Errorf("got unexpected reply, expected "+ - "%T but got: %T", r, message) - } - - // Verify proofs - ufi := suite.Point().Mul(r.Fi, suite.Point().Add(U, Xc)) - uiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), r.Ui.V) - uiHat := suite.Point().Add(ufi, uiei) - - gfi := suite.Point().Mul(r.Fi, nil) - gxi := a.startRes.poly.Eval(r.Ui.I).V //TODO: Poly *share.PubPoly represents all public keys - hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) - hiHat := suite.Point().Add(gfi, hiei) - hash := sha256.New() - r.Ui.V.MarshalTo(hash) - uiHat.MarshalTo(hash) - hiHat.MarshalTo(hash) - - e := suite.Scalar().SetBytes(hash.Sum(nil)) - if e.Equal(r.Ei) { - pubShares[r.Ui.I] = r.Ui - } else { - dela.Logger.Warn().Msgf("Received invalid share %v from node", r.Ui.I) - } - } - - res, err := share.RecoverCommit(suite, pubShares, len(addrs), len(addrs)) - if err != nil { - return []types.Ciphertext{}, nil, xerrors.Errorf("failed to recover commit: %v", err) - } - - decryptedMessage, err := res.Data() - if err != nil { - return []types.Ciphertext{}, nil, xerrors.Errorf("failed to get embedded data: %v", err) - } - - dela.Logger.Info().Msgf("Decrypted message: %v", decryptedMessage) - - ciphertext = []types.Ciphertext{ - K: K, - C: C, - UBar: UBar, - E: E, - F: F, - GBar: GBar, - } - - return ciphertext, remainder, nil -} - func newWorker(numParticipants int, decryptedMessage [][]byte, responses []types.VerifiableDecryptReply, ciphertexts []types.Ciphertext) worker { @@ -711,6 +492,215 @@ func (w worker) work(jobIndex int) error { return nil } +// EncryptSecret implements dkg.Actor. +func (a *Actor) EncryptSecret(msg []byte) (U kyber.Point, Cs []kyber.Point) { + pubK, err := a.GetPublicKey() + if err != nil { + dela.Logger.Error().Msgf("Cannot encrypt secret: %v", err.Error()) + } + + r := suite.Scalar().Pick(suite.RandomStream()) + C := suite.Point().Mul(r, pubK) + dela.Logger.Debug().Msgf("C:%v", C) + + U = suite.Point().Mul(r, nil) + dela.Logger.Debug().Msgf("U is:%v", U.String()) + + for len(msg) > 0 { + kp := suite.Point().Embed(msg, suite.RandomStream()) + dela.Logger.Debug().Msgf("Keypoint:%v", kp.String()) + dela.Logger.Debug().Msgf("X:%v", pubK.String()) + + Cs = append(Cs, suite.Point().Add(C, kp)) + dela.Logger.Debug().Msgf("Cs:%v", C) + + msg = msg[min(len(msg), kp.EmbedLen()):] + } + + return +} + +type OCS struct { + shared *share.PriShare // Shared represents the private key + poly *share.PubPoly // Represents all public keys + replies []types.ReencryptReply // replies received + U kyber.Point // U is the random part of the encrypted secret + pubk kyber.Point // The client's public key + nbnodes int // How many nodes participate in the distributed operations + nbfailures int // How many failures occurred so far + threshold int // How many replies are needed to re-create the secret + Uis []*share.PubShare // re-encrypted shares +} + +// newOCS creates a new on-chain secret structure. +func newOCS(pubk kyber.Point) *OCS { + return &OCS{ + pubk: pubk, + } +} + +// ReencryptSecret implements dkg.Actor. +func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point) (Uis []*share.PubShare, err error) { + if !a.startRes.Done() { + return nil, xerrors.Errorf(initDkgFirst) + } + + ctx, cancel := context.WithTimeout(context.Background(), decryptTimeout) + defer cancel() + ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameDecrypt) + + players := mino.NewAddresses(a.startRes.getParticipants()...) + + sender, receiver, err := a.rpc.Stream(ctx, players) + if err != nil { + return nil, xerrors.Errorf(failedStreamCreation, err) + } + + iterator := players.AddressIterator() + addrs := make([]mino.Address, 0, players.Len()) + + for iterator.HasNext() { + addrs = append(addrs, iterator.GetNext()) + } + + txMsg := types.NewReencryptRequest(U, pubk) + + err = <-sender.Send(txMsg, addrs...) + if err != nil { + return nil, xerrors.Errorf("failed to send reencrypt request: %v", err) + } + + ocs := newOCS(pubk) + ocs.U = U + ocs.nbnodes = len(addrs) + ocs.threshold = ocs.nbnodes - 1 + + for i := 0; i < len(addrs); i++ { + src, rxMsg, err := receiver.Recv(ctx) + if err != nil { + return nil, xerrors.Errorf(unexpectedStreamStop, err) + } + + dela.Logger.Debug().Msgf("Received a decryption reply from %v", src) + + reply, ok := rxMsg.(types.ReencryptReply) + if !ok { + return nil, xerrors.Errorf("got unexpected reply, expected "+ + "%T but got: %T", reply, rxMsg) + } + + processReencryptReply(ocs, &reply) + } + + dela.Logger.Info().Msgf("Reencrypted message: %v", ocs.Uis) + + err = nil + return +} + +func processReencryptReply(ocs *OCS, reply *types.ReencryptReply) (err error) { + if reply.Ui == nil { + err = xerrors.Errorf("Received empty reply") + dela.Logger.Warn().Msg("Empty reply received") + ocs.nbfailures++ + if ocs.nbfailures > ocs.nbnodes-ocs.threshold { + err = xerrors.Errorf("couldn't get enough shares") + dela.Logger.Warn().Msg(err.Error()) + } + return err + } + + ocs.replies = append(ocs.replies, *reply) + + // minus one to exclude the root + if len(ocs.replies) >= int(ocs.threshold-1) { + ocs.Uis = make([]*share.PubShare, ocs.nbnodes) + ocs.Uis[0] = getUi(ocs, ocs.U, ocs.pubk) + + for _, r := range ocs.replies { + // Verify proofs + ufi := suite.Point().Mul(r.Fi, suite.Point().Add(ocs.U, ocs.pubk)) + uiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), r.Ui.V) + uiHat := suite.Point().Add(ufi, uiei) + + gfi := suite.Point().Mul(r.Fi, nil) + gxi := ocs.poly.Eval(r.Ui.I).V + hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) + hiHat := suite.Point().Add(gfi, hiei) + hash := sha256.New() + r.Ui.V.MarshalTo(hash) + uiHat.MarshalTo(hash) + hiHat.MarshalTo(hash) + e := suite.Scalar().SetBytes(hash.Sum(nil)) + if e.Equal(r.Ei) { + ocs.Uis[r.Ui.I] = r.Ui + } else { + dela.Logger.Warn().Msgf("Received invalid share from node: %v", r.Ui.I) + ocs.nbfailures++ + } + } + dela.Logger.Info().Msg("Reencryption completed") + return nil + } + + // If we are leaving by here it means that we do not have + // enough replies yet. We must eventually trigger a finish() + // somehow. It will either happen because we get another + // reply, and now we have enough, or because we get enough + // failures and know to give up, or because o.timeout triggers + // and calls finish(false) in it's callback function. + + err = xerrors.Errorf("not enough replies") + dela.Logger.Warn().Msg(err.Error()) + return err +} + +// DecryptSecret implements dkg.Actor. +func (a *Actor) DecryptSecret(Cs []kyber.Point, XhatEnc kyber.Point, Sk kyber.Scalar) (msg []byte, err error) { + pubK, err := a.GetPublicKey() + if err != nil { + dela.Logger.Error().Msgf("Cannot encrypt secret: %v", err.Error()) + } + + dela.Logger.Debug().Msgf("DKG pubK:%v", pubK) + dela.Logger.Debug().Msgf("XhatEnc:%v", XhatEnc) + dela.Logger.Debug().Msgf("xc:%v", Sk) + + xcInv := suite.Scalar().Neg(Sk) + dela.Logger.Debug().Msgf("xcInv:%v", xcInv) + + sum := suite.Scalar().Add(Sk, xcInv) + dela.Logger.Debug().Msgf("xc + xcInv: %v", sum) + + XhatDec := suite.Point().Mul(xcInv, pubK) + dela.Logger.Debug().Msgf("XhatDec:%v", XhatDec) + + Xhat := suite.Point().Add(XhatEnc, XhatDec) + dela.Logger.Debug().Msgf("Xhat:%v", Xhat) + + XhatInv := suite.Point().Neg(Xhat) + dela.Logger.Debug().Msgf("XhatInv:%v", XhatInv) + + // Decrypt Cs to keyPointHat + for _, C := range Cs { + dela.Logger.Debug().Msgf("C:%v", C) + + keyPointHat := suite.Point().Add(C, XhatInv) + dela.Logger.Debug().Msgf("keyPointHat:%v", keyPointHat) + + keyPart, err := keyPointHat.Data() + dela.Logger.Debug().Msgf("keyPart:%v", keyPart) + + if err != nil { + e := xerrors.Errorf("Error while decrypting Cs: %v", err) + dela.Logger.Error().Msg(e.Error()) + return nil, e + } + msg = append(msg, keyPart...) + } + return +} + // Reshare implements dkg.Actor. It recreates the DKG with an updated list of // participants. func (a *Actor) Reshare(co crypto.CollectiveAuthority, thresholdNew int) error { @@ -859,3 +849,20 @@ func union(el1 []mino.Address, el2 []mino.Address) []mino.Address { return addrsAll } + +func getUi(ocs *OCS, U, pubk kyber.Point) *share.PubShare { + v := suite.Point().Mul(ocs.shared.V, U) + v.Add(v, suite.Point().Mul(ocs.shared.V, pubk)) + return &share.PubShare{ + I: ocs.shared.I, + V: v, + } +} + +// Helper functions +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/dkg/pedersen/pedersen_test.go b/dkg/pedersen/pedersen_test.go index d9594ad74..57bc39e5e 100644 --- a/dkg/pedersen/pedersen_test.go +++ b/dkg/pedersen/pedersen_test.go @@ -1,7 +1,11 @@ package pedersen import ( - "go.dedis.ch/kyber/v3/group/edwards25519" + "fmt" + "go.dedis.ch/dela/mino/minoch" + "go.dedis.ch/kyber/v3/share" + "go.dedis.ch/kyber/v3/suites" + "go.dedis.ch/kyber/v3/util/key" "testing" "github.com/rs/zerolog" @@ -192,9 +196,6 @@ func TestPedersen_Scenario(t *testing.T) { pubkeys[i] = pubkey } - fakeAuthority := NewAuthority(addrs, pubkeys) - - message := []byte("Hello world") actors := make([]dkg.Actor, n) for i := 0; i < n; i++ { actor, err := dkgs[i].Listen() @@ -204,11 +205,15 @@ func TestPedersen_Scenario(t *testing.T) { } // trying to call a decrypt/encrypt before a setup + message := []byte("Hello world") + _, _, _, err := actors[0].Encrypt(message) require.EqualError(t, err, "you must first initialize DKG. Did you call setup() first?") _, err = actors[0].Decrypt(nil, nil) require.EqualError(t, err, "you must first initialize DKG. Did you call setup() first?") + fakeAuthority := NewAuthority(addrs, pubkeys) + _, err = actors[0].Setup(fakeAuthority, n) require.NoError(t, err) @@ -227,81 +232,67 @@ func TestPedersen_Scenario(t *testing.T) { } func TestPedersen_ReencryptScenario(t *testing.T) { + // Use with MINO_TRAFFIC=log + // traffic.LogItems = false + // traffic.LogEvent = false + // defer func() { + // traffic.SaveItems("graph.dot", true, false) + // traffic.SaveEvents("events.dot") + // }() + oldLog := dela.Logger defer func() { dela.Logger = oldLog }() - dela.Logger = dela.Logger.Level(zerolog.DebugLevel) - - n := 7 + dela.Logger = dela.Logger.Level(zerolog.WarnLevel) - minos := make([]mino.Mino, n) - dkgs := make([]dkg.DKG, n) - addrs := make([]mino.Address, n) + nbNodes := 7 - for i := 0; i < n; i++ { - addr := minogrpc.ParseAddress("127.0.0.1", 0) + minos := make([]mino.Mino, nbNodes) + dkgs := make([]dkg.DKG, nbNodes) + addrs := make([]mino.Address, nbNodes) - m, err := minogrpc.NewMinogrpc(addr, nil, tree.NewRouter(minogrpc.NewAddressFactory())) - require.NoError(t, err) + manager := minoch.NewManager() - defer m.GracefulStop() - - minos[i] = m - addrs[i] = m.GetAddress() + for i := 0; i < nbNodes; i++ { + minos[i] = minoch.MustCreate(manager, fmt.Sprint("node", i)) + addrs[i] = minos[i].GetAddress() } pubkeys := make([]kyber.Point, len(minos)) for i, mi := range minos { - for _, m := range minos { - mi.(*minogrpc.Minogrpc).GetCertificateStore().Store(m.GetAddress(), m.(*minogrpc.Minogrpc).GetCertificateChain()) - } - - d, pubkey := NewPedersen(mi.(*minogrpc.Minogrpc)) - + d, pubkey := NewPedersen(mi.(*minoch.Minoch)) dkgs[i] = d pubkeys[i] = pubkey } - fakeAuthority := NewAuthority(addrs, pubkeys) - - actors := make([]dkg.Actor, n) - for i := 0; i < n; i++ { + actors := make([]dkg.Actor, nbNodes) + for i := 0; i < nbNodes; i++ { actor, err := dkgs[i].Listen() require.NoError(t, err) actors[i] = actor } - // trying to call a reencrypt before a setup - _, _, _, err := actors[0].Reencrypt(nil, nil, nil) - require.EqualError(t, err, "you must first initialize DKG. Did you call setup() first?") - - _, err = actors[0].Setup(fakeAuthority, n) + fakeAuthority := NewAuthority(addrs, pubkeys) + _, err := actors[0].Setup(fakeAuthority, nbNodes) require.NoError(t, err) - suite := edwards25519.NewBlakeSHA256Ed25519() - - // Create a public/private keypair - privKey := suite.Scalar().Pick(suite.RandomStream()) - pubKey := suite.Point().Mul(privKey, nil) + // every node should be able to encrypt/reencrypt/decrypt + message := []byte("Hello world") + kp := key.NewKeyPair(suites.MustFind("Ed25519")) - // every node should be able to encrypt/reencrypt with new PUBK/decrypt with new privk - for i := 0; i < n; i++ { - //TODO: generate random message - message := []byte("Hello world") + for i := 0; i < nbNodes; i++ { + U, Cs := actors[i].EncryptSecret(message) - K, C, remainder, err := actors[i].Encrypt(message) + Uis, err := actors[i].ReencryptSecret(U, kp.Public) require.NoError(t, err) - require.Len(t, remainder, 0) - K, C, remainder, err = actors[i].Reencrypt(K, C, pubKey) - require.NoError(t, err) - require.Len(t, remainder, 0) + XhatEnc, err := share.RecoverCommit(suites.MustFind("Ed25519"), Uis, (2*nbNodes/3)+1, nbNodes) - decrypted, err := ed25519.ElGamalDecrypt(suite, privKey, K, C) + decrypted, err := actors[i].DecryptSecret(Cs, XhatEnc, kp.Private) require.NoError(t, err) require.Equal(t, message, decrypted) } diff --git a/dkg/pedersen/types/messages.go b/dkg/pedersen/types/messages.go index 20b807209..3591c77d3 100644 --- a/dkg/pedersen/types/messages.go +++ b/dkg/pedersen/types/messages.go @@ -440,24 +440,23 @@ func (req DecryptRequest) Serialize(ctx serde.Context) ([]byte, error) { return data, nil } -// ReencryptRequest is a message sent to request a reencryption. -// -// - implements serde.Message +// ReencryptRequest share sent to a node in order to +// reencrypt a secret with the given public key type ReencryptRequest struct { // U is the point from the write-request U kyber.Point - // Pk is the public key of the reader - Pk kyber.Point + // Xc is the public key of the reader + PubK kyber.Point // VerificationData is optional and can be any slice of bytes, so that each // node can verify if the reencryption request is valid or not. VerificationData *[]byte } // NewReencryptRequest creates a new decryption request. -func NewReencryptRequest(u, pk kyber.Point) ReencryptRequest { - return ReencryptRequest{ - U: u, - Pk: pk, +func NewReencryptRequest(u, pubk kyber.Point) *ReencryptRequest { + return &ReencryptRequest{ + U: u, + PubK: pubk, } } @@ -475,14 +474,15 @@ func (req ReencryptRequest) Serialize(ctx serde.Context) ([]byte, error) { // ReencryptReply returns the share to re-encrypt from one node type ReencryptReply struct { - Ui *share.PubShare - Ei kyber.Scalar - Fi kyber.Scalar + PubK kyber.Point + Ui *share.PubShare + Ei kyber.Scalar + Fi kyber.Scalar } // NewReencryptReply creates a new decryption request. -func NewReencryptReply(ui *share.PubShare, ei, fi kyber.Scalar) ReencryptReply { - return ReencryptReply{ +func NewReencryptReply(ui *share.PubShare, ei, fi kyber.Scalar) *ReencryptReply { + return &ReencryptReply{ Ui: ui, Ei: ei, Fi: fi, diff --git a/dkg/pedersen/verifiable_test.go b/dkg/pedersen/verifiable_test.go index 5afad4bc2..3f449f32e 100644 --- a/dkg/pedersen/verifiable_test.go +++ b/dkg/pedersen/verifiable_test.go @@ -2,8 +2,6 @@ package pedersen import ( "fmt" - "go.dedis.ch/dela/crypto/ed25519" - "go.dedis.ch/kyber/v3/group/edwards25519" "math/rand" "testing" "time" @@ -221,119 +219,6 @@ func Test_VerifiableEncDec_minogrpc(t *testing.T) { } } -func Test_VerifiableReencrypt_minogrpc(t *testing.T) { - // we want to time the decryption for different batch sizes with different - // number of nodes - - numWorkersSlice := []int{8} - batchSizeSlice := []int{32} - - // setting up the dkg - n := 7 - threshold := n - - minos := make([]mino.Mino, n) - dkgs := make([]dkg.DKG, n) - addrs := make([]mino.Address, n) - - // Create GBar. We need a generator in order to follow the encryption and - // decryption protocol of https://arxiv.org/pdf/2205.08529.pdf. We take an - // agreed data among the participants and embed it as a point. The result is - // the generator that we are seeking. - agreedData := make([]byte, 32) - _, err := rand.Read(agreedData) - require.NoError(t, err) - GBar := suite.Point().Embed(agreedData, keccak.New(agreedData)) - - t.Log("initiating the dkg nodes ...") - - for i := 0; i < n; i++ { - addr := minogrpc.ParseAddress("127.0.0.1", 0) - - minogrpc, err := minogrpc.NewMinogrpc(addr, nil, tree.NewRouter(minogrpc.NewAddressFactory())) - require.NoError(t, err) - - defer minogrpc.GracefulStop() - - minos[i] = minogrpc - addrs[i] = minogrpc.GetAddress() - } - - pubkeys := make([]kyber.Point, n) - - for i, mino := range minos { - for _, m := range minos { - mino.(*minogrpc.Minogrpc).GetCertificateStore().Store(m.GetAddress(), - m.(*minogrpc.Minogrpc).GetCertificateChain()) - } - dkg, pubkey := NewPedersen(mino.(*minogrpc.Minogrpc)) - dkgs[i] = dkg - pubkeys[i] = pubkey - } - - fakeAuthority := NewAuthority(addrs, pubkeys) - - actors := make([]dkg.Actor, n) - for i := 0; i < n; i++ { - actor, err := dkgs[i].Listen() - require.NoError(t, err) - actors[i] = actor - } - - t.Log("setting up the dkg ...") - - start := time.Now() - _, err = actors[0].Setup(fakeAuthority, threshold) - require.NoError(t, err) - setupTime := time.Since(start) - - // generating random messages in batch and encrypt them - for i, batchSize := range batchSizeSlice { - t.Logf("=== starting the process with batch size = %d === \n", batchSize) - - workerNum = numWorkersSlice[i] - - msg := make([][29]byte, batchSize) - var ciphertexts []types.Ciphertext - for i := 0; i < batchSize; i++ { - _, err = rand.Read(msg[i][:]) - require.NoError(t, err) - - ciphertext, remainder, err := actors[0].VerifiableEncrypt(msg[i][:], GBar) - require.NoError(t, err) - require.Len(t, remainder, 0) - - ciphertexts = append(ciphertexts, ciphertext) - } - - t.Log("reencrypting the batch ...") - - // create pub/priv key pair - var suite = edwards25519.NewBlakeSHA256Ed25519() - privKey := suite.Scalar().Pick(suite.RandomStream()) - pubKey := suite.Point().Mul(privKey, nil) - - start = time.Now() - reencrypted, rem, err := actors[0].VerifiableReencrypt(ciphertexts, pubKey) - //TODO what to do with rem here ? - reencryptionTime := time.Since(start) - require.NoError(t, err) - - for i := 0; i < batchSize; i++ { - //TODO verify this extraction ? - K := reencrypted[i].K - C := reencrypted[i].C - decrypted, err := ed25519.ElGamalDecrypt(suite, privKey, K, C) - require.NoError(t, err) - require.Equal(t, msg[i][:], decrypted[i]) - } - - t.Logf("n=%d, batchSize=%d, workerNum=%d, decryption time=%s, "+ - "throughput=%v[tx/s], dkg setup time=%s", n, batchSize, workerNum, - reencryptionTime, float64(batchSize)/reencryptionTime.Seconds(), setupTime) - } -} - func Test_VerifiableDecrypt_NotStarted(t *testing.T) { a := Actor{ startRes: &state{dkgState: initial}, From c6e89fd58fa0422c48616265beeb3c608ffc4b18 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 24 May 2023 17:02:56 +0200 Subject: [PATCH 06/34] working pederson test to reencrypt some data --- dkg/dkg.go | 2 +- dkg/pedersen/dkg.go | 2 +- dkg/pedersen/json/json.go | 46 +++++++-------- dkg/pedersen/pedersen.go | 100 ++++++++++++++++----------------- dkg/pedersen/pedersen_test.go | 6 +- dkg/pedersen/types/messages.go | 12 ++-- 6 files changed, 79 insertions(+), 89 deletions(-) diff --git a/dkg/dkg.go b/dkg/dkg.go index 9308542a8..e0b9edb2d 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -34,7 +34,7 @@ type Actor interface { VerifiableDecrypt(ciphertexts []types.Ciphertext) ([][]byte, error) EncryptSecret(message []byte) (U kyber.Point, Cs []kyber.Point) - ReencryptSecret(U kyber.Point, Pk kyber.Point) (Uis []*share.PubShare, err error) + ReencryptSecret(U kyber.Point, Pk kyber.Point, threshold int) (Uis []*share.PubShare, err error) DecryptSecret(Cs []kyber.Point, XhatEnc kyber.Point, Sk kyber.Scalar) (message []byte, err error) } diff --git a/dkg/pedersen/dkg.go b/dkg/pedersen/dkg.go index 596405b26..0038f14e3 100644 --- a/dkg/pedersen/dkg.go +++ b/dkg/pedersen/dkg.go @@ -818,7 +818,7 @@ func (s *instance) handleReencryptRequest(out mino.Sender, msg types.ReencryptRe ei := suite.Scalar().SetBytes(hash.Sum(nil)) fi := suite.Scalar().Add(si, suite.Scalar().Mul(ei, s.privShare.V)) - response := types.NewReencryptReply(ui, ei, fi) + response := types.NewReencryptReply(msg.PubK, ui, ei, fi) errs := out.Send(response, from) err := <-errs diff --git a/dkg/pedersen/json/json.go b/dkg/pedersen/json/json.go index 80bdd2205..cc1b8208f 100644 --- a/dkg/pedersen/json/json.go +++ b/dkg/pedersen/json/json.go @@ -105,14 +105,14 @@ type VerifiableDecryptReply struct { } type ReencryptRequest struct { - U []byte - PubK PublicKey - VerificationData *[]byte + U []byte + PubK PublicKey } type ReencryptReply struct { PubK PublicKey - Ui *share.PubShare + UiI []byte + UiV []byte Ei []byte Fi []byte } @@ -575,15 +575,9 @@ func encodeReencryptRequest(msg types.ReencryptRequest) (Message, error) { return Message{}, xerrors.Errorf("couldn't marshal PubK: %v", err) } - v, err := msg.VerificationData.MarshalBinary() - if err != nil { - return Message{}, xerrors.Errorf("couldn't marshal PubK: %v", err) - } - req := ReencryptRequest{ - U: u, - PubK: pubk, - VerificationData: v, + U: u, + PubK: pubk, } return Message{ReencryptRequest: &req}, nil @@ -595,7 +589,10 @@ func encodeReencryptReply(msg types.ReencryptReply) (Message, error) { return Message{}, xerrors.Errorf("couldn't marshal PubK: %v", err) } - ui, err := msg.Ui.MarshalBinary() + I := msg.Ui.I + i := []byte{byte(I >> 24), byte(I >> 16), byte(I >> 8), byte(I)} + + v, err := msg.Ui.V.MarshalBinary() if err != nil { return Message{}, xerrors.Errorf("couldn't marshal Ui: %v", err) } @@ -612,7 +609,8 @@ func encodeReencryptReply(msg types.ReencryptReply) (Message, error) { rep := ReencryptReply{ PubK: pubk, - Ui: ui, + UiI: i, + UiV: v, Ei: ei, Fi: fi, } @@ -875,22 +873,14 @@ func (f msgFormat) decodeReencryptRequest(ctx serde.Context, request *ReencryptR return nil, xerrors.Errorf("couldn't unmarshal PubK: %v", err) } - v := f.suite.Scalar() - err = v.UnmarshalBinary(request.VerificationData) - if err != nil { - return nil, xerrors.Errorf("couldn't marshal verification data: %v", err) - } - resp := types.ReencryptRequest{ - U: u, - PubK: pubk, - VerificationData: v, + U: u, + PubK: pubk, } return resp, nil } -// TODO implement func (f msgFormat) decodeReencryptReply(ctx serde.Context, reply *ReencryptReply) (serde.Message, error) { pubk := f.suite.Point() err := pubk.UnmarshalBinary(reply.PubK) @@ -898,12 +888,16 @@ func (f msgFormat) decodeReencryptReply(ctx serde.Context, reply *ReencryptReply return nil, xerrors.Errorf("couldn't unmarshal PubK: %v", err) } - ui := f.suite.Point() - err = ui.UnmarshalBinary(reply.Ui) + i := int(reply.UiI[0]<<24) + int(reply.UiI[1]<<16) + int(reply.UiI[2]<<8) + int(reply.UiI[3]) + + v := f.suite.Point() + err = v.UnmarshalBinary(reply.UiV) if err != nil { return nil, xerrors.Errorf("couldn't unmarshal Ui: %v", err) } + ui := &share.PubShare{i, v} + ei := f.suite.Scalar() err = ei.UnmarshalBinary(reply.Ei) if err != nil { diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 21ce6da54..e96f4fa5f 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -521,15 +521,15 @@ func (a *Actor) EncryptSecret(msg []byte) (U kyber.Point, Cs []kyber.Point) { } type OCS struct { - shared *share.PriShare // Shared represents the private key - poly *share.PubPoly // Represents all public keys - replies []types.ReencryptReply // replies received - U kyber.Point // U is the random part of the encrypted secret - pubk kyber.Point // The client's public key - nbnodes int // How many nodes participate in the distributed operations - nbfailures int // How many failures occurred so far - threshold int // How many replies are needed to re-create the secret - Uis []*share.PubShare // re-encrypted shares + U kyber.Point // U is the random part of the encrypted secret + pubk kyber.Point // The client's public key + + nbnodes int // How many nodes participate in the distributed operations + nbfailures int // How many failures occurred so far + threshold int // How many replies are needed to re-create the secret + + replies []types.ReencryptReply // replies received + Uis []*share.PubShare // re-encrypted shares } // newOCS creates a new on-chain secret structure. @@ -540,7 +540,7 @@ func newOCS(pubk kyber.Point) *OCS { } // ReencryptSecret implements dkg.Actor. -func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point) (Uis []*share.PubShare, err error) { +func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point, threshold int) (Uis []*share.PubShare, err error) { if !a.startRes.Done() { return nil, xerrors.Errorf(initDkgFirst) } @@ -573,7 +573,7 @@ func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point) (Uis []*share.P ocs := newOCS(pubk) ocs.U = U ocs.nbnodes = len(addrs) - ocs.threshold = ocs.nbnodes - 1 + ocs.threshold = threshold for i := 0; i < len(addrs); i++ { src, rxMsg, err := receiver.Recv(ctx) @@ -595,6 +595,7 @@ func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point) (Uis []*share.P dela.Logger.Info().Msgf("Reencrypted message: %v", ocs.Uis) err = nil + Uis = ocs.Uis return } @@ -612,32 +613,36 @@ func processReencryptReply(ocs *OCS, reply *types.ReencryptReply) (err error) { ocs.replies = append(ocs.replies, *reply) - // minus one to exclude the root - if len(ocs.replies) >= int(ocs.threshold-1) { - ocs.Uis = make([]*share.PubShare, ocs.nbnodes) - ocs.Uis[0] = getUi(ocs, ocs.U, ocs.pubk) + if len(ocs.replies) >= ocs.threshold { + ocs.Uis = make([]*share.PubShare, 0, ocs.nbnodes) for _, r := range ocs.replies { - // Verify proofs - ufi := suite.Point().Mul(r.Fi, suite.Point().Add(ocs.U, ocs.pubk)) - uiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), r.Ui.V) - uiHat := suite.Point().Add(ufi, uiei) - - gfi := suite.Point().Mul(r.Fi, nil) - gxi := ocs.poly.Eval(r.Ui.I).V - hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) - hiHat := suite.Point().Add(gfi, hiei) - hash := sha256.New() - r.Ui.V.MarshalTo(hash) - uiHat.MarshalTo(hash) - hiHat.MarshalTo(hash) - e := suite.Scalar().SetBytes(hash.Sum(nil)) - if e.Equal(r.Ei) { - ocs.Uis[r.Ui.I] = r.Ui - } else { - dela.Logger.Warn().Msgf("Received invalid share from node: %v", r.Ui.I) - ocs.nbfailures++ - } + + /* + // Verify proofs + ufi := suite.Point().Mul(r.Fi, suite.Point().Add(ocs.U, ocs.pubk)) + uiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), r.Ui.V) + uiHat := suite.Point().Add(ufi, uiei) + + gfi := suite.Point().Mul(r.Fi, nil) + gxi := ocs.poly.Eval(r.Ui.I).V + hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) + hiHat := suite.Point().Add(gfi, hiei) + hash := sha256.New() + r.Ui.V.MarshalTo(hash) + uiHat.MarshalTo(hash) + hiHat.MarshalTo(hash) + e := suite.Scalar().SetBytes(hash.Sum(nil)) + if e.Equal(r.Ei) { + + */ + ocs.Uis = append(ocs.Uis, r.Ui) + /* + } else { + dela.Logger.Warn().Msgf("Received invalid share from node: %v", r.Ui.I) + ocs.nbfailures++ + } + */ } dela.Logger.Info().Msg("Reencryption completed") return nil @@ -655,6 +660,14 @@ func processReencryptReply(ocs *OCS, reply *types.ReencryptReply) (err error) { return err } +// Helper functions +func min(a, b int) int { + if a < b { + return a + } + return b +} + // DecryptSecret implements dkg.Actor. func (a *Actor) DecryptSecret(Cs []kyber.Point, XhatEnc kyber.Point, Sk kyber.Scalar) (msg []byte, err error) { pubK, err := a.GetPublicKey() @@ -849,20 +862,3 @@ func union(el1 []mino.Address, el2 []mino.Address) []mino.Address { return addrsAll } - -func getUi(ocs *OCS, U, pubk kyber.Point) *share.PubShare { - v := suite.Point().Mul(ocs.shared.V, U) - v.Add(v, suite.Point().Mul(ocs.shared.V, pubk)) - return &share.PubShare{ - I: ocs.shared.I, - V: v, - } -} - -// Helper functions -func min(a, b int) int { - if a < b { - return a - } - return b -} diff --git a/dkg/pedersen/pedersen_test.go b/dkg/pedersen/pedersen_test.go index 57bc39e5e..a4fcf2e72 100644 --- a/dkg/pedersen/pedersen_test.go +++ b/dkg/pedersen/pedersen_test.go @@ -248,6 +248,7 @@ func TestPedersen_ReencryptScenario(t *testing.T) { dela.Logger = dela.Logger.Level(zerolog.WarnLevel) nbNodes := 7 + threshold := (2 * nbNodes / 3) + 1 minos := make([]mino.Mino, nbNodes) dkgs := make([]dkg.DKG, nbNodes) @@ -287,10 +288,11 @@ func TestPedersen_ReencryptScenario(t *testing.T) { for i := 0; i < nbNodes; i++ { U, Cs := actors[i].EncryptSecret(message) - Uis, err := actors[i].ReencryptSecret(U, kp.Public) + Uis, err := actors[i].ReencryptSecret(U, kp.Public, threshold) require.NoError(t, err) + require.NotNil(t, Uis) - XhatEnc, err := share.RecoverCommit(suites.MustFind("Ed25519"), Uis, (2*nbNodes/3)+1, nbNodes) + XhatEnc, err := share.RecoverCommit(suites.MustFind("Ed25519"), Uis, threshold, nbNodes) decrypted, err := actors[i].DecryptSecret(Cs, XhatEnc, kp.Private) require.NoError(t, err) diff --git a/dkg/pedersen/types/messages.go b/dkg/pedersen/types/messages.go index 3591c77d3..37044ad30 100644 --- a/dkg/pedersen/types/messages.go +++ b/dkg/pedersen/types/messages.go @@ -447,9 +447,6 @@ type ReencryptRequest struct { U kyber.Point // Xc is the public key of the reader PubK kyber.Point - // VerificationData is optional and can be any slice of bytes, so that each - // node can verify if the reencryption request is valid or not. - VerificationData *[]byte } // NewReencryptRequest creates a new decryption request. @@ -481,11 +478,12 @@ type ReencryptReply struct { } // NewReencryptReply creates a new decryption request. -func NewReencryptReply(ui *share.PubShare, ei, fi kyber.Scalar) *ReencryptReply { +func NewReencryptReply(pubk kyber.Point, ui *share.PubShare, ei, fi kyber.Scalar) *ReencryptReply { return &ReencryptReply{ - Ui: ui, - Ei: ei, - Fi: fi, + PubK: pubk, + Ui: ui, + Ei: ei, + Fi: fi, } } From 2ec15f6c8fbded20e5f3bb96d7b469d965327f12 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Tue, 30 May 2023 16:03:54 +0200 Subject: [PATCH 07/34] fixed lint warnings --- dkg/pedersen/controller/action.go | 57 --------------------------- dkg/pedersen/controller/controller.go | 2 +- dkg/pedersen/json/json.go | 2 +- dkg/pedersen/pedersen_test.go | 1 + dkg/pedersen/state.go | 7 ++-- 5 files changed, 6 insertions(+), 63 deletions(-) diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index bb8f752b8..f8e2ba45c 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -230,63 +230,6 @@ func (a decryptAction) Execute(ctx node.Context) error { return nil } -type reencryptAction struct{} - -func (a reencryptAction) Execute(ctx node.Context) error { - var actor dkg.Actor - - err := ctx.Injector.Resolve(&actor) - if err != nil { - return xerrors.Errorf(resolveActorFailed, err) - } - - // first, let's reencrypt the given data - encrypted := ctx.Flags.String("encrypted") - - k, c, err := decodeEncrypted(encrypted) - if err != nil { - return xerrors.Errorf("failed to decode encrypted str: %v", err) - } - - publickey := ctx.Flags.String("publickey") - - pk, err := decodePublickey(publickey) - if err != nil { - return xerrors.Errorf("failed to decode public key str: %v", err) - } - - k, c, remainder, err := actor.Reencrypt(k, c, pk) - if err != nil { - return xerrors.Errorf("failed to reencrypt: %v", err) - } - - outStr, err := encodeEncrypted(k, c, remainder) - if err != nil { - return xerrors.Errorf("failed to generate output: %v", err) - } - - fmt.Fprint(ctx.Out, outStr) - - return nil -} - -func decodePublickey(str string) (pk kyber.Point, err error) { - // Decode public key - publickey, err := hex.DecodeString(str) - if err != nil { - return nil, xerrors.Errorf("failed to decode pk: %v", err) - } - - pk = suite.Point() - - err = pk.UnmarshalBinary(publickey) - if err != nil { - return nil, xerrors.Errorf("failed to unmarshal pk point: %v", err) - } - - return pk, nil -} - func encodeEncrypted(k, c kyber.Point, remainder []byte) (string, error) { kbuff, err := k.MarshalBinary() if err != nil { diff --git a/dkg/pedersen/controller/controller.go b/dkg/pedersen/controller/controller.go index 65febdd02..4fcabceb7 100644 --- a/dkg/pedersen/controller/controller.go +++ b/dkg/pedersen/controller/controller.go @@ -79,7 +79,7 @@ func (m minimal) SetCommands(builder node.Builder) { Usage: "the new public key to reencrypt the message, as ", }, ) - sub.SetAction(builder.MakeAction(reencryptAction{})) + //TODO sub.SetAction(builder.MakeAction(reencryptAction{})) sub = cmd.SetSubCommand("verifiableEncrypt") sub.SetDescription("encrypt a message and provides a proof. " + diff --git a/dkg/pedersen/json/json.go b/dkg/pedersen/json/json.go index cc1b8208f..c371cf91a 100644 --- a/dkg/pedersen/json/json.go +++ b/dkg/pedersen/json/json.go @@ -888,7 +888,7 @@ func (f msgFormat) decodeReencryptReply(ctx serde.Context, reply *ReencryptReply return nil, xerrors.Errorf("couldn't unmarshal PubK: %v", err) } - i := int(reply.UiI[0]<<24) + int(reply.UiI[1]<<16) + int(reply.UiI[2]<<8) + int(reply.UiI[3]) + i := int(reply.UiI[0])<<24 + int(reply.UiI[1])<<16 + int(reply.UiI[2])<<8 + int(reply.UiI[3]) v := f.suite.Point() err = v.UnmarshalBinary(reply.UiV) diff --git a/dkg/pedersen/pedersen_test.go b/dkg/pedersen/pedersen_test.go index a4fcf2e72..02bb78c8b 100644 --- a/dkg/pedersen/pedersen_test.go +++ b/dkg/pedersen/pedersen_test.go @@ -293,6 +293,7 @@ func TestPedersen_ReencryptScenario(t *testing.T) { require.NotNil(t, Uis) XhatEnc, err := share.RecoverCommit(suites.MustFind("Ed25519"), Uis, threshold, nbNodes) + require.NoError(t, err) decrypted, err := actors[i].DecryptSecret(Cs, XhatEnc, kp.Private) require.NoError(t, err) diff --git a/dkg/pedersen/state.go b/dkg/pedersen/state.go index 0490a5ebf..f195c954a 100644 --- a/dkg/pedersen/state.go +++ b/dkg/pedersen/state.go @@ -3,7 +3,6 @@ package pedersen import ( "go.dedis.ch/dela/mino" "go.dedis.ch/kyber/v3" - "go.dedis.ch/kyber/v3/share" "golang.org/x/xerrors" "sync" ) @@ -51,9 +50,9 @@ type state struct { // participants is set once a sharing or resharing starts participants []mino.Address pubkeys []kyber.Point - poly *share.PubPoly // TODO: is it the right place for reencrypt ? - threshold int - dkgState dkgState + //TODO add verifiability (poly *share.PubPoly) + threshold int + dkgState dkgState } func (s *state) switchState(new dkgState) error { From 2efa54a208049635e570250ba0561d57c7bee421 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 31 May 2023 13:25:32 +0200 Subject: [PATCH 08/34] fix go vet: avoid output like comment too long in libc --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e1ed898a6..8215471a8 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ lint: tidy vet: tidy @echo "⚠️ Warning: the following only works with go >= 1.14" && \ go install ./internal/mcheck && \ - go vet -vettool=`go env GOPATH`/bin/mcheck -commentLen -ifInit ./... + go vet -vettool=`go env GOPATH`/bin/mcheck -ifInit ./... # test runs all tests in DELA without coverage test: tidy From e73a8a357666944a19b2ad8a5bd0bb5f430a5840 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Mon, 5 Jun 2023 08:53:41 +0200 Subject: [PATCH 09/34] clean up --- crypto/ed25519/ed25519.go | 10 ---------- dkg/pedersen/controller/controller.go | 26 +++++++++++++------------- dkg/pedersen/dkg_test.go | 18 ++++++++++++------ dkg/pedersen/json/json.go | 1 - dkg/pedersen/pedersen.go | 13 +++++++------ 5 files changed, 32 insertions(+), 36 deletions(-) diff --git a/crypto/ed25519/ed25519.go b/crypto/ed25519/ed25519.go index 9ea18bb6d..ea56b6c30 100644 --- a/crypto/ed25519/ed25519.go +++ b/crypto/ed25519/ed25519.go @@ -328,13 +328,3 @@ func (s Signer) Sign(msg []byte) (crypto.Signature, error) { return Signature{data: sig}, nil } - -func ElGamalDecrypt(group kyber.Group, prikey kyber.Scalar, K, C kyber.Point) ( - message []byte, err error) { - - // ElGamal-decrypt the ciphertext (K,C) to reproduce the message. - S := group.Point().Mul(prikey, K) // regenerate shared secret - M := group.Point().Sub(C, S) // use to un-blind the message - message, err = M.Data() // extract the embedded data - return -} diff --git a/dkg/pedersen/controller/controller.go b/dkg/pedersen/controller/controller.go index 4fcabceb7..296113290 100644 --- a/dkg/pedersen/controller/controller.go +++ b/dkg/pedersen/controller/controller.go @@ -67,19 +67,19 @@ func (m minimal) SetCommands(builder node.Builder) { ) sub.SetAction(builder.MakeAction(decryptAction{})) - sub = cmd.SetSubCommand("reencrypt") - sub.SetDescription("reencrypt a message") - sub.SetFlags( - cli.StringFlag{ - Name: "encrypted", - Usage: "the encrypted string, as :", - }, - cli.StringFlag{ - Name: "publickey", - Usage: "the new public key to reencrypt the message, as ", - }, - ) - //TODO sub.SetAction(builder.MakeAction(reencryptAction{})) + //sub = cmd.SetSubCommand("reencrypt") + //sub.SetDescription("reencrypt a message") + //sub.SetFlags( + // cli.StringFlag{ + // Name: "encrypted", + // Usage: "the encrypted string, as :", + // }, + // cli.StringFlag{ + // Name: "publickey", + // Usage: "the new public key to reencrypt the message, as ", + // }, + //) + //sub.SetAction(builder.MakeAction(reencryptAction{})) sub = cmd.SetSubCommand("verifiableEncrypt") sub.SetDescription("encrypt a message and provides a proof. " + diff --git a/dkg/pedersen/dkg_test.go b/dkg/pedersen/dkg_test.go index 08d7c7843..7d8e4e5c8 100644 --- a/dkg/pedersen/dkg_test.go +++ b/dkg/pedersen/dkg_test.go @@ -168,12 +168,18 @@ func TestDKGInstance_Start(t *testing.T) { require.EqualError(t, err, "there should be as many participants as pubKey: 1 != 0") s.startRes.dkgState = initial - - start = types.NewStart(2, []mino.Address{fake.NewAddress(0), - fake.NewAddress(1)}, []kyber.Point{pubKey, suite.Point()}) - - ctx, cancel := context.WithCancel(context.Background()) - cancel() + s.startRes.threshold = 2 + + start = types.NewStart(2, + []mino.Address{ + fake.NewAddress(0), + fake.NewAddress(1)}, + []kyber.Point{ + pubKey, + suite.Point()}) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) + defer cancel() err = s.start(ctx, start, channel.Timed[types.Deal]{}, channel.Timed[types.Response]{}, from, fake.Sender{}) diff --git a/dkg/pedersen/json/json.go b/dkg/pedersen/json/json.go index c371cf91a..49ec7e597 100644 --- a/dkg/pedersen/json/json.go +++ b/dkg/pedersen/json/json.go @@ -859,7 +859,6 @@ func (f msgFormat) decodeVerifiableDecryptReply(ctx serde.Context, return resp, nil } -// TODO implement func (f msgFormat) decodeReencryptRequest(ctx serde.Context, request *ReencryptRequest) (serde.Message, error) { u := f.suite.Point() err := u.UnmarshalBinary(request.U) diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index e96f4fa5f..210c2d3cf 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -1,6 +1,5 @@ package pedersen -import "C" import ( "crypto/sha256" "runtime" @@ -45,8 +44,8 @@ var ( // associated with the `dkg-decrypt` protocol. protocolNameDecrypt = "dkg-decrypt" // protocolNameReencrypt denotes the value of the protocol span tag - // associated with the `dkg-reencrypt` protocol. - protocolNameReencrypt = "dkg-reencrypt" + //// associated with the `dkg-reencrypt` protocol. + //protocolNameReencrypt = "dkg-reencrypt" // ProtocolNameResharing denotes the value of the protocol span tag // associated with the `dkg-resharing` protocol. protocolNameResharing = "dkg-resharing" @@ -57,7 +56,6 @@ var ( const ( setupTimeout = time.Minute * 50 decryptTimeout = time.Minute * 5 - reencryptTimeout = time.Minute * 5 resharingTimeout = time.Minute * 5 ) @@ -589,7 +587,10 @@ func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point, threshold int) "%T but got: %T", reply, rxMsg) } - processReencryptReply(ocs, &reply) + err = processReencryptReply(ocs, &reply) + if err != nil { + return nil, xerrors.Errorf("Reencryption failed: %v", err) + } } dela.Logger.Info().Msgf("Reencrypted message: %v", ocs.Uis) @@ -653,7 +654,7 @@ func processReencryptReply(ocs *OCS, reply *types.ReencryptReply) (err error) { // somehow. It will either happen because we get another // reply, and now we have enough, or because we get enough // failures and know to give up, or because o.timeout triggers - // and calls finish(false) in it's callback function. + // and calls finish(false) in its callback function. err = xerrors.Errorf("not enough replies") dela.Logger.Warn().Msg(err.Error()) From 3643363f1b1f4e75e51cb9a446d4002fda918d3f Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Mon, 5 Jun 2023 10:40:47 +0200 Subject: [PATCH 10/34] fixed TestDKGInstance --- dkg/pedersen/dkg.go | 16 ++++++++-------- dkg/pedersen/dkg_test.go | 7 +++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/dkg/pedersen/dkg.go b/dkg/pedersen/dkg.go index 0038f14e3..022835472 100644 --- a/dkg/pedersen/dkg.go +++ b/dkg/pedersen/dkg.go @@ -220,7 +220,7 @@ func (s *instance) start(ctx context.Context, start types.Start, deals channel.T err = s.doDKG(ctx, deals, resps, out, from) if err != nil { - xerrors.Errorf("something went wrong during DKG: %v", err) + return xerrors.Errorf("something went wrong during DKG: %v", err) } return nil @@ -522,7 +522,7 @@ func (s *instance) reshare(ctx context.Context, out mino.Sender, err = s.doReshare(ctx, msg, from, out, reshares, resps) if err != nil { - xerrors.Errorf("failed to reshare: %v", err) + return xerrors.Errorf("failed to reshare: %v", err) } return nil @@ -552,7 +552,7 @@ func (s *instance) doReshare(ctx context.Context, start types.StartResharing, switch nt { case oldNode: // Update local DKG for resharing - share, err := s.dkg.DistKeyShare() + distKeyShare, err := s.dkg.DistKeyShare() if err != nil { return xerrors.Errorf("old node failed to create: %v", err) } @@ -564,7 +564,7 @@ func (s *instance) doReshare(ctx context.Context, start types.StartResharing, Longterm: s.privKey, OldNodes: s.startRes.getPublicKeys(), NewNodes: start.GetPubkeysNew(), - Share: share, + Share: distKeyShare, Threshold: start.GetTNew(), OldThreshold: s.startRes.getThreshold(), } @@ -577,7 +577,7 @@ func (s *instance) doReshare(ctx context.Context, start types.StartResharing, s.dkg = d // Send my Deals to the new and common nodes - err = s.sendDealsResharing(ctx, out, addrsNew, share.Commits) + err = s.sendDealsResharing(ctx, out, addrsNew, distKeyShare.Commits) if err != nil { return xerrors.Errorf("old node failed to send deals: %v", err) } @@ -586,7 +586,7 @@ func (s *instance) doReshare(ctx context.Context, start types.StartResharing, case commonNode: // Update local DKG for resharing - share, err := s.dkg.DistKeyShare() + distKeyShare, err := s.dkg.DistKeyShare() if err != nil { return xerrors.Errorf("common node failed to create: %v", err) } @@ -598,7 +598,7 @@ func (s *instance) doReshare(ctx context.Context, start types.StartResharing, Longterm: s.privKey, OldNodes: s.startRes.getPublicKeys(), NewNodes: start.GetPubkeysNew(), - Share: share, + Share: distKeyShare, Threshold: start.GetTNew(), OldThreshold: s.startRes.getThreshold(), } @@ -611,7 +611,7 @@ func (s *instance) doReshare(ctx context.Context, start types.StartResharing, s.dkg = d // Send my Deals to the new and common nodes - err = s.sendDealsResharing(ctx, out, addrsNew, share.Commits) + err = s.sendDealsResharing(ctx, out, addrsNew, distKeyShare.Commits) if err != nil { return xerrors.Errorf("common node failed to send deals: %v", err) } diff --git a/dkg/pedersen/dkg_test.go b/dkg/pedersen/dkg_test.go index 7d8e4e5c8..8f652aaf2 100644 --- a/dkg/pedersen/dkg_test.go +++ b/dkg/pedersen/dkg_test.go @@ -150,7 +150,7 @@ func TestDKGInstance_StartFailNewDKG(t *testing.T) { require.EqualError(t, err, "failed to create new DKG: dkg: can't run with empty node list") } -func TestDKGInstance_Start(t *testing.T) { +func TestDKGInstance_StartFailDeal(t *testing.T) { privKey := suite.Scalar().Pick(suite.RandomStream()) pubKey := suite.Point().Mul(privKey, nil) @@ -183,7 +183,10 @@ func TestDKGInstance_Start(t *testing.T) { err = s.start(ctx, start, channel.Timed[types.Deal]{}, channel.Timed[types.Response]{}, from, fake.Sender{}) - require.NoError(t, err) + require.ErrorContains(t, err, + "something went wrong during DKG: failed to respond") + // this actually ensures that the start occurred successfully, + // but the DKG execution failed because deals are not sent. } func TestDKGInstance_doDKG_DealFail(t *testing.T) { From b7776f8d77d703945b77d459a20e9b31e472c1b6 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Mon, 5 Jun 2023 11:34:40 +0200 Subject: [PATCH 11/34] reencryption works --- dkg/pedersen/pedersen.go | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 210c2d3cf..3eaa070ab 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -588,16 +588,14 @@ func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point, threshold int) } err = processReencryptReply(ocs, &reply) - if err != nil { - return nil, xerrors.Errorf("Reencryption failed: %v", err) + if err == nil { + dela.Logger.Info().Msgf("Reencrypted message: %v", ocs.Uis) + + return ocs.Uis, nil } } - dela.Logger.Info().Msgf("Reencrypted message: %v", ocs.Uis) - - err = nil - Uis = ocs.Uis - return + return nil, xerrors.Errorf("Reencryption failed: %v", err) } func processReencryptReply(ocs *OCS, reply *types.ReencryptReply) (err error) { @@ -657,7 +655,7 @@ func processReencryptReply(ocs *OCS, reply *types.ReencryptReply) (err error) { // and calls finish(false) in its callback function. err = xerrors.Errorf("not enough replies") - dela.Logger.Warn().Msg(err.Error()) + dela.Logger.Debug().Msg(err.Error()) return err } From e72586cba0645ac0f2cded16fda5813447b1d038 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Mon, 5 Jun 2023 11:39:03 +0200 Subject: [PATCH 12/34] restaured comment length in go vet --- Makefile | 2 +- dkg/pedersen/pedersen.go | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 8215471a8..e1ed898a6 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ lint: tidy vet: tidy @echo "⚠️ Warning: the following only works with go >= 1.14" && \ go install ./internal/mcheck && \ - go vet -vettool=`go env GOPATH`/bin/mcheck -ifInit ./... + go vet -vettool=`go env GOPATH`/bin/mcheck -commentLen -ifInit ./... # test runs all tests in DELA without coverage test: tidy diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 3eaa070ab..f0caa8768 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -637,10 +637,12 @@ func processReencryptReply(ocs *OCS, reply *types.ReencryptReply) (err error) { */ ocs.Uis = append(ocs.Uis, r.Ui) /* - } else { - dela.Logger.Warn().Msgf("Received invalid share from node: %v", r.Ui.I) - ocs.nbfailures++ - } + } + else + { + dela.Logger.Warn().Msgf("Received invalid share from node: %v", r.Ui.I) + ocs.nbfailures++ + } */ } dela.Logger.Info().Msg("Reencryption completed") From 1cea29e6daf2771d76b9ee8192d46bf1f0ca3b1a Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Mon, 5 Jun 2023 13:39:32 +0200 Subject: [PATCH 13/34] reduce sonar warnings --- dkg/pedersen/pedersen.go | 12 ++++++------ dkg/pedersen/types/messages.go | 10 +++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index f0caa8768..ec5e98bfd 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -33,6 +33,9 @@ const failedStreamCreation = "failed to create stream: %v" // unexpectedStreamStop message indicating that a stream stopped unexpectedly const unexpectedStreamStop = "stream stopped unexpectedly: %v" +// unexpectedReply message indicating that a reply was not expected +const unexpectedReply = "got unexpected reply, expected %T but got: %T" + // suite is the Kyber suite for Pedersen. var suite = suites.MustFind("Ed25519") @@ -260,8 +263,7 @@ func (a *Actor) Decrypt(K, C kyber.Point) ([]byte, error) { decryptReply, ok := message.(types.DecryptReply) if !ok { - return []byte{}, xerrors.Errorf("got unexpected reply, expected "+ - "%T but got: %T", decryptReply, message) + return []byte{}, xerrors.Errorf(unexpectedReply, decryptReply, message) } pubShares[i] = &share.PubShare{ @@ -393,8 +395,7 @@ func (a *Actor) VerifiableDecrypt(ciphertexts []types.Ciphertext) ([][]byte, err shareAndProof, ok := message.(types.VerifiableDecryptReply) if !ok { - return nil, xerrors.Errorf("got unexpected reply, expected "+ - "%T but got: %T", shareAndProof, message) + return nil, xerrors.Errorf(unexpectedReply, shareAndProof, message) } responses[i] = shareAndProof @@ -583,8 +584,7 @@ func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point, threshold int) reply, ok := rxMsg.(types.ReencryptReply) if !ok { - return nil, xerrors.Errorf("got unexpected reply, expected "+ - "%T but got: %T", reply, rxMsg) + return nil, xerrors.Errorf(unexpectedReply, reply, rxMsg) } err = processReencryptReply(ocs, &reply) diff --git a/dkg/pedersen/types/messages.go b/dkg/pedersen/types/messages.go index 37044ad30..c6d41b08b 100644 --- a/dkg/pedersen/types/messages.go +++ b/dkg/pedersen/types/messages.go @@ -9,6 +9,10 @@ import ( "golang.org/x/xerrors" ) +// couldntEncodeDecryptRequest indicates that a decrypt request couldn't be +// encoded +const couldntEncodeDecryptRequest = "couldn't encode decrypt request: %v" + // Ciphertext provides the verifiable encryption function. A description can be // found in https://arxiv.org/pdf/2205.08529.pdf. The equivalent of each // parameter in the paper is written in front of it. @@ -434,7 +438,7 @@ func (req DecryptRequest) Serialize(ctx serde.Context) ([]byte, error) { data, err := format.Encode(ctx, req) if err != nil { - return nil, xerrors.Errorf("couldn't encode decrypt request: %v", err) + return nil, xerrors.Errorf(couldntEncodeDecryptRequest, err) } return data, nil @@ -463,7 +467,7 @@ func (req ReencryptRequest) Serialize(ctx serde.Context) ([]byte, error) { data, err := format.Encode(ctx, req) if err != nil { - return nil, xerrors.Errorf("couldn't encode decrypt request: %v", err) + return nil, xerrors.Errorf(couldntEncodeDecryptRequest, err) } return data, nil @@ -493,7 +497,7 @@ func (req ReencryptReply) Serialize(ctx serde.Context) ([]byte, error) { data, err := format.Encode(ctx, req) if err != nil { - return nil, xerrors.Errorf("couldn't encode decrypt request: %v", err) + return nil, xerrors.Errorf(couldntEncodeDecryptRequest, err) } return data, nil From df635fa2cc592e3b75f1a818bd64d21547eb0e5f Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Mon, 5 Jun 2023 13:59:20 +0200 Subject: [PATCH 14/34] cleanups --- dkg/pedersen/dkg.go | 8 +++++--- dkg/pedersen/dkg_test.go | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dkg/pedersen/dkg.go b/dkg/pedersen/dkg.go index 022835472..04e18a1d3 100644 --- a/dkg/pedersen/dkg.go +++ b/dkg/pedersen/dkg.go @@ -281,6 +281,7 @@ func (s *instance) deal(ctx context.Context, out mino.Sender) error { return xerrors.Errorf("failed to compute the deals: %v", err) } + participants := s.startRes.getParticipants() for i, deal := range deals { dealMsg := types.NewDeal( deal.Index, @@ -293,7 +294,7 @@ func (s *instance) deal(ctx context.Context, out mino.Sender) error { ), ) - to := s.startRes.getParticipants()[i] + to := participants[i] s.log.Trace().Str("to", to.String()).Msg("send deal") @@ -316,13 +317,14 @@ func (s *instance) deal(ctx context.Context, out mino.Sender) error { func (s *instance) respond(ctx context.Context, deals channel.Timed[types.Deal], out mino.Sender) error { numReceivedDeals := 0 - for numReceivedDeals < len(s.startRes.getParticipants())-1 { + participants := s.startRes.getParticipants() + for numReceivedDeals < len(participants)-1 { deal, err := deals.NonBlockingReceiveWithContext(ctx) if err != nil { return xerrors.Errorf("context done: %v", err) } - err = s.handleDeal(ctx, deal, out, s.startRes.getParticipants()) + err = s.handleDeal(ctx, deal, out, participants) if err != nil { return xerrors.Errorf("failed to handle received deal: %v", err) } diff --git a/dkg/pedersen/dkg_test.go b/dkg/pedersen/dkg_test.go index 8f652aaf2..a15107025 100644 --- a/dkg/pedersen/dkg_test.go +++ b/dkg/pedersen/dkg_test.go @@ -178,7 +178,7 @@ func TestDKGInstance_StartFailDeal(t *testing.T) { pubKey, suite.Point()}) - ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() err = s.start(ctx, start, channel.Timed[types.Deal]{}, From 5ce9b505c9f6423e86bbce967169c3a4b6b115fc Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Tue, 13 Jun 2023 17:29:05 +0200 Subject: [PATCH 15/34] tidy up code after review --- dkg/dkg.go | 19 ++- dkg/pedersen/controller/controller.go | 14 --- dkg/pedersen/ocs.go | 169 ++++++++++++++++++++++++++ dkg/pedersen/pedersen.go | 150 ----------------------- dkg/pedersen/pedersen_test.go | 11 +- 5 files changed, 189 insertions(+), 174 deletions(-) create mode 100644 dkg/pedersen/ocs.go diff --git a/dkg/dkg.go b/dkg/dkg.go index e0b9edb2d..4ba070226 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -4,7 +4,6 @@ import ( "go.dedis.ch/dela/crypto" "go.dedis.ch/dela/dkg/pedersen/types" "go.dedis.ch/kyber/v3" - "go.dedis.ch/kyber/v3/share" ) // DKG defines the primitive to start a DKG protocol @@ -25,16 +24,32 @@ type Actor interface { // setup has not been done. GetPublicKey() (kyber.Point, error) + // Encrypt encrypts the given message into kyber points + // using the DKG public key Encrypt(message []byte) (K, C kyber.Point, remainder []byte, err error) + // Decrypt decrypts a pair of kyber points into the original message + // using the DKG internal private key Decrypt(K, C kyber.Point) ([]byte, error) + // Reshare recreates the DKG with an updated list of participants. Reshare(co crypto.CollectiveAuthority, newThreshold int) error + // VerifiableEncrypt encrypts the given message into kyber points + // using the DKG public key and proof of work algorithm. VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext types.Ciphertext, remainder []byte, err error) + + // VerifiableDecrypt decrypts a pair of kyber points into the original message + // using the DKG internal private key and a proof of work algorithm. VerifiableDecrypt(ciphertexts []types.Ciphertext) ([][]byte, error) + // EncryptSecret encrypts the given message the calypso way EncryptSecret(message []byte) (U kyber.Point, Cs []kyber.Point) - ReencryptSecret(U kyber.Point, Pk kyber.Point, threshold int) (Uis []*share.PubShare, err error) + // ReencryptSecret is the first version of the calypso + // reencryption algorithm in DELA + ReencryptSecret(U kyber.Point, Pk kyber.Point) (XhatEnc kyber.Point, err error) + + // DecryptSecret is a helper function to decrypt a secret message previously + // encrypted and reencrypted by the DKG DecryptSecret(Cs []kyber.Point, XhatEnc kyber.Point, Sk kyber.Scalar) (message []byte, err error) } diff --git a/dkg/pedersen/controller/controller.go b/dkg/pedersen/controller/controller.go index 296113290..c23897e27 100644 --- a/dkg/pedersen/controller/controller.go +++ b/dkg/pedersen/controller/controller.go @@ -67,20 +67,6 @@ func (m minimal) SetCommands(builder node.Builder) { ) sub.SetAction(builder.MakeAction(decryptAction{})) - //sub = cmd.SetSubCommand("reencrypt") - //sub.SetDescription("reencrypt a message") - //sub.SetFlags( - // cli.StringFlag{ - // Name: "encrypted", - // Usage: "the encrypted string, as :", - // }, - // cli.StringFlag{ - // Name: "publickey", - // Usage: "the new public key to reencrypt the message, as ", - // }, - //) - //sub.SetAction(builder.MakeAction(reencryptAction{})) - sub = cmd.SetSubCommand("verifiableEncrypt") sub.SetDescription("encrypt a message and provides a proof. " + "Outputs :::::") diff --git a/dkg/pedersen/ocs.go b/dkg/pedersen/ocs.go new file mode 100644 index 000000000..cfb08b45a --- /dev/null +++ b/dkg/pedersen/ocs.go @@ -0,0 +1,169 @@ +package pedersen + +import ( + "go.dedis.ch/dela" + "go.dedis.ch/dela/dkg/pedersen/types" + "go.dedis.ch/dela/internal/tracing" + "go.dedis.ch/dela/mino" + "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/share" + "go.dedis.ch/kyber/v3/suites" + "golang.org/x/net/context" + "golang.org/x/xerrors" +) + +type onChainSecret struct { + U kyber.Point // U is the random part of the encrypted secret + pubk kyber.Point // The client's public key + + nbnodes int // How many nodes participate in the distributed operations + nbfailures int // How many failures occurred so far + threshold int // How many replies are needed to re-create the secret + + replies []types.ReencryptReply // replies received + Uis []*share.PubShare // re-encrypted shares +} + +// newOCS creates a new on-chain secret structure. +func newOCS(pubk kyber.Point) *onChainSecret { + return &onChainSecret{ + pubk: pubk, + } +} + +// ReencryptSecret implements dkg.Actor. +func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point) (XhatEnc kyber.Point, err error) { + if !a.startRes.Done() { + return nil, xerrors.Errorf(initDkgFirst) + } + + ctx, cancel := context.WithTimeout(context.Background(), decryptTimeout) + defer cancel() + ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameDecrypt) + + players := mino.NewAddresses(a.startRes.getParticipants()...) + + sender, receiver, err := a.rpc.Stream(ctx, players) + if err != nil { + return nil, xerrors.Errorf(failedStreamCreation, err) + } + + iterator := players.AddressIterator() + addrs := make([]mino.Address, 0, players.Len()) + + for iterator.HasNext() { + addrs = append(addrs, iterator.GetNext()) + } + + txMsg := types.NewReencryptRequest(U, pubk) + + err = <-sender.Send(txMsg, addrs...) + if err != nil { + return nil, xerrors.Errorf("failed to send reencrypt request: %v", err) + } + + ocs := newOCS(pubk) + ocs.U = U + ocs.nbnodes = len(addrs) + ocs.threshold = a.startRes.getThreshold() + + for i := 0; i < len(addrs); i++ { + src, rxMsg, err := receiver.Recv(ctx) + if err != nil { + return nil, xerrors.Errorf(unexpectedStreamStop, err) + } + + dela.Logger.Debug().Msgf("Received a decryption reply from %v", src) + + reply, ok := rxMsg.(types.ReencryptReply) + if !ok { + return nil, xerrors.Errorf(unexpectedReply, reply, rxMsg) + } + + err = processReencryptReply(ocs, &reply) + if err == nil { + dela.Logger.Debug().Msgf("Reencryption Uis: %v", ocs.Uis) + + XhatEnc, err := share.RecoverCommit(suites.MustFind("Ed25519"), ocs.Uis, ocs.threshold, ocs.nbnodes) + if err != nil { + return nil, xerrors.Errorf("Reencryption failed: %v", err) + } + + // we have successfully reencrypted + return XhatEnc, nil + } + } + + return nil, xerrors.Errorf("Reencryption failed: %v", err) +} + +func processReencryptReply(ocs *onChainSecret, reply *types.ReencryptReply) (err error) { + if reply.Ui == nil { + err = xerrors.Errorf("Received empty reply") + dela.Logger.Warn().Msg("Empty reply received") + ocs.nbfailures++ + if ocs.nbfailures > ocs.nbnodes-ocs.threshold { + err = xerrors.Errorf("couldn't get enough shares") + dela.Logger.Warn().Msg(err.Error()) + } + return err + } + + ocs.replies = append(ocs.replies, *reply) + + if len(ocs.replies) >= ocs.threshold { + ocs.Uis = make([]*share.PubShare, 0, ocs.nbnodes) + + for _, r := range ocs.replies { + + /* + // Verify proofs + ufi := suite.Point().Mul(r.Fi, suite.Point().Add(ocs.U, ocs.pubk)) + uiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), r.Ui.V) + uiHat := suite.Point().Add(ufi, uiei) + + gfi := suite.Point().Mul(r.Fi, nil) + gxi := ocs.poly.Eval(r.Ui.I).V + hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) + hiHat := suite.Point().Add(gfi, hiei) + hash := sha256.New() + r.Ui.V.MarshalTo(hash) + uiHat.MarshalTo(hash) + hiHat.MarshalTo(hash) + e := suite.Scalar().SetBytes(hash.Sum(nil)) + if e.Equal(r.Ei) { + + */ + ocs.Uis = append(ocs.Uis, r.Ui) + /* + } + else + { + dela.Logger.Warn().Msgf("Received invalid share from node: %v", r.Ui.I) + ocs.nbfailures++ + } + */ + } + dela.Logger.Info().Msg("Reencryption completed") + return nil + } + + // If we are leaving by here it means that we do not have + // enough replies yet. We must eventually trigger a finish() + // somehow. It will either happen because we get another + // reply, and now we have enough, or because we get enough + // failures and know to give up, or because o.timeout triggers + // and calls finish(false) in its callback function. + + err = xerrors.Errorf("not enough replies") + dela.Logger.Debug().Msg(err.Error()) + return err +} + +// Helper functions +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index ec5e98bfd..3bf5be809 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -519,156 +519,6 @@ func (a *Actor) EncryptSecret(msg []byte) (U kyber.Point, Cs []kyber.Point) { return } -type OCS struct { - U kyber.Point // U is the random part of the encrypted secret - pubk kyber.Point // The client's public key - - nbnodes int // How many nodes participate in the distributed operations - nbfailures int // How many failures occurred so far - threshold int // How many replies are needed to re-create the secret - - replies []types.ReencryptReply // replies received - Uis []*share.PubShare // re-encrypted shares -} - -// newOCS creates a new on-chain secret structure. -func newOCS(pubk kyber.Point) *OCS { - return &OCS{ - pubk: pubk, - } -} - -// ReencryptSecret implements dkg.Actor. -func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point, threshold int) (Uis []*share.PubShare, err error) { - if !a.startRes.Done() { - return nil, xerrors.Errorf(initDkgFirst) - } - - ctx, cancel := context.WithTimeout(context.Background(), decryptTimeout) - defer cancel() - ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameDecrypt) - - players := mino.NewAddresses(a.startRes.getParticipants()...) - - sender, receiver, err := a.rpc.Stream(ctx, players) - if err != nil { - return nil, xerrors.Errorf(failedStreamCreation, err) - } - - iterator := players.AddressIterator() - addrs := make([]mino.Address, 0, players.Len()) - - for iterator.HasNext() { - addrs = append(addrs, iterator.GetNext()) - } - - txMsg := types.NewReencryptRequest(U, pubk) - - err = <-sender.Send(txMsg, addrs...) - if err != nil { - return nil, xerrors.Errorf("failed to send reencrypt request: %v", err) - } - - ocs := newOCS(pubk) - ocs.U = U - ocs.nbnodes = len(addrs) - ocs.threshold = threshold - - for i := 0; i < len(addrs); i++ { - src, rxMsg, err := receiver.Recv(ctx) - if err != nil { - return nil, xerrors.Errorf(unexpectedStreamStop, err) - } - - dela.Logger.Debug().Msgf("Received a decryption reply from %v", src) - - reply, ok := rxMsg.(types.ReencryptReply) - if !ok { - return nil, xerrors.Errorf(unexpectedReply, reply, rxMsg) - } - - err = processReencryptReply(ocs, &reply) - if err == nil { - dela.Logger.Info().Msgf("Reencrypted message: %v", ocs.Uis) - - return ocs.Uis, nil - } - } - - return nil, xerrors.Errorf("Reencryption failed: %v", err) -} - -func processReencryptReply(ocs *OCS, reply *types.ReencryptReply) (err error) { - if reply.Ui == nil { - err = xerrors.Errorf("Received empty reply") - dela.Logger.Warn().Msg("Empty reply received") - ocs.nbfailures++ - if ocs.nbfailures > ocs.nbnodes-ocs.threshold { - err = xerrors.Errorf("couldn't get enough shares") - dela.Logger.Warn().Msg(err.Error()) - } - return err - } - - ocs.replies = append(ocs.replies, *reply) - - if len(ocs.replies) >= ocs.threshold { - ocs.Uis = make([]*share.PubShare, 0, ocs.nbnodes) - - for _, r := range ocs.replies { - - /* - // Verify proofs - ufi := suite.Point().Mul(r.Fi, suite.Point().Add(ocs.U, ocs.pubk)) - uiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), r.Ui.V) - uiHat := suite.Point().Add(ufi, uiei) - - gfi := suite.Point().Mul(r.Fi, nil) - gxi := ocs.poly.Eval(r.Ui.I).V - hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) - hiHat := suite.Point().Add(gfi, hiei) - hash := sha256.New() - r.Ui.V.MarshalTo(hash) - uiHat.MarshalTo(hash) - hiHat.MarshalTo(hash) - e := suite.Scalar().SetBytes(hash.Sum(nil)) - if e.Equal(r.Ei) { - - */ - ocs.Uis = append(ocs.Uis, r.Ui) - /* - } - else - { - dela.Logger.Warn().Msgf("Received invalid share from node: %v", r.Ui.I) - ocs.nbfailures++ - } - */ - } - dela.Logger.Info().Msg("Reencryption completed") - return nil - } - - // If we are leaving by here it means that we do not have - // enough replies yet. We must eventually trigger a finish() - // somehow. It will either happen because we get another - // reply, and now we have enough, or because we get enough - // failures and know to give up, or because o.timeout triggers - // and calls finish(false) in its callback function. - - err = xerrors.Errorf("not enough replies") - dela.Logger.Debug().Msg(err.Error()) - return err -} - -// Helper functions -func min(a, b int) int { - if a < b { - return a - } - return b -} - // DecryptSecret implements dkg.Actor. func (a *Actor) DecryptSecret(Cs []kyber.Point, XhatEnc kyber.Point, Sk kyber.Scalar) (msg []byte, err error) { pubK, err := a.GetPublicKey() diff --git a/dkg/pedersen/pedersen_test.go b/dkg/pedersen/pedersen_test.go index 02bb78c8b..403007729 100644 --- a/dkg/pedersen/pedersen_test.go +++ b/dkg/pedersen/pedersen_test.go @@ -3,7 +3,6 @@ package pedersen import ( "fmt" "go.dedis.ch/dela/mino/minoch" - "go.dedis.ch/kyber/v3/share" "go.dedis.ch/kyber/v3/suites" "go.dedis.ch/kyber/v3/util/key" "testing" @@ -248,7 +247,6 @@ func TestPedersen_ReencryptScenario(t *testing.T) { dela.Logger = dela.Logger.Level(zerolog.WarnLevel) nbNodes := 7 - threshold := (2 * nbNodes / 3) + 1 minos := make([]mino.Mino, nbNodes) dkgs := make([]dkg.DKG, nbNodes) @@ -282,18 +280,15 @@ func TestPedersen_ReencryptScenario(t *testing.T) { require.NoError(t, err) // every node should be able to encrypt/reencrypt/decrypt - message := []byte("Hello world") kp := key.NewKeyPair(suites.MustFind("Ed25519")) for i := 0; i < nbNodes; i++ { + message := []byte(fmt.Sprint("Hello world, I'm", i)) U, Cs := actors[i].EncryptSecret(message) - Uis, err := actors[i].ReencryptSecret(U, kp.Public, threshold) - require.NoError(t, err) - require.NotNil(t, Uis) - - XhatEnc, err := share.RecoverCommit(suites.MustFind("Ed25519"), Uis, threshold, nbNodes) + XhatEnc, err := actors[i].ReencryptSecret(U, kp.Public) require.NoError(t, err) + require.NotNil(t, XhatEnc) decrypted, err := actors[i].DecryptSecret(Cs, XhatEnc, kp.Private) require.NoError(t, err) From b336d309183e736a54370304a67f6cbf46e309d7 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 14 Jun 2023 10:53:22 +0200 Subject: [PATCH 16/34] finished clean up after review --- dkg/pedersen/controller/action.go | 8 ++++---- dkg/pedersen/ocs.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index f8e2ba45c..1fcb8436e 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -81,14 +81,14 @@ type listenAction struct { } func (a listenAction) Execute(ctx node.Context) error { - var d dkg.DKG + var dkgObject dkg.DKG - err := ctx.Injector.Resolve(&d) + err := ctx.Injector.Resolve(&dkgObject) if err != nil { - return xerrors.Errorf("failed to resolve dkg: %v", err) + return xerrors.Errorf("failed to resolve dkgObject: %v", err) } - actor, err := d.Listen() + actor, err := dkgObject.Listen() if err != nil { return xerrors.Errorf("failed to listen: %v", err) } diff --git a/dkg/pedersen/ocs.go b/dkg/pedersen/ocs.go index cfb08b45a..e18084307 100644 --- a/dkg/pedersen/ocs.go +++ b/dkg/pedersen/ocs.go @@ -160,7 +160,7 @@ func processReencryptReply(ocs *onChainSecret, reply *types.ReencryptReply) (err return err } -// Helper functions +// min is a helper functions func min(a, b int) int { if a < b { return a From 14879bc0781084cfe89b8fcefa03484a05a03760 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 14 Jun 2023 12:49:52 +0200 Subject: [PATCH 17/34] fix failing test --- dkg/pedersen/controller/action.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index 1fcb8436e..acb9234e1 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -85,7 +85,7 @@ func (a listenAction) Execute(ctx node.Context) error { err := ctx.Injector.Resolve(&dkgObject) if err != nil { - return xerrors.Errorf("failed to resolve dkgObject: %v", err) + return xerrors.Errorf("failed to resolve dkg: %v", err) } actor, err := dkgObject.Listen() From 58079827a2ac39ed1b8a6eeddd92d85640673c59 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Mon, 5 Jun 2023 13:59:20 +0200 Subject: [PATCH 18/34] cleanups --- dkg/pedersen/dkg.go | 1 + 1 file changed, 1 insertion(+) diff --git a/dkg/pedersen/dkg.go b/dkg/pedersen/dkg.go index 04e18a1d3..f5c251b8e 100644 --- a/dkg/pedersen/dkg.go +++ b/dkg/pedersen/dkg.go @@ -282,6 +282,7 @@ func (s *instance) deal(ctx context.Context, out mino.Sender) error { } participants := s.startRes.getParticipants() + // for _, to := range participants { for i, deal := range deals { dealMsg := types.NewDeal( deal.Index, From 2b7c5294577dcdc3f5258f9c996b1a8b0773285e Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Tue, 13 Jun 2023 13:10:32 +0200 Subject: [PATCH 19/34] align interfaces Encrypt/EncryptSecret --- dkg/dkg.go | 9 +- dkg/pedersen/controller/action.go | 136 +++++++++++++++++----- dkg/pedersen/controller/action_test.go | 76 ++++++++----- dkg/pedersen/controller/controller.go | 6 +- dkg/pedersen/pedersen.go | 149 ++++++++++++++++++++----- dkg/pedersen/pedersen_test.go | 22 ++-- dkg/pedersen/resharing_test.go | 9 +- 7 files changed, 301 insertions(+), 106 deletions(-) diff --git a/dkg/dkg.go b/dkg/dkg.go index 4ba070226..f2e6d261b 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -26,10 +26,15 @@ type Actor interface { // Encrypt encrypts the given message into kyber points // using the DKG public key - Encrypt(message []byte) (K, C kyber.Point, remainder []byte, err error) + Encrypt(message []byte) (K kyber.Point, Cs []kyber.Point, err error) + // Decrypt decrypts a pair of kyber points into the original message // using the DKG internal private key - Decrypt(K, C kyber.Point) ([]byte, error) + Decrypt(K kyber.Point, Cs []kyber.Point) ([]byte, error) + + // Reencrypt reencrypts generate a temporary key from the public key + // to be able to decrypt the message by the user's private key + Reencrypt(K kyber.Point, PK kyber.Point) (XhatEnc kyber.Point, err error) // Reshare recreates the DKG with an updated list of participants. Reshare(co crypto.CollectiveAuthority, newThreshold int) error diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index acb9234e1..123da7b07 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -188,12 +188,12 @@ func (a encryptAction) Execute(ctx node.Context) error { return xerrors.Errorf("failed to decode message: %v", err) } - k, c, remainder, err := actor.Encrypt(message) + k, cs, err := actor.Encrypt(message) if err != nil { return xerrors.Errorf("failed to encrypt: %v", err) } - outStr, err := encodeEncrypted(k, c, remainder) + outStr, err := encodeEncrypted(k, cs) if err != nil { return xerrors.Errorf("failed to generate output: %v", err) } @@ -215,12 +215,12 @@ func (a decryptAction) Execute(ctx node.Context) error { encrypted := ctx.Flags.String("encrypted") - k, c, err := decodeEncrypted(encrypted) + k, cs, err := decodeEncrypted(encrypted) if err != nil { return xerrors.Errorf("failed to decode encrypted str: %v", err) } - decrypted, err := actor.Decrypt(k, c) + decrypted, err := actor.Decrypt(k, cs) if err != nil { return xerrors.Errorf("failed to decrypt: %v", err) } @@ -230,57 +230,131 @@ func (a decryptAction) Execute(ctx node.Context) error { return nil } -func encodeEncrypted(k, c kyber.Point, remainder []byte) (string, error) { - kbuff, err := k.MarshalBinary() +type reencryptAction struct{} + +func (a reencryptAction) Execute(ctx node.Context) error { + var actor dkg.Actor + + err := ctx.Injector.Resolve(&actor) if err != nil { - return "", xerrors.Errorf("failed to marshal k: %v", err) + return xerrors.Errorf(resolveActorFailed, err) } - cbuff, err := c.MarshalBinary() + encrypted := ctx.Flags.String("encrypted") + + k, _, err := decodeEncrypted(encrypted) if err != nil { - return "", xerrors.Errorf("failed to marshal c: %v", err) + return xerrors.Errorf("failed to decode encrypted str: %v", err) } - encoded := hex.EncodeToString(kbuff) + separator + - hex.EncodeToString(cbuff) + separator + - hex.EncodeToString(remainder) + publicKey := ctx.Flags.String("pubk") - return encoded, nil -} + pk, err := decodePublicKey(publicKey) + if err != nil { + return xerrors.Errorf("failed to decode public key str: %v", err) + } -func decodeEncrypted(str string) (k kyber.Point, c kyber.Point, err error) { - parts := strings.Split(str, separator) - if len(parts) < 2 { - return nil, nil, xerrors.Errorf("malformed encoded: %s", str) + xhatenc, err := actor.Reencrypt(k, pk) + if err != nil { + return xerrors.Errorf("failed to reencrypt: %v", err) } - // Decode K - kbuff, err := hex.DecodeString(parts[0]) + outStr, err := encodeReencrypted(xhatenc) if err != nil { - return nil, nil, xerrors.Errorf("failed to decode k point: %v", err) + return xerrors.Errorf("failed to encode the reencryption data: %v", err) } - k = suite.Point() + fmt.Fprint(ctx.Out, outStr) + + return nil +} - err = k.UnmarshalBinary(kbuff) +func encodeReencrypted(xhatenc kyber.Point) (string, error) { + buff, err := xhatenc.MarshalBinary() if err != nil { - return nil, nil, xerrors.Errorf("failed to unmarshal k point: %v", err) + return "", xerrors.Errorf("failed to marshal xhatenc: %v", err) } - // Decode C - cbuff, err := hex.DecodeString(parts[1]) + encoded := hex.EncodeToString(buff) + + return encoded, nil +} + +func decodePublicKey(str string) (pk kyber.Point, err error) { + pkbuff, err := hex.DecodeString(str) if err != nil { - return nil, nil, xerrors.Errorf("failed to decode c point: %v", err) + return nil, xerrors.Errorf("failed to decode public key: %v", err) } - c = suite.Point() + pk = suite.Point() - err = c.UnmarshalBinary(cbuff) + err = pk.UnmarshalBinary(pkbuff) if err != nil { - return nil, nil, xerrors.Errorf("failed to unmarshal c point: %v", err) + return nil, xerrors.Errorf("failed to unmarshal pk: %v", err) + } + + return pk, nil +} + +func encodeEncrypted(k kyber.Point, cs []kyber.Point) (string, error) { + kbuff, err := k.MarshalBinary() + if err != nil { + return "", xerrors.Errorf("failed to marshal k: %v", err) + } + + encoded := hex.EncodeToString(kbuff) + + for _, c := range cs { + cbuff, err := c.MarshalBinary() + if err != nil { + return "", xerrors.Errorf("failed to marshal c: %v", err) + } + encoded += separator + hex.EncodeToString(cbuff) + } + + return encoded, nil +} + +func decodeEncrypted(str string) (k kyber.Point, cs []kyber.Point, err error) { + parts := strings.Split(str, separator) + if len(parts) < 2 { + return nil, nil, xerrors.Errorf("malformed encoded: %s", str) + } + + for i, p := range parts { + if i == 0 { + // Decode K + kbuff, err := hex.DecodeString(p) + if err != nil { + return nil, nil, xerrors.Errorf("failed to decode k point: %v", err) + } + + k = suite.Point() + + err = k.UnmarshalBinary(kbuff) + if err != nil { + return nil, nil, xerrors.Errorf("failed to unmarshal k point: %v", err) + } + + } else { + // Decode C + cbuff, err := hex.DecodeString(p) + if err != nil { + return nil, nil, xerrors.Errorf("failed to decode c point: %v", err) + } + + c := suite.Point() + + err = c.UnmarshalBinary(cbuff) + if err != nil { + return nil, nil, xerrors.Errorf("failed to unmarshal c point: %v", err) + } + + cs = append(cs, c) + } } - return k, c, nil + return k, cs, nil } // Verifiable encryption diff --git a/dkg/pedersen/controller/action_test.go b/dkg/pedersen/controller/action_test.go index 1606518d8..12def936c 100644 --- a/dkg/pedersen/controller/action_test.go +++ b/dkg/pedersen/controller/action_test.go @@ -385,20 +385,22 @@ func TestEncryptAction_encodeFail(t *testing.T) { require.EqualError(t, err, fake.Err("failed to generate output: failed to marshal k")) } -func TestEncryptAction_OK(t *testing.T) { +// TODO jean: re-enable this test ASAP +func IgnoreTestEncryptAction_OK(t *testing.T) { a := encryptAction{} data := "aa" + fakeK := badPoint{data: data} + + var array interface{} = badPointArray{data: data} + fakeCs := array.([]kyber.Point) + + // fakeCs := make([]badPoint, 1) + // fakeCs = append(fakeCs, badPoint{data: data}) + actor := fakeActor{k: fakeK, cs: fakeCs} inj := node.NewInjector() - inj.Inject(fakeActor{ - k: badPoint{ - data: data, - }, - c: badPoint{ - data: data, - }, - }) + inj.Inject(actor) flags := node.FlagSet{ "message": "aef123", @@ -417,7 +419,7 @@ func TestEncryptAction_OK(t *testing.T) { dataHex := hex.EncodeToString([]byte(data)) - require.Equal(t, dataHex+":"+dataHex+":", out.String()) + require.Equal(t, dataHex+":"+dataHex, out.String()) } func TestDecryptAction_noActor(t *testing.T) { @@ -454,7 +456,7 @@ func TestDecryptAction_decodeFail(t *testing.T) { } func TestDecryptAction_decryptFail(t *testing.T) { - encrypted := "abea449f0ab86029c529f541cdd7f48aee3102b9c1ea2999b5d39c2cc49a4c23:ae29dd65cb4ceaaf7830008b9544625a05b6dbbcd421cf8475aedbef8e8d1da9:" + encrypted := "abea449f0ab86029c529f541cdd7f48aee3102b9c1ea2999b5d39c2cc49a4c23:ae29dd65cb4ceaaf7830008b9544625a05b6dbbcd421cf8475aedbef8e8d1da9" a := decryptAction{} inj := node.NewInjector() @@ -476,7 +478,7 @@ func TestDecryptAction_decryptFail(t *testing.T) { } func TestDecryptAction_decryptOK(t *testing.T) { - encrypted := "abea449f0ab86029c529f541cdd7f48aee3102b9c1ea2999b5d39c2cc49a4c23:ae29dd65cb4ceaaf7830008b9544625a05b6dbbcd421cf8475aedbef8e8d1da9:" + encrypted := "abea449f0ab86029c529f541cdd7f48aee3102b9c1ea2999b5d39c2cc49a4c23:ae29dd65cb4ceaaf7830008b9544625a05b6dbbcd421cf8475aedbef8e8d1da9" message := "fake" expected := hex.EncodeToString([]byte(message)) @@ -507,13 +509,15 @@ func TestDecryptAction_decryptOK(t *testing.T) { } func TestEncodeEncrypted_marshalKFail(t *testing.T) { - _, err := encodeEncrypted(badPoint{err: fake.GetError()}, nil, nil) + _, err := encodeEncrypted(badPoint{err: fake.GetError()}, nil) require.EqualError(t, err, fake.Err("failed to marshal k")) } -func TestEncodeEncrypted_marshalCFail(t *testing.T) { - _, err := encodeEncrypted(badPoint{}, badPoint{err: fake.GetError()}, nil) - require.EqualError(t, err, fake.Err("failed to marshal c")) +// TODO jean: reenable this test +func IgnoreTestEncodeEncrypted_marshalCSFail(t *testing.T) { + //_, err := encodeEncrypted(badPoint{}, badPointArray{ + // cs: make([]kyber.Point, 1), err: fake.GetError()}) + //require.EqualError(t, err, fake.Err("failed to marshal c")) } func TestDecodeEncrypted_kHexBad(t *testing.T) { @@ -1382,15 +1386,16 @@ func TestReshareAction_OK(t *testing.T) { type fakeActor struct { dkg.Actor - setupErr error - encryptErr error - decryptErr error - vencryptErr error - vdecryptErr error - reshareErr error + setupErr error + encryptErr error + decryptErr error + reencryptErr error + vencryptErr error + vdecryptErr error + reshareErr error - k kyber.Point - c kyber.Point + k kyber.Point + cs []kyber.Point decryptData []byte ct types.Ciphertext @@ -1401,14 +1406,18 @@ func (f fakeActor) Setup(co crypto.CollectiveAuthority, threshold int) (pubKey k return suite.Point(), f.setupErr } -func (f fakeActor) Encrypt(message []byte) (K, C kyber.Point, remainder []byte, err error) { - return f.k, f.c, nil, f.encryptErr +func (f fakeActor) Encrypt(message []byte) (K kyber.Point, CS []kyber.Point, err error) { + return f.k, f.cs, f.encryptErr } -func (f fakeActor) Decrypt(K, C kyber.Point) ([]byte, error) { +func (f fakeActor) Decrypt(K kyber.Point, CS []kyber.Point) ([]byte, error) { return f.decryptData, f.decryptErr } +func (f fakeActor) Reencrypt(K kyber.Point, PK kyber.Point) (XhatEnc kyber.Point, err error) { + return nil, f.reencryptErr +} + func (f fakeActor) VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext types.Ciphertext, remainder []byte, err error) { return f.ct, nil, f.vencryptErr } @@ -1443,6 +1452,19 @@ func (b badPoint) MarshalBinary() (data []byte, err error) { return []byte(b.data), b.err } +type PointArray []kyber.Point +type badPointArray struct { + PointArray + + err error + data string +} + +func (b badPointArray) MarshalBinary() (data []byte, err error) { + data = []byte(b.data) + return data, b.err +} + type badScalar struct { kyber.Scalar diff --git a/dkg/pedersen/controller/controller.go b/dkg/pedersen/controller/controller.go index c23897e27..71b58d856 100644 --- a/dkg/pedersen/controller/controller.go +++ b/dkg/pedersen/controller/controller.go @@ -48,7 +48,7 @@ func (m minimal) SetCommands(builder node.Builder) { sub.SetAction(builder.MakeAction(setupAction{})) sub = cmd.SetSubCommand("encrypt") - sub.SetDescription("encrypt a message. Outputs ::") + sub.SetDescription("encrypt a message and outputs :") sub.SetFlags( cli.StringFlag{ Name: "message", @@ -58,11 +58,11 @@ func (m minimal) SetCommands(builder node.Builder) { sub.SetAction(builder.MakeAction(encryptAction{})) sub = cmd.SetSubCommand("decrypt") - sub.SetDescription("decrypt a message") + sub.SetDescription("decrypt a message and outputs the decrypted message") sub.SetFlags( cli.StringFlag{ Name: "encrypted", - Usage: "the encrypted string, as :", + Usage: "the encrypted string, as :", }, ) sub.SetAction(builder.MakeAction(decryptAction{})) diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 3bf5be809..c6612ac40 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -195,32 +195,53 @@ func (a *Actor) GetPublicKey() (kyber.Point, error) { // Encrypt implements dkg.Actor. It uses the DKG public key to encrypt a // message. -func (a *Actor) Encrypt(message []byte) (K, C kyber.Point, remainder []byte, +func (a *Actor) Encrypt(msg []byte) (K kyber.Point, Cs []kyber.Point, err error) { if !a.startRes.Done() { - return nil, nil, nil, xerrors.Errorf(initDkgFirst) + return nil, nil, xerrors.Errorf(initDkgFirst) } - // Embed the message (or as much of it as will fit) into a curve point. - M := suite.Point().Embed(message, random.New()) - max := suite.Point().EmbedLen() - if max > len(message) { - max = len(message) + pubK, err := a.GetPublicKey() + if err != nil { + dela.Logger.Error().Msgf("Cannot encrypt: %v", err.Error()) } - remainder = message[max:] + // ElGamal-encrypt the point to produce ciphertext (K,C). - k := suite.Scalar().Pick(random.New()) // ephemeral private key - K = suite.Point().Mul(k, nil) // ephemeral DH public key - S := suite.Point().Mul(k, a.startRes.getDistKey()) // ephemeral DH shared secret - C = S.Add(S, M) // message blinded with secret + // r: ephemeral, random private key + r := suite.Scalar().Pick(suite.RandomStream()) + // K: ephemeral DH public key + // note K = U in cothority + K = suite.Point().Mul(r, nil) + dela.Logger.Debug().Msgf("K: %v", K.String()) - return K, C, remainder, nil + C := suite.Point().Mul(r, pubK) + dela.Logger.Debug().Msgf("C: %v", C) + + // S: ephemeral DH shared secret + S := suite.Point().Mul(r, pubK) + dela.Logger.Debug().Msgf("S: %v", S.String()) + + for len(msg) > 0 { + kp := suite.Point().Embed(msg, suite.RandomStream()) + dela.Logger.Debug().Msgf("kp: %v", kp.String()) + + // message blinded with secret + c := suite.Point().Add(C, kp) + dela.Logger.Debug().Msgf("c: %v", c) + + Cs = append(Cs, c) + dela.Logger.Debug().Msgf("Cs: %v", Cs) + + msg = msg[min(len(msg), kp.EmbedLen()):] + } + + return K, Cs, nil } // Decrypt implements dkg.Actor. It gets the private shares of the nodes and // decrypt the message. -func (a *Actor) Decrypt(K, C kyber.Point) ([]byte, error) { +func (a *Actor) Decrypt(K kyber.Point, Cs []kyber.Point) ([]byte, error) { if !a.startRes.Done() { return nil, xerrors.Errorf(initDkgFirst) @@ -244,11 +265,87 @@ func (a *Actor) Decrypt(K, C kyber.Point) ([]byte, error) { addrs = append(addrs, iterator.GetNext()) } - message := types.NewDecryptRequest(K, C) + var decryptedMessage []byte + + for _, C := range Cs { + message := types.NewDecryptRequest(K, C) + + err = <-sender.Send(message, addrs...) + if err != nil { + return nil, xerrors.Errorf("failed to send decrypt request: %v", err) + } + + pubShares := make([]*share.PubShare, len(addrs)) + + for i := 0; i < len(addrs); i++ { + src, message, err := receiver.Recv(ctx) + if err != nil { + return []byte{}, xerrors.Errorf(unexpectedStreamStop, err) + } + + dela.Logger.Debug().Msgf("Received a decryption reply from %v", src) + + decryptReply, ok := message.(types.DecryptReply) + if !ok { + return []byte{}, xerrors.Errorf(unexpectedReply, decryptReply, message) + } + + pubShares[i] = &share.PubShare{ + I: int(decryptReply.I), + V: decryptReply.V, + } + } + + res, err := share.RecoverCommit(suite, pubShares, len(addrs), len(addrs)) + if err != nil { + return []byte{}, xerrors.Errorf("failed to recover commit: %v", err) + } + + decrypted, err := res.Data() + + decryptedMessage = append(decryptedMessage, decrypted...) + if err != nil { + return []byte{}, xerrors.Errorf("failed to get embedded data: %v", err) + } + } + dela.Logger.Info().Msgf("Decrypted message: %v", decryptedMessage) + + return decryptedMessage, nil +} + +// Reencrypt implements dkg.Actor. It reencrypts the K with the given +// public key (pk), so that the user can decrypt the Cs with its +// private key (sk) +func (a *Actor) Reencrypt(K kyber.Point, PK kyber.Point) ( + XhatEnc kyber.Point, err error) { + + if !a.startRes.Done() { + return nil, xerrors.Errorf(initDkgFirst) + } + + ctx, cancel := context.WithTimeout(context.Background(), decryptTimeout) + defer cancel() + ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameDecrypt) + + players := mino.NewAddresses(a.startRes.getParticipants()...) + + sender, receiver, err := a.rpc.Stream(ctx, players) + if err != nil { + return nil, xerrors.Errorf(failedStreamCreation, err) + } + + iterator := players.AddressIterator() + addrs := make([]mino.Address, 0, players.Len()) + + for iterator.HasNext() { + addrs = append(addrs, iterator.GetNext()) + } + + message := types.NewReencryptRequest(K, PK) err = <-sender.Send(message, addrs...) if err != nil { - return nil, xerrors.Errorf("failed to send decrypt request: %v", err) + return nil, xerrors.Errorf("failed to send reencrypt request: %v", err) } pubShares := make([]*share.PubShare, len(addrs)) @@ -256,14 +353,14 @@ func (a *Actor) Decrypt(K, C kyber.Point) ([]byte, error) { for i := 0; i < len(addrs); i++ { src, message, err := receiver.Recv(ctx) if err != nil { - return []byte{}, xerrors.Errorf(unexpectedStreamStop, err) + return nil, xerrors.Errorf(unexpectedStreamStop, err) } dela.Logger.Debug().Msgf("Received a decryption reply from %v", src) decryptReply, ok := message.(types.DecryptReply) if !ok { - return []byte{}, xerrors.Errorf(unexpectedReply, decryptReply, message) + return nil, xerrors.Errorf(unexpectedReply, decryptReply, message) } pubShares[i] = &share.PubShare{ @@ -272,19 +369,14 @@ func (a *Actor) Decrypt(K, C kyber.Point) ([]byte, error) { } } - res, err := share.RecoverCommit(suite, pubShares, len(addrs), len(addrs)) + Xhat, err := share.RecoverCommit(suite, pubShares, a.startRes.threshold, len(addrs)) if err != nil { - return []byte{}, xerrors.Errorf("failed to recover commit: %v", err) + return nil, xerrors.Errorf("failed to recover commit: %v", err) } - decryptedMessage, err := res.Data() - if err != nil { - return []byte{}, xerrors.Errorf("failed to get embedded data: %v", err) - } - - dela.Logger.Info().Msgf("Decrypted message: %v", decryptedMessage) + dela.Logger.Info().Msgf("Xhat: %v", Xhat) - return decryptedMessage, nil + return Xhat, nil } // VerifiableEncrypt implements dkg.Actor. It uses the DKG public key to encrypt @@ -510,7 +602,8 @@ func (a *Actor) EncryptSecret(msg []byte) (U kyber.Point, Cs []kyber.Point) { dela.Logger.Debug().Msgf("Keypoint:%v", kp.String()) dela.Logger.Debug().Msgf("X:%v", pubK.String()) - Cs = append(Cs, suite.Point().Add(C, kp)) + c := suite.Point().Add(C, kp) + Cs = append(Cs, c) dela.Logger.Debug().Msgf("Cs:%v", C) msg = msg[min(len(msg), kp.EmbedLen()):] diff --git a/dkg/pedersen/pedersen_test.go b/dkg/pedersen/pedersen_test.go index 403007729..5d3038519 100644 --- a/dkg/pedersen/pedersen_test.go +++ b/dkg/pedersen/pedersen_test.go @@ -96,13 +96,16 @@ func TestPedersen_Decrypt(t *testing.T) { participants: []mino.Address{fake.NewAddress(0)}, distrKey: suite.Point()}, } - _, err := actor.Decrypt(suite.Point(), suite.Point()) + K := suite.Point() + Cs := make([]kyber.Point, 1) + + _, err := actor.Decrypt(K, Cs) require.EqualError(t, err, fake.Err("failed to create stream")) rpc := fake.NewStreamRPC(fake.NewBadReceiver(), fake.NewBadSender()) actor.rpc = rpc - _, err = actor.Decrypt(suite.Point(), suite.Point()) + _, err = actor.Decrypt(K, Cs) require.EqualError(t, err, fake.Err("failed to send decrypt request")) recv := fake.NewReceiver(fake.NewRecvMsg(fake.NewAddress(0), nil)) @@ -110,7 +113,7 @@ func TestPedersen_Decrypt(t *testing.T) { rpc = fake.NewStreamRPC(recv, fake.Sender{}) actor.rpc = rpc - _, err = actor.Decrypt(suite.Point(), suite.Point()) + _, err = actor.Decrypt(K, Cs) require.EqualError(t, err, "got unexpected reply, expected types.DecryptReply but got: ") recv = fake.NewReceiver( @@ -120,7 +123,7 @@ func TestPedersen_Decrypt(t *testing.T) { rpc = fake.NewStreamRPC(recv, fake.Sender{}) actor.rpc = rpc - _, err = actor.Decrypt(suite.Point(), suite.Point()) + _, err = actor.Decrypt(K, Cs) require.EqualError(t, err, "failed to recover commit: share: not enough "+ "good public shares to reconstruct secret commitment") @@ -131,7 +134,7 @@ func TestPedersen_Decrypt(t *testing.T) { rpc = fake.NewStreamRPC(recv, fake.Sender{}) actor.rpc = rpc - _, err = actor.Decrypt(suite.Point(), suite.Point()) + _, err = actor.Decrypt(K, Cs) require.NoError(t, err) } @@ -144,7 +147,9 @@ func Test_Decrypt_StreamStop(t *testing.T) { }, } - _, err := a.Decrypt(nil, nil) + Cs := make([]kyber.Point, 1) + + _, err := a.Decrypt(nil, Cs) require.EqualError(t, err, fake.Err("stream stopped unexpectedly")) } @@ -206,7 +211,7 @@ func TestPedersen_Scenario(t *testing.T) { // trying to call a decrypt/encrypt before a setup message := []byte("Hello world") - _, _, _, err := actors[0].Encrypt(message) + _, _, err := actors[0].Encrypt(message) require.EqualError(t, err, "you must first initialize DKG. Did you call setup() first?") _, err = actors[0].Decrypt(nil, nil) require.EqualError(t, err, "you must first initialize DKG. Did you call setup() first?") @@ -221,9 +226,8 @@ func TestPedersen_Scenario(t *testing.T) { // every node should be able to encrypt/decrypt for i := 0; i < n; i++ { - K, C, remainder, err := actors[i].Encrypt(message) + K, C, err := actors[i].Encrypt(message) require.NoError(t, err) - require.Len(t, remainder, 0) decrypted, err := actors[i].Decrypt(K, C) require.NoError(t, err) require.Equal(t, message, decrypted) diff --git a/dkg/pedersen/resharing_test.go b/dkg/pedersen/resharing_test.go index eb7dea13c..1b92f8438 100644 --- a/dkg/pedersen/resharing_test.go +++ b/dkg/pedersen/resharing_test.go @@ -79,9 +79,8 @@ func TestResharing_minoch(t *testing.T) { // Encrypt a message with the old committee public key. The new committee // should be able to decrypt it successfully message := []byte(testMessage) - K, C, remainder, err := actorsOld[0].Encrypt(message) + K, C, err := actorsOld[0].Encrypt(message) require.NoError(t, err, "encrypting the message was not successful") - require.Len(t, remainder, 0) // Setting up the second dkg nCommon is the number of nodes that are common // between the new and the old committee. @@ -219,9 +218,8 @@ func TestResharing_minogrpc(t *testing.T) { // Encrypt a message with the old committee public key. the new committee // should be able to decrypt it successfully message := []byte(testMessage) - K, C, remainder, err := actorsOld[0].Encrypt(message) + K, C, err := actorsOld[0].Encrypt(message) require.NoError(t, err, "encrypting the message was not successful") - require.Len(t, remainder, 0) // Setting up the second dkg. nCommon is the number of nodes that are common // between the new and the old committee @@ -374,9 +372,8 @@ func TestResharingTwice(t *testing.T) { // Encrypt a message with the old committee public key. the new committee // should be able to decrypt it successfully message := []byte(testMessage) - K, C, remainder, err := actors1[0].Encrypt(message) + K, C, err := actors1[0].Encrypt(message) require.NoError(t, err, "encrypting the message was not successful") - require.Len(t, remainder, 0) // Setting up the second dkg nCommon is the number of nodes that are common // between the new and the old committee From 8f1ab3c66d8ceac9ba368d1f42283a3a51206120 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Tue, 13 Jun 2023 14:17:06 +0200 Subject: [PATCH 20/34] fix missing encryption tests --- dkg/pedersen/controller/action_test.go | 41 ++++++++++---------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/dkg/pedersen/controller/action_test.go b/dkg/pedersen/controller/action_test.go index 12def936c..7e08e51c0 100644 --- a/dkg/pedersen/controller/action_test.go +++ b/dkg/pedersen/controller/action_test.go @@ -385,18 +385,14 @@ func TestEncryptAction_encodeFail(t *testing.T) { require.EqualError(t, err, fake.Err("failed to generate output: failed to marshal k")) } -// TODO jean: re-enable this test ASAP -func IgnoreTestEncryptAction_OK(t *testing.T) { +func TestEncryptAction_OK(t *testing.T) { a := encryptAction{} data := "aa" fakeK := badPoint{data: data} - var array interface{} = badPointArray{data: data} - fakeCs := array.([]kyber.Point) - - // fakeCs := make([]badPoint, 1) - // fakeCs = append(fakeCs, badPoint{data: data}) + fakeCs := make([]kyber.Point, 0, 1) + fakeCs = append(fakeCs, badPoint{data: data}) actor := fakeActor{k: fakeK, cs: fakeCs} inj := node.NewInjector() @@ -509,15 +505,21 @@ func TestDecryptAction_decryptOK(t *testing.T) { } func TestEncodeEncrypted_marshalKFail(t *testing.T) { - _, err := encodeEncrypted(badPoint{err: fake.GetError()}, nil) + fakeK := badPoint{err: fake.GetError()} + fakeCs := make([]kyber.Point, 0, 1) + fakeCs = append(fakeCs, badPoint{}) + + _, err := encodeEncrypted(fakeK, fakeCs) require.EqualError(t, err, fake.Err("failed to marshal k")) } -// TODO jean: reenable this test -func IgnoreTestEncodeEncrypted_marshalCSFail(t *testing.T) { - //_, err := encodeEncrypted(badPoint{}, badPointArray{ - // cs: make([]kyber.Point, 1), err: fake.GetError()}) - //require.EqualError(t, err, fake.Err("failed to marshal c")) +func TestEncodeEncrypted_marshalCSFail(t *testing.T) { + fakeK := badPoint{} + fakeCs := make([]kyber.Point, 0, 1) + fakeCs = append(fakeCs, badPoint{err: fake.GetError()}) + + _, err := encodeEncrypted(fakeK, fakeCs) + require.EqualError(t, err, fake.Err("failed to marshal c")) } func TestDecodeEncrypted_kHexBad(t *testing.T) { @@ -1452,19 +1454,6 @@ func (b badPoint) MarshalBinary() (data []byte, err error) { return []byte(b.data), b.err } -type PointArray []kyber.Point -type badPointArray struct { - PointArray - - err error - data string -} - -func (b badPointArray) MarshalBinary() (data []byte, err error) { - data = []byte(b.data) - return data, b.err -} - type badScalar struct { kyber.Scalar From ee177b3dfef8d756a6e9bdb253572f494b77753f Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 14 Jun 2023 16:00:55 +0200 Subject: [PATCH 21/34] fix rebase whoops --- dkg/pedersen/controller/controller.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dkg/pedersen/controller/controller.go b/dkg/pedersen/controller/controller.go index 71b58d856..b9adeaa95 100644 --- a/dkg/pedersen/controller/controller.go +++ b/dkg/pedersen/controller/controller.go @@ -67,6 +67,20 @@ func (m minimal) SetCommands(builder node.Builder) { ) sub.SetAction(builder.MakeAction(decryptAction{})) + sub = cmd.SetSubCommand("reencrypt") + sub.SetDescription("reencrypt a message and outputs ") + sub.SetFlags( + cli.StringFlag{ + Name: "encrypted", + Usage: "the encrypted string, as :", + }, + cli.StringFlag{ + Name: "pubk", + Usage: "the new public key to reencrypt the message, as ", + }, + ) + sub.SetAction(builder.MakeAction(reencryptAction{})) + sub = cmd.SetSubCommand("verifiableEncrypt") sub.SetDescription("encrypt a message and provides a proof. " + "Outputs :::::") From e28af43cdc576a7e00382097c4aa443a7d5affcc Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Mon, 19 Jun 2023 11:15:43 +0200 Subject: [PATCH 22/34] cleaned up dkg interface --- dkg/dkg.go | 11 --- dkg/pedersen/ocs.go | 8 +- dkg/pedersen/pedersen.go | 143 +--------------------------------- dkg/pedersen/pedersen_test.go | 52 ++++++++++++- 4 files changed, 54 insertions(+), 160 deletions(-) diff --git a/dkg/dkg.go b/dkg/dkg.go index f2e6d261b..419066f5e 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -46,15 +46,4 @@ type Actor interface { // VerifiableDecrypt decrypts a pair of kyber points into the original message // using the DKG internal private key and a proof of work algorithm. VerifiableDecrypt(ciphertexts []types.Ciphertext) ([][]byte, error) - - // EncryptSecret encrypts the given message the calypso way - EncryptSecret(message []byte) (U kyber.Point, Cs []kyber.Point) - - // ReencryptSecret is the first version of the calypso - // reencryption algorithm in DELA - ReencryptSecret(U kyber.Point, Pk kyber.Point) (XhatEnc kyber.Point, err error) - - // DecryptSecret is a helper function to decrypt a secret message previously - // encrypted and reencrypted by the DKG - DecryptSecret(Cs []kyber.Point, XhatEnc kyber.Point, Sk kyber.Scalar) (message []byte, err error) } diff --git a/dkg/pedersen/ocs.go b/dkg/pedersen/ocs.go index e18084307..be300a503 100644 --- a/dkg/pedersen/ocs.go +++ b/dkg/pedersen/ocs.go @@ -31,15 +31,15 @@ func newOCS(pubk kyber.Point) *onChainSecret { } } -// ReencryptSecret implements dkg.Actor. -func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point) (XhatEnc kyber.Point, err error) { +// Reencrypt implements dkg.Actor. +func (a *Actor) Reencrypt(U kyber.Point, pubk kyber.Point) (XhatEnc kyber.Point, err error) { if !a.startRes.Done() { return nil, xerrors.Errorf(initDkgFirst) } ctx, cancel := context.WithTimeout(context.Background(), decryptTimeout) defer cancel() - ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameDecrypt) + ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameReencrypt) players := mino.NewAddresses(a.startRes.getParticipants()...) @@ -67,7 +67,7 @@ func (a *Actor) ReencryptSecret(U kyber.Point, pubk kyber.Point) (XhatEnc kyber. ocs.nbnodes = len(addrs) ocs.threshold = a.startRes.getThreshold() - for i := 0; i < len(addrs); i++ { + for i := 0; i < ocs.nbnodes; i++ { src, rxMsg, err := receiver.Recv(ctx) if err != nil { return nil, xerrors.Errorf(unexpectedStreamStop, err) diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index c6612ac40..27cbb8d63 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -48,7 +48,7 @@ var ( protocolNameDecrypt = "dkg-decrypt" // protocolNameReencrypt denotes the value of the protocol span tag //// associated with the `dkg-reencrypt` protocol. - //protocolNameReencrypt = "dkg-reencrypt" + protocolNameReencrypt = "dkg-reencrypt" // ProtocolNameResharing denotes the value of the protocol span tag // associated with the `dkg-resharing` protocol. protocolNameResharing = "dkg-resharing" @@ -313,72 +313,6 @@ func (a *Actor) Decrypt(K kyber.Point, Cs []kyber.Point) ([]byte, error) { return decryptedMessage, nil } -// Reencrypt implements dkg.Actor. It reencrypts the K with the given -// public key (pk), so that the user can decrypt the Cs with its -// private key (sk) -func (a *Actor) Reencrypt(K kyber.Point, PK kyber.Point) ( - XhatEnc kyber.Point, err error) { - - if !a.startRes.Done() { - return nil, xerrors.Errorf(initDkgFirst) - } - - ctx, cancel := context.WithTimeout(context.Background(), decryptTimeout) - defer cancel() - ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameDecrypt) - - players := mino.NewAddresses(a.startRes.getParticipants()...) - - sender, receiver, err := a.rpc.Stream(ctx, players) - if err != nil { - return nil, xerrors.Errorf(failedStreamCreation, err) - } - - iterator := players.AddressIterator() - addrs := make([]mino.Address, 0, players.Len()) - - for iterator.HasNext() { - addrs = append(addrs, iterator.GetNext()) - } - - message := types.NewReencryptRequest(K, PK) - - err = <-sender.Send(message, addrs...) - if err != nil { - return nil, xerrors.Errorf("failed to send reencrypt request: %v", err) - } - - pubShares := make([]*share.PubShare, len(addrs)) - - for i := 0; i < len(addrs); i++ { - src, message, err := receiver.Recv(ctx) - if err != nil { - return nil, xerrors.Errorf(unexpectedStreamStop, err) - } - - dela.Logger.Debug().Msgf("Received a decryption reply from %v", src) - - decryptReply, ok := message.(types.DecryptReply) - if !ok { - return nil, xerrors.Errorf(unexpectedReply, decryptReply, message) - } - - pubShares[i] = &share.PubShare{ - I: int(decryptReply.I), - V: decryptReply.V, - } - } - - Xhat, err := share.RecoverCommit(suite, pubShares, a.startRes.threshold, len(addrs)) - if err != nil { - return nil, xerrors.Errorf("failed to recover commit: %v", err) - } - - dela.Logger.Info().Msgf("Xhat: %v", Xhat) - - return Xhat, nil -} - // VerifiableEncrypt implements dkg.Actor. It uses the DKG public key to encrypt // a message and provide a zero knowledge proof that the encryption is done by // this person. @@ -583,81 +517,6 @@ func (w worker) work(jobIndex int) error { return nil } -// EncryptSecret implements dkg.Actor. -func (a *Actor) EncryptSecret(msg []byte) (U kyber.Point, Cs []kyber.Point) { - pubK, err := a.GetPublicKey() - if err != nil { - dela.Logger.Error().Msgf("Cannot encrypt secret: %v", err.Error()) - } - - r := suite.Scalar().Pick(suite.RandomStream()) - C := suite.Point().Mul(r, pubK) - dela.Logger.Debug().Msgf("C:%v", C) - - U = suite.Point().Mul(r, nil) - dela.Logger.Debug().Msgf("U is:%v", U.String()) - - for len(msg) > 0 { - kp := suite.Point().Embed(msg, suite.RandomStream()) - dela.Logger.Debug().Msgf("Keypoint:%v", kp.String()) - dela.Logger.Debug().Msgf("X:%v", pubK.String()) - - c := suite.Point().Add(C, kp) - Cs = append(Cs, c) - dela.Logger.Debug().Msgf("Cs:%v", C) - - msg = msg[min(len(msg), kp.EmbedLen()):] - } - - return -} - -// DecryptSecret implements dkg.Actor. -func (a *Actor) DecryptSecret(Cs []kyber.Point, XhatEnc kyber.Point, Sk kyber.Scalar) (msg []byte, err error) { - pubK, err := a.GetPublicKey() - if err != nil { - dela.Logger.Error().Msgf("Cannot encrypt secret: %v", err.Error()) - } - - dela.Logger.Debug().Msgf("DKG pubK:%v", pubK) - dela.Logger.Debug().Msgf("XhatEnc:%v", XhatEnc) - dela.Logger.Debug().Msgf("xc:%v", Sk) - - xcInv := suite.Scalar().Neg(Sk) - dela.Logger.Debug().Msgf("xcInv:%v", xcInv) - - sum := suite.Scalar().Add(Sk, xcInv) - dela.Logger.Debug().Msgf("xc + xcInv: %v", sum) - - XhatDec := suite.Point().Mul(xcInv, pubK) - dela.Logger.Debug().Msgf("XhatDec:%v", XhatDec) - - Xhat := suite.Point().Add(XhatEnc, XhatDec) - dela.Logger.Debug().Msgf("Xhat:%v", Xhat) - - XhatInv := suite.Point().Neg(Xhat) - dela.Logger.Debug().Msgf("XhatInv:%v", XhatInv) - - // Decrypt Cs to keyPointHat - for _, C := range Cs { - dela.Logger.Debug().Msgf("C:%v", C) - - keyPointHat := suite.Point().Add(C, XhatInv) - dela.Logger.Debug().Msgf("keyPointHat:%v", keyPointHat) - - keyPart, err := keyPointHat.Data() - dela.Logger.Debug().Msgf("keyPart:%v", keyPart) - - if err != nil { - e := xerrors.Errorf("Error while decrypting Cs: %v", err) - dela.Logger.Error().Msg(e.Error()) - return nil, e - } - msg = append(msg, keyPart...) - } - return -} - // Reshare implements dkg.Actor. It recreates the DKG with an updated list of // participants. func (a *Actor) Reshare(co crypto.CollectiveAuthority, thresholdNew int) error { diff --git a/dkg/pedersen/pedersen_test.go b/dkg/pedersen/pedersen_test.go index 5d3038519..afd32251b 100644 --- a/dkg/pedersen/pedersen_test.go +++ b/dkg/pedersen/pedersen_test.go @@ -5,6 +5,7 @@ import ( "go.dedis.ch/dela/mino/minoch" "go.dedis.ch/kyber/v3/suites" "go.dedis.ch/kyber/v3/util/key" + "golang.org/x/xerrors" "testing" "github.com/rs/zerolog" @@ -288,13 +289,17 @@ func TestPedersen_ReencryptScenario(t *testing.T) { for i := 0; i < nbNodes; i++ { message := []byte(fmt.Sprint("Hello world, I'm", i)) - U, Cs := actors[i].EncryptSecret(message) + U, Cs, err := actors[i].Encrypt(message) + require.NoError(t, err) - XhatEnc, err := actors[i].ReencryptSecret(U, kp.Public) + XhatEnc, err := actors[i].Reencrypt(U, kp.Public) require.NoError(t, err) require.NotNil(t, XhatEnc) - decrypted, err := actors[i].DecryptSecret(Cs, XhatEnc, kp.Private) + dkgPk, err := actors[i].GetPublicKey() + require.NoError(t, err) + + decrypted, err := decryptReencrypted(Cs, XhatEnc, dkgPk, kp.Private) require.NoError(t, err) require.Equal(t, message, decrypted) } @@ -474,3 +479,44 @@ type fakeSigner struct { func (s fakeSigner) GetPublicKey() crypto.PublicKey { return ed25519.NewPublicKeyFromPoint(s.pubkey) } + +// decryptReencrypted helps to decrypt a reencrypted message. +func decryptReencrypted(Cs []kyber.Point, XhatEnc kyber.Point, dkgPk kyber.Point, Sk kyber.Scalar) (msg []byte, err error) { + dela.Logger.Debug().Msgf("DKG pubK:%v", dkgPk) + dela.Logger.Debug().Msgf("XhatEnc:%v", XhatEnc) + dela.Logger.Debug().Msgf("xc:%v", Sk) + + xcInv := suite.Scalar().Neg(Sk) + dela.Logger.Debug().Msgf("xcInv:%v", xcInv) + + sum := suite.Scalar().Add(Sk, xcInv) + dela.Logger.Debug().Msgf("xc + xcInv: %v", sum) + + XhatDec := suite.Point().Mul(xcInv, dkgPk) + dela.Logger.Debug().Msgf("XhatDec:%v", XhatDec) + + Xhat := suite.Point().Add(XhatEnc, XhatDec) + dela.Logger.Debug().Msgf("Xhat:%v", Xhat) + + XhatInv := suite.Point().Neg(Xhat) + dela.Logger.Debug().Msgf("XhatInv:%v", XhatInv) + + // Decrypt Cs to keyPointHat + for _, C := range Cs { + dela.Logger.Debug().Msgf("C:%v", C) + + keyPointHat := suite.Point().Add(C, XhatInv) + dela.Logger.Debug().Msgf("keyPointHat:%v", keyPointHat) + + keyPart, err := keyPointHat.Data() + dela.Logger.Debug().Msgf("keyPart:%v", keyPart) + + if err != nil { + e := xerrors.Errorf("Error while decrypting Cs: %v", err) + dela.Logger.Error().Msg(e.Error()) + return nil, e + } + msg = append(msg, keyPart...) + } + return +} From 0788a6e130154f0869327eefd162db33af0df078 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 21 Jun 2023 17:24:09 +0200 Subject: [PATCH 23/34] changes after 1st review --- dkg/dkg.go | 14 +++++++++----- dkg/pedersen/dkg.go | 10 +++++----- dkg/pedersen/{ocs.go => reencrypt.go} | 12 ++++++------ 3 files changed, 20 insertions(+), 16 deletions(-) rename dkg/pedersen/{ocs.go => reencrypt.go} (94%) diff --git a/dkg/dkg.go b/dkg/dkg.go index 419066f5e..eda7b3939 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -26,10 +26,14 @@ type Actor interface { // Encrypt encrypts the given message into kyber points // using the DKG public key + // where K is the ephemeral DH (Diffie-Hellman) public key + // and Cs is the resulting, encrypted message Encrypt(message []byte) (K kyber.Point, Cs []kyber.Point, err error) - // Decrypt decrypts a pair of kyber points into the original message - // using the DKG internal private key + // Decrypt decrypts a ciphertext (composed of a K and an array of C's) + // into the original message using the DKG internal private key + // where K is the ephemeral DH (Diffie-Hellman) public key + // and Cs is the encrypted message Decrypt(K kyber.Point, Cs []kyber.Point) ([]byte, error) // Reencrypt reencrypts generate a temporary key from the public key @@ -39,11 +43,11 @@ type Actor interface { // Reshare recreates the DKG with an updated list of participants. Reshare(co crypto.CollectiveAuthority, newThreshold int) error - // VerifiableEncrypt encrypts the given message into kyber points - // using the DKG public key and proof of work algorithm. + // VerifiableEncrypt encrypts the given message into a ciphertext + // using the DKG public key and a verifiable encryption function. VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext types.Ciphertext, remainder []byte, err error) // VerifiableDecrypt decrypts a pair of kyber points into the original message - // using the DKG internal private key and a proof of work algorithm. + // using the DKG internal private key and a verifiable encryption function. VerifiableDecrypt(ciphertexts []types.Ciphertext) ([][]byte, error) } diff --git a/dkg/pedersen/dkg.go b/dkg/pedersen/dkg.go index f5c251b8e..f3c6ca949 100644 --- a/dkg/pedersen/dkg.go +++ b/dkg/pedersen/dkg.go @@ -808,11 +808,11 @@ func (s *instance) handleReencryptRequest(out mino.Sender, msg types.ReencryptRe return xerrors.Errorf("you must first initialize DKG. Did you call setup() first?") } - ui := s.getUI(msg.U, msg.PubK) + ui := s.getUI(msg.K, msg.PubK) - // Calculating proofs + // Calculating proofs of reencryption si := suite.Scalar().Pick(suite.RandomStream()) - uiHat := suite.Point().Mul(si, suite.Point().Add(msg.U, msg.PubK)) + uiHat := suite.Point().Mul(si, suite.Point().Add(msg.K, msg.PubK)) hiHat := suite.Point().Mul(si, nil) hash := sha256.New() ui.V.MarshalTo(hash) @@ -832,8 +832,8 @@ func (s *instance) handleReencryptRequest(out mino.Sender, msg types.ReencryptRe return nil } -func (s *instance) getUI(U, pubk kyber.Point) *share.PubShare { - v := suite.Point().Mul(s.privShare.V, U) +func (s *instance) getUI(K, pubk kyber.Point) *share.PubShare { + v := suite.Point().Mul(s.privShare.V, K) v.Add(v, suite.Point().Mul(s.privShare.V, pubk)) return &share.PubShare{ I: s.privShare.I, diff --git a/dkg/pedersen/ocs.go b/dkg/pedersen/reencrypt.go similarity index 94% rename from dkg/pedersen/ocs.go rename to dkg/pedersen/reencrypt.go index be300a503..e5988550a 100644 --- a/dkg/pedersen/ocs.go +++ b/dkg/pedersen/reencrypt.go @@ -13,7 +13,7 @@ import ( ) type onChainSecret struct { - U kyber.Point // U is the random part of the encrypted secret + K kyber.Point // K is the random part of the encrypted secret pubk kyber.Point // The client's public key nbnodes int // How many nodes participate in the distributed operations @@ -25,14 +25,15 @@ type onChainSecret struct { } // newOCS creates a new on-chain secret structure. -func newOCS(pubk kyber.Point) *onChainSecret { +func newOCS(K kyber.Point, pubk kyber.Point) *onChainSecret { return &onChainSecret{ + K: K, pubk: pubk, } } // Reencrypt implements dkg.Actor. -func (a *Actor) Reencrypt(U kyber.Point, pubk kyber.Point) (XhatEnc kyber.Point, err error) { +func (a *Actor) Reencrypt(K kyber.Point, pubk kyber.Point) (XhatEnc kyber.Point, err error) { if !a.startRes.Done() { return nil, xerrors.Errorf(initDkgFirst) } @@ -55,15 +56,14 @@ func (a *Actor) Reencrypt(U kyber.Point, pubk kyber.Point) (XhatEnc kyber.Point, addrs = append(addrs, iterator.GetNext()) } - txMsg := types.NewReencryptRequest(U, pubk) + txMsg := types.NewReencryptRequest(K, pubk) err = <-sender.Send(txMsg, addrs...) if err != nil { return nil, xerrors.Errorf("failed to send reencrypt request: %v", err) } - ocs := newOCS(pubk) - ocs.U = U + ocs := newOCS(K, pubk) ocs.nbnodes = len(addrs) ocs.threshold = a.startRes.getThreshold() From a2a9480cbfc35334faae5bbc46bfb2bece80f430 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 21 Jun 2023 17:24:59 +0200 Subject: [PATCH 24/34] improve coverage --- dkg/pedersen/json/json.go | 25 +++-- dkg/pedersen/json/json_test.go | 157 +++++++++++++++++++++++----- dkg/pedersen/pedersen.go | 4 +- dkg/pedersen/types/messages.go | 30 ++++-- dkg/pedersen/types/messages_test.go | 11 ++ 5 files changed, 175 insertions(+), 52 deletions(-) diff --git a/dkg/pedersen/json/json.go b/dkg/pedersen/json/json.go index 49ec7e597..28771c9e7 100644 --- a/dkg/pedersen/json/json.go +++ b/dkg/pedersen/json/json.go @@ -105,13 +105,13 @@ type VerifiableDecryptReply struct { } type ReencryptRequest struct { - U []byte + K []byte PubK PublicKey } type ReencryptReply struct { PubK PublicKey - UiI []byte + UiI int UiV []byte Ei []byte Fi []byte @@ -565,9 +565,9 @@ func (f msgFormat) decodeDecryptRequest(ctx serde.Context, msg *DecryptRequest) } func encodeReencryptRequest(msg types.ReencryptRequest) (Message, error) { - u, err := msg.U.MarshalBinary() + k, err := msg.K.MarshalBinary() if err != nil { - return Message{}, xerrors.Errorf("couldn't marshal U: %v", err) + return Message{}, xerrors.Errorf("couldn't marshal K: %v", err) } pubk, err := msg.PubK.MarshalBinary() @@ -576,7 +576,7 @@ func encodeReencryptRequest(msg types.ReencryptRequest) (Message, error) { } req := ReencryptRequest{ - U: u, + K: k, PubK: pubk, } @@ -589,8 +589,7 @@ func encodeReencryptReply(msg types.ReencryptReply) (Message, error) { return Message{}, xerrors.Errorf("couldn't marshal PubK: %v", err) } - I := msg.Ui.I - i := []byte{byte(I >> 24), byte(I >> 16), byte(I >> 8), byte(I)} + i := msg.GetI() v, err := msg.Ui.V.MarshalBinary() if err != nil { @@ -860,10 +859,10 @@ func (f msgFormat) decodeVerifiableDecryptReply(ctx serde.Context, } func (f msgFormat) decodeReencryptRequest(ctx serde.Context, request *ReencryptRequest) (serde.Message, error) { - u := f.suite.Point() - err := u.UnmarshalBinary(request.U) + k := f.suite.Point() + err := k.UnmarshalBinary(request.K) if err != nil { - return nil, xerrors.Errorf("couldn't unmarshal U: %v", err) + return nil, xerrors.Errorf("couldn't unmarshal K: %v", err) } pubk := f.suite.Point() @@ -873,7 +872,7 @@ func (f msgFormat) decodeReencryptRequest(ctx serde.Context, request *ReencryptR } resp := types.ReencryptRequest{ - U: u, + K: k, PubK: pubk, } @@ -887,12 +886,12 @@ func (f msgFormat) decodeReencryptReply(ctx serde.Context, reply *ReencryptReply return nil, xerrors.Errorf("couldn't unmarshal PubK: %v", err) } - i := int(reply.UiI[0])<<24 + int(reply.UiI[1])<<16 + int(reply.UiI[2])<<8 + int(reply.UiI[3]) + i := reply.UiI v := f.suite.Point() err = v.UnmarshalBinary(reply.UiV) if err != nil { - return nil, xerrors.Errorf("couldn't unmarshal Ui: %v", err) + return nil, xerrors.Errorf("couldn't unmarshal UiV: %v", err) } ui := &share.PubShare{i, v} diff --git a/dkg/pedersen/json/json_test.go b/dkg/pedersen/json/json_test.go index 2b298f825..0e030972c 100644 --- a/dkg/pedersen/json/json_test.go +++ b/dkg/pedersen/json/json_test.go @@ -2,6 +2,7 @@ package json import ( "fmt" + "go.dedis.ch/kyber/v3/share" "testing" "github.com/stretchr/testify/require" @@ -16,7 +17,7 @@ import ( // suite is the Kyber suite for Pedersen. var suite = suites.MustFind("Ed25519") -func TestMessageFormat_Start_Encode(t *testing.T) { +func TestMessageFormat_EncodeStart(t *testing.T) { start := types.NewStart(1, []mino.Address{fake.NewAddress(0)}, []kyber.Point{suite.Point()}) format := newMsgFormat() @@ -42,7 +43,7 @@ func TestMessageFormat_Start_Encode(t *testing.T) { require.EqualError(t, err, "unsupported message of type 'fake.Message'") } -func TestMessageFormat_StartResharing_Encode(t *testing.T) { +func TestMessageFormat_EncodeStartResharing(t *testing.T) { start := types.NewStartResharing(1, 1, []mino.Address{fake.NewAddress(0)}, []mino.Address{fake.NewAddress(1)}, []kyber.Point{suite.Point()}, []kyber.Point{suite.Point()}) @@ -72,7 +73,7 @@ func TestMessageFormat_StartResharing_Encode(t *testing.T) { require.EqualError(t, err, fake.Err("failed to encode message: couldn't marshal old public key")) } -func TestMessageFormat_Deal_Encode(t *testing.T) { +func TestMessageFormat_EncodeEncryptDeal(t *testing.T) { deal := types.NewDeal(1, []byte{1}, types.EncryptedDeal{}) format := newMsgFormat() @@ -84,7 +85,7 @@ func TestMessageFormat_Deal_Encode(t *testing.T) { require.Equal(t, expected, string(data)) } -func TestMessageFormat_Reshare_Encode(t *testing.T) { +func TestMessageFormat_EncodeReshare(t *testing.T) { reshare := types.NewReshare(types.Deal{}, []kyber.Point{suite.Point()}) format := newMsgFormat() ctx := serde.NewContext(fake.ContextEngine{}) @@ -99,7 +100,7 @@ func TestMessageFormat_Reshare_Encode(t *testing.T) { require.EqualError(t, err, fake.Err("failed to encode message: couldn't marshal public coefficient")) } -func TestMessageFormat_Response_Encode(t *testing.T) { +func TestMessageFormat_EncodeDealerResponse(t *testing.T) { resp := types.NewResponse(1, types.DealerResponse{}) format := newMsgFormat() @@ -111,7 +112,7 @@ func TestMessageFormat_Response_Encode(t *testing.T) { require.Equal(t, expected, string(data)) } -func TestMessageFormat_StartDone_Encode(t *testing.T) { +func TestMessageFormat_EncodeStartDone(t *testing.T) { done := types.NewStartDone(suite.Point()) format := newMsgFormat() @@ -126,7 +127,7 @@ func TestMessageFormat_StartDone_Encode(t *testing.T) { require.EqualError(t, err, fake.Err("failed to encode message: couldn't marshal public key")) } -func TestMessageFormat_DecryptRequest_Encode(t *testing.T) { +func TestMessageFormat_EncodeDecryptRequest(t *testing.T) { req := types.NewDecryptRequest(suite.Point(), suite.Point()) format := newMsgFormat() @@ -146,7 +147,7 @@ func TestMessageFormat_DecryptRequest_Encode(t *testing.T) { require.EqualError(t, err, fake.Err("failed to encode message: couldn't marshal C")) } -func TestMessageFormat_VerifiableDecryptRequest_Encode(t *testing.T) { +func TestMessageFormat_EncodeVerifiableDecryptRequest(t *testing.T) { req := types.NewVerifiableDecryptRequest([]types.Ciphertext{{ K: suite.Point(), C: suite.Point(), @@ -180,7 +181,7 @@ func TestMessageFormat_VerifiableDecryptRequest_Encode(t *testing.T) { t.Run("GBar", check("GBar", types.Ciphertext{K: suite.Point(), C: suite.Point(), UBar: suite.Point(), E: suite.Scalar(), F: suite.Scalar(), GBar: badPoint{}})) } -func TestMessageFormat_DecryptReply_Encode(t *testing.T) { +func TestMessageFormat_EncodeDecryptReply(t *testing.T) { resp := types.NewDecryptReply(5, suite.Point()) format := newMsgFormat() @@ -195,10 +196,34 @@ func TestMessageFormat_DecryptReply_Encode(t *testing.T) { require.EqualError(t, err, fake.Err("failed to encode message: couldn't marshal V")) } -func TestMessageFormat_VerifiableDecryptReply_Encode(t *testing.T) { +func TestMessageFormat_EncodeReencryptReply(t *testing.T) { + resp := types.NewReencryptReply( + suite.Point(), + &share.PubShare{ + I: int(12358), + V: suite.Point(), + }, + suite.Scalar().Pick(suite.RandomStream()), + suite.Scalar(), + ) + + format := newMsgFormat() + ctx := serde.NewContext(fake.ContextEngine{}) + + data, err := format.Encode(ctx, resp) + require.NoError(t, err) + + require.Regexp(t, `{"ReencryptReply":{"PubK":"[^"]+","UiI":12358,"UiV":"[^"]+","Ei":"[^"]+","Fi":"[^"]+"}}`, string(data)) + + resp.PubK = badPoint{} + _, err = format.Encode(ctx, resp) + require.EqualError(t, err, fake.Err("failed to encode message: couldn't marshal PubK")) +} + +func TestMessageFormat_EncodeVerifiableDecryptReply(t *testing.T) { req := types.NewVerifiableDecryptReply([]types.ShareAndProof{{ V: suite.Point(), - I: int64(0), + I: int64(1321), Ui: suite.Point(), Ei: suite.Scalar(), Fi: suite.Scalar(), @@ -210,7 +235,7 @@ func TestMessageFormat_VerifiableDecryptReply_Encode(t *testing.T) { data, err := format.Encode(ctx, req) require.NoError(t, err) - regexp := `{"VerifiableDecryptReply":{"Sp":\[{"V":"[^"]+","I":0,"Ui":"[^"]+","Ei":"[^"]+","Fi":"[^"]+","Hi":"[^"]+"}\]}}` + regexp := `{"VerifiableDecryptReply":{"Sp":\[{"V":"[^"]+","I":1321,"Ui":"[^"]+","Ei":"[^"]+","Fi":"[^"]+","Hi":"[^"]+"}\]}}` require.Regexp(t, regexp, string(data)) check := func(attr string, sp types.ShareAndProof) func(t *testing.T) { @@ -228,7 +253,7 @@ func TestMessageFormat_VerifiableDecryptReply_Encode(t *testing.T) { t.Run("Hi", check("H_i", types.ShareAndProof{V: suite.Point(), Ui: suite.Point(), Ei: suite.Scalar(), Fi: suite.Scalar(), Hi: badPoint{}})) } -func TestMessageFormat_Decode(t *testing.T) { +func TestMessageFormat_DecodeStart(t *testing.T) { format := newMsgFormat() ctx := serde.NewContext(fake.ContextEngine{}) ctx = serde.WithFactory(ctx, types.AddrKey{}, fake.AddressFactory{}) @@ -256,19 +281,30 @@ func TestMessageFormat_Decode(t *testing.T) { badCtx := serde.WithFactory(ctx, types.AddrKey{}, nil) _, err = format.Decode(badCtx, []byte(`{"Start":{}}`)) require.EqualError(t, err, "invalid factory of type ''") +} +func TestMessageFormat_DecodeEncryptedDeal(t *testing.T) { + format := newMsgFormat() + ctx := serde.NewContext(fake.ContextEngine{}) - // Decode deal messages. deal, err := format.Decode(ctx, []byte(`{"Deal":{}}`)) require.NoError(t, err) require.Equal(t, types.NewDeal(0, nil, types.EncryptedDeal{}), deal) +} + +func TestMessageFormat_DecodeDealerResponse(t *testing.T) { + format := newMsgFormat() + ctx := serde.NewContext(fake.ContextEngine{}) - // Decode response messages. resp, err := format.Decode(ctx, []byte(`{"Response":{}}`)) require.NoError(t, err) require.Equal(t, types.NewResponse(0, types.DealerResponse{}), resp) +} + +func TestMessageFormat_DecodeStartDone(t *testing.T) { + format := newMsgFormat() + ctx := serde.NewContext(fake.ContextEngine{}) - // Decode start done messages. - data = []byte(fmt.Sprintf(`{"StartDone":{"PublicKey":"%s"}}`, testPoint)) + data := []byte(fmt.Sprintf(`{"StartDone":{"PublicKey":"%s"}}`, testPoint)) done, err := format.Decode(ctx, data) require.NoError(t, err) require.IsType(t, types.StartDone{}, done) @@ -277,9 +313,13 @@ func TestMessageFormat_Decode(t *testing.T) { _, err = format.Decode(ctx, data) require.EqualError(t, err, "couldn't unmarshal public key: invalid Ed25519 curve point") +} + +func TestMessageFormat_DecodeDecryptRequest(t *testing.T) { + format := newMsgFormat() + ctx := serde.NewContext(fake.ContextEngine{}) - // Decode decryption request messages. - data = []byte(fmt.Sprintf(`{"DecryptRequest":{"K":"%s","C":"%s"}}`, testPoint, testPoint)) + data := []byte(fmt.Sprintf(`{"DecryptRequest":{"K":"%s","C":"%s"}}`, testPoint, testPoint)) req, err := format.Decode(ctx, data) require.NoError(t, err) require.IsType(t, types.DecryptRequest{}, req) @@ -294,11 +334,16 @@ func TestMessageFormat_Decode(t *testing.T) { require.EqualError(t, err, "couldn't unmarshal C: invalid Ed25519 curve point") - // Decode decryption reply messages. - data = []byte(fmt.Sprintf(`{"DecryptReply":{"I":4,"V":"%s"}}`, testPoint)) - resp, err = format.Decode(ctx, data) +} + +func TestMessageFormat_DecodeDecryptReply(t *testing.T) { + format := newMsgFormat() + ctx := serde.NewContext(fake.ContextEngine{}) + + data := []byte(fmt.Sprintf(`{"DecryptReply":{"I":4,"V":"%s"}}`, testPoint)) + reply, err := format.Decode(ctx, data) require.NoError(t, err) - require.IsType(t, types.DecryptReply{}, resp) + require.IsType(t, types.DecryptReply{}, reply) data = []byte(`{"DecryptReply":{"V":[]}}`) _, err = format.Decode(ctx, data) @@ -312,7 +357,65 @@ func TestMessageFormat_Decode(t *testing.T) { require.EqualError(t, err, "message is empty") } -func TestMessageFormat_Decode_StartResharing(t *testing.T) { +func TestMessageFormat_DecodeReencryptRequest(t *testing.T) { + format := newMsgFormat() + ctx := serde.NewContext(fake.ContextEngine{}) + + data := []byte(fmt.Sprintf(`{"ReencryptRequest":{"K":"%s","PubK":"%s"}}`, testPoint, testPoint)) + request, err := format.Decode(ctx, data) + require.NoError(t, err) + require.IsType(t, types.ReencryptRequest{}, request) + + data = []byte(fmt.Sprintf(`{"ReencryptRequest":{"K":[],"PubK":"%s"}}`, testPoint)) + _, err = format.Decode(ctx, data) + require.EqualError(t, err, + "couldn't unmarshal K: invalid Ed25519 curve point") + + data = []byte(fmt.Sprintf(`{"ReencryptRequest":{"K":"%s","PubK":[]}}`, testPoint)) + _, err = format.Decode(ctx, data) + require.EqualError(t, err, + "couldn't unmarshal PubK: invalid Ed25519 curve point") +} + +func TestMessageFormat_DecodeReencryptReply(t *testing.T) { + format := newMsgFormat() + ctx := serde.NewContext(fake.ContextEngine{}) + + data := []byte(fmt.Sprintf(`{"ReencryptReply":{"Pubk":"%s","UiI":13,"UiV":"%s","Ei":"%s","Fi":"%s"}}`, + testPoint, testPoint, testPoint, testPoint)) + reply, err := format.Decode(ctx, data) + require.NoError(t, err) + require.IsType(t, types.ReencryptReply{}, reply) + + data = []byte(fmt.Sprintf(`{"ReencryptReply":{"Pubk":[],"UiI":13,"UiV":"%s","Ei":"%s","Fi":"%s"}}`, + testPoint, testPoint, testPoint)) + _, err = format.Decode(ctx, data) + require.ErrorContains(t, err, "couldn't unmarshal PubK") + + data = []byte(fmt.Sprintf(`{"ReencryptReply":{"Pubk":"%s","UiI":"0","UiV":"%s","Ei":"%s","Fi":"%s"}}`, + testPoint, testPoint, testPoint, testPoint)) + _, err = format.Decode(ctx, data) + require.ErrorContains(t, err, "json: cannot unmarshal string into") + require.ErrorContains(t, err, "of type int") + + data = []byte(fmt.Sprintf(`{"ReencryptReply":{"Pubk":"%s","UiI":13,"UiV":[],"Ei":"%s","Fi":"%s"}}`, + testPoint, testPoint, testPoint)) + _, err = format.Decode(ctx, data) + require.ErrorContains(t, err, "couldn't unmarshal UiV") + + data = []byte(fmt.Sprintf(`{"ReencryptReply":{"Pubk":"%s","UiI":13,"UiV":"%s","Ei":[],"Fi":"%s"}}`, + testPoint, testPoint, testPoint)) + _, err = format.Decode(ctx, data) + require.ErrorContains(t, err, "couldn't unmarshal Ei") + + data = []byte(fmt.Sprintf(`{"ReencryptReply":{"Pubk":"%s","UiI":13,"UiV":"%s","Ei":"%s","Fi":[]}}`, + testPoint, testPoint, testPoint)) + _, err = format.Decode(ctx, data) + require.ErrorContains(t, err, "couldn't unmarshal Fi") + +} + +func TestMessageFormat_DecodeStartResharing(t *testing.T) { format := newMsgFormat() ctx := serde.NewContext(fake.ContextEngine{}) ctx = serde.WithFactory(ctx, types.AddrKey{}, fake.AddressFactory{}) @@ -349,7 +452,7 @@ func TestMessageFormat_Decode_StartResharing(t *testing.T) { "couldn't unmarshal old public key: invalid Ed25519 curve point") } -func TestMessageFormat_Decode_Reshare(t *testing.T) { +func TestMessageFormat_DecodeReshare(t *testing.T) { format := newMsgFormat() ctx := serde.NewContext(fake.ContextEngine{}) ctx = serde.WithFactory(ctx, types.AddrKey{}, fake.AddressFactory{}) @@ -371,7 +474,7 @@ func TestMessageFormat_Decode_Reshare(t *testing.T) { require.EqualError(t, err, "couldn't unmarshal public coeff key: invalid Ed25519 curve point") } -func TestMessageFormat_Decode_VerifiableDecryptRequest(t *testing.T) { +func TestMessageFormat_DecodeVerifiableDecryptRequest(t *testing.T) { format := newMsgFormat() ctx := serde.NewContext(fake.ContextEngine{}) ctx = serde.WithFactory(ctx, types.AddrKey{}, fake.AddressFactory{}) @@ -420,7 +523,7 @@ func TestMessageFormat_Decode_VerifiableDecryptRequest(t *testing.T) { require.EqualError(t, err, "couldn't unmarshal GBar: invalid Ed25519 curve point") } -func TestMessageFormat_Decode_VerifiableDecryptReply(t *testing.T) { +func TestMessageFormat_DecodeVerifiableDecryptReply(t *testing.T) { format := newMsgFormat() ctx := serde.NewContext(fake.ContextEngine{}) ctx = serde.WithFactory(ctx, types.AddrKey{}, fake.AddressFactory{}) diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 27cbb8d63..50e78bd3d 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -302,11 +302,11 @@ func (a *Actor) Decrypt(K kyber.Point, Cs []kyber.Point) ([]byte, error) { } decrypted, err := res.Data() - - decryptedMessage = append(decryptedMessage, decrypted...) if err != nil { return []byte{}, xerrors.Errorf("failed to get embedded data: %v", err) } + + decryptedMessage = append(decryptedMessage, decrypted...) } dela.Logger.Info().Msgf("Decrypted message: %v", decryptedMessage) diff --git a/dkg/pedersen/types/messages.go b/dkg/pedersen/types/messages.go index c6d41b08b..082309459 100644 --- a/dkg/pedersen/types/messages.go +++ b/dkg/pedersen/types/messages.go @@ -447,16 +447,16 @@ func (req DecryptRequest) Serialize(ctx serde.Context) ([]byte, error) { // ReencryptRequest share sent to a node in order to // reencrypt a secret with the given public key type ReencryptRequest struct { - // U is the point from the write-request - U kyber.Point - // Xc is the public key of the reader + // K is the point from the writer + K kyber.Point + // PubK is the public key of the reader PubK kyber.Point } -// NewReencryptRequest creates a new decryption request. -func NewReencryptRequest(u, pubk kyber.Point) *ReencryptRequest { +// NewReencryptRequest creates a new reencryption request. +func NewReencryptRequest(k, pubk kyber.Point) *ReencryptRequest { return &ReencryptRequest{ - U: u, + K: k, PubK: pubk, } } @@ -482,8 +482,8 @@ type ReencryptReply struct { } // NewReencryptReply creates a new decryption request. -func NewReencryptReply(pubk kyber.Point, ui *share.PubShare, ei, fi kyber.Scalar) *ReencryptReply { - return &ReencryptReply{ +func NewReencryptReply(pubk kyber.Point, ui *share.PubShare, ei, fi kyber.Scalar) ReencryptReply { + return ReencryptReply{ PubK: pubk, Ui: ui, Ei: ei, @@ -492,10 +492,10 @@ func NewReencryptReply(pubk kyber.Point, ui *share.PubShare, ei, fi kyber.Scalar } // Serialize implements serde.Message. -func (req ReencryptReply) Serialize(ctx serde.Context) ([]byte, error) { +func (reply ReencryptReply) Serialize(ctx serde.Context) ([]byte, error) { format := msgFormats.Get(ctx.GetFormat()) - data, err := format.Encode(ctx, req) + data, err := format.Encode(ctx, reply) if err != nil { return nil, xerrors.Errorf(couldntEncodeDecryptRequest, err) } @@ -503,6 +503,16 @@ func (req ReencryptReply) Serialize(ctx serde.Context) ([]byte, error) { return data, nil } +// GetI returns I. +func (reply ReencryptReply) GetI() int { + return reply.Ui.I +} + +// GetV returns V. +func (reply ReencryptReply) GetV() kyber.Point { + return reply.Ui.V +} + // VerifiableDecryptRequest is a message sent to request a verifiable // decryption. // diff --git a/dkg/pedersen/types/messages_test.go b/dkg/pedersen/types/messages_test.go index c86ea6f79..cf96d64c9 100644 --- a/dkg/pedersen/types/messages_test.go +++ b/dkg/pedersen/types/messages_test.go @@ -260,6 +260,17 @@ func TestDecryptRequest_Serialize(t *testing.T) { require.EqualError(t, err, fake.Err("couldn't encode decrypt request")) } +func TestReencryptRequest_Serialize(t *testing.T) { + req := ReencryptRequest{} + + data, err := req.Serialize(fake.NewContext()) + require.NoError(t, err) + require.Equal(t, fake.GetFakeFormatValue(), data) + + _, err = req.Serialize(fake.NewBadContext()) + require.EqualError(t, err, fake.Err("couldn't encode decrypt request")) +} + func TestVerifiableDecryptRequest_Get(t *testing.T) { req := NewVerifiableDecryptRequest([]Ciphertext{{}, {}}) From 80d6b7b0b1008177a008cd6e5c210226de58427f Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Mon, 26 Jun 2023 14:08:54 +0200 Subject: [PATCH 25/34] changes after review --- dkg/dkg.go | 3 +- dkg/pedersen/controller/action_test.go | 2 +- dkg/pedersen/dkg.go | 2 +- dkg/pedersen/json/json_test.go | 1 - dkg/pedersen/pedersen.go | 43 +++++++++++++------------- dkg/pedersen/resharing_test.go | 14 ++++----- dkg/pedersen/types/messages.go | 9 +++--- 7 files changed, 36 insertions(+), 38 deletions(-) diff --git a/dkg/dkg.go b/dkg/dkg.go index eda7b3939..493387fe8 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -27,7 +27,8 @@ type Actor interface { // Encrypt encrypts the given message into kyber points // using the DKG public key // where K is the ephemeral DH (Diffie-Hellman) public key - // and Cs is the resulting, encrypted message + // and Cs is the resulting, encrypted points + // or an error if encryption is not possible. Encrypt(message []byte) (K kyber.Point, Cs []kyber.Point, err error) // Decrypt decrypts a ciphertext (composed of a K and an array of C's) diff --git a/dkg/pedersen/controller/action_test.go b/dkg/pedersen/controller/action_test.go index 7e08e51c0..3dc449e42 100644 --- a/dkg/pedersen/controller/action_test.go +++ b/dkg/pedersen/controller/action_test.go @@ -392,7 +392,7 @@ func TestEncryptAction_OK(t *testing.T) { fakeK := badPoint{data: data} fakeCs := make([]kyber.Point, 0, 1) - fakeCs = append(fakeCs, badPoint{data: data}) + fakeCs = append(fakeCs, fakeK) actor := fakeActor{k: fakeK, cs: fakeCs} inj := node.NewInjector() diff --git a/dkg/pedersen/dkg.go b/dkg/pedersen/dkg.go index f3c6ca949..fb18c68fc 100644 --- a/dkg/pedersen/dkg.go +++ b/dkg/pedersen/dkg.go @@ -282,7 +282,7 @@ func (s *instance) deal(ctx context.Context, out mino.Sender) error { } participants := s.startRes.getParticipants() - // for _, to := range participants { + for i, deal := range deals { dealMsg := types.NewDeal( deal.Index, diff --git a/dkg/pedersen/json/json_test.go b/dkg/pedersen/json/json_test.go index 0e030972c..267ed846b 100644 --- a/dkg/pedersen/json/json_test.go +++ b/dkg/pedersen/json/json_test.go @@ -412,7 +412,6 @@ func TestMessageFormat_DecodeReencryptReply(t *testing.T) { testPoint, testPoint, testPoint)) _, err = format.Decode(ctx, data) require.ErrorContains(t, err, "couldn't unmarshal Fi") - } func TestMessageFormat_DecodeStartResharing(t *testing.T) { diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 50e78bd3d..92f5c6bab 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -112,7 +112,7 @@ type Actor struct { } // Setup implement dkg.Actor. It initializes the DKG. -func (a *Actor) Setup(co crypto.CollectiveAuthority, threshold int) (kyber.Point, error) { +func (a *Actor) Setup(coAuth crypto.CollectiveAuthority, threshold int) (kyber.Point, error) { if a.startRes.Done() { return nil, xerrors.Errorf("startRes is already done, only one setup call is allowed") @@ -122,16 +122,16 @@ func (a *Actor) Setup(co crypto.CollectiveAuthority, threshold int) (kyber.Point defer cancel() ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameSetup) - sender, receiver, err := a.rpc.Stream(ctx, co) + sender, receiver, err := a.rpc.Stream(ctx, coAuth) if err != nil { return nil, xerrors.Errorf("failed to stream: %v", err) } - addrs := make([]mino.Address, 0, co.Len()) - pubkeys := make([]kyber.Point, 0, co.Len()) + addrs := make([]mino.Address, 0, coAuth.Len()) + pubkeys := make([]kyber.Point, 0, coAuth.Len()) - addrIter := co.AddressIterator() - pubkeyIter := co.PublicKeyIterator() + addrIter := coAuth.AddressIterator() + pubkeyIter := coAuth.PublicKeyIterator() for addrIter.HasNext() && pubkeyIter.HasNext() { addrs = append(addrs, addrIter.GetNext()) @@ -194,9 +194,9 @@ func (a *Actor) GetPublicKey() (kyber.Point, error) { } // Encrypt implements dkg.Actor. It uses the DKG public key to encrypt a -// message. -func (a *Actor) Encrypt(msg []byte) (K kyber.Point, Cs []kyber.Point, - err error) { +// message, and returns a random, ephemeral part K +// and the cipher as an array of Kyber points +func (a *Actor) Encrypt(msg []byte) (kyber.Point, []kyber.Point, error) { if !a.startRes.Done() { return nil, nil, xerrors.Errorf(initDkgFirst) @@ -208,11 +208,9 @@ func (a *Actor) Encrypt(msg []byte) (K kyber.Point, Cs []kyber.Point, } // ElGamal-encrypt the point to produce ciphertext (K,C). - // r: ephemeral, random private key r := suite.Scalar().Pick(suite.RandomStream()) - // K: ephemeral DH public key - // note K = U in cothority - K = suite.Point().Mul(r, nil) + + K := suite.Point().Mul(r, nil) dela.Logger.Debug().Msgf("K: %v", K.String()) C := suite.Point().Mul(r, pubK) @@ -222,6 +220,7 @@ func (a *Actor) Encrypt(msg []byte) (K kyber.Point, Cs []kyber.Point, S := suite.Point().Mul(r, pubK) dela.Logger.Debug().Msgf("S: %v", S.String()) + Cs := make([]kyber.Point, 0, 16) for len(msg) > 0 { kp := suite.Point().Embed(msg, suite.RandomStream()) dela.Logger.Debug().Msgf("kp: %v", kp.String()) @@ -318,8 +317,8 @@ func (a *Actor) Decrypt(K kyber.Point, Cs []kyber.Point) ([]byte, error) { // this person. // // See https://arxiv.org/pdf/2205.08529.pdf / section 5.4 Protocol / step 1 -func (a *Actor) VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext types.Ciphertext, - remainder []byte, err error) { +func (a *Actor) VerifiableEncrypt(message []byte, GBar kyber.Point) (types.Ciphertext, + []byte, error) { if !a.startRes.Done() { return types.Ciphertext{}, nil, xerrors.Errorf("you must first initialize " + @@ -334,7 +333,7 @@ func (a *Actor) VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext max = len(message) } - remainder = message[max:] + remainder := message[max:] // ElGamal-encrypt the point to produce ciphertext (localK,localC). localk := suite.Scalar().Pick(random.New()) // ephemeral private key @@ -358,7 +357,7 @@ func (a *Actor) VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext E := suite.Scalar().SetBytes(hash.Sum(nil)) F := suite.Scalar().Add(s, suite.Scalar().Mul(E, localk)) - ciphertext = types.Ciphertext{ + ciphertext := types.Ciphertext{ K: localK, C: localC, UBar: UBar, @@ -519,16 +518,16 @@ func (w worker) work(jobIndex int) error { // Reshare implements dkg.Actor. It recreates the DKG with an updated list of // participants. -func (a *Actor) Reshare(co crypto.CollectiveAuthority, thresholdNew int) error { +func (a *Actor) Reshare(coAuth crypto.CollectiveAuthority, thresholdNew int) error { if !a.startRes.Done() { return xerrors.Errorf(initDkgFirst) } - addrsNew := make([]mino.Address, 0, co.Len()) - pubkeysNew := make([]kyber.Point, 0, co.Len()) + addrsNew := make([]mino.Address, 0, coAuth.Len()) + pubkeysNew := make([]kyber.Point, 0, coAuth.Len()) - addrIter := co.AddressIterator() - pubkeyIter := co.PublicKeyIterator() + addrIter := coAuth.AddressIterator() + pubkeyIter := coAuth.PublicKeyIterator() for addrIter.HasNext() && pubkeyIter.HasNext() { addrsNew = append(addrsNew, addrIter.GetNext()) diff --git a/dkg/pedersen/resharing_test.go b/dkg/pedersen/resharing_test.go index 1b92f8438..4a759c442 100644 --- a/dkg/pedersen/resharing_test.go +++ b/dkg/pedersen/resharing_test.go @@ -79,7 +79,7 @@ func TestResharing_minoch(t *testing.T) { // Encrypt a message with the old committee public key. The new committee // should be able to decrypt it successfully message := []byte(testMessage) - K, C, err := actorsOld[0].Encrypt(message) + K, Cs, err := actorsOld[0].Encrypt(message) require.NoError(t, err, "encrypting the message was not successful") // Setting up the second dkg nCommon is the number of nodes that are common @@ -152,7 +152,7 @@ func TestResharing_minoch(t *testing.T) { // The public key should remain the same require.NoError(t, err, "the public key should remain the same") newPubKey.Equal(oldPubKey) - decrypted, err := actorNew.Decrypt(K, C) + decrypted, err := actorNew.Decrypt(K, Cs) require.NoError(t, err, "decryption was not successful") require.Equal(t, message, decrypted, "the new committee should be able "+ "to decrypt the messages encrypted by the old committee") @@ -218,7 +218,7 @@ func TestResharing_minogrpc(t *testing.T) { // Encrypt a message with the old committee public key. the new committee // should be able to decrypt it successfully message := []byte(testMessage) - K, C, err := actorsOld[0].Encrypt(message) + K, Cs, err := actorsOld[0].Encrypt(message) require.NoError(t, err, "encrypting the message was not successful") // Setting up the second dkg. nCommon is the number of nodes that are common @@ -316,7 +316,7 @@ func TestResharing_minogrpc(t *testing.T) { // The public key should remain the same require.NoError(t, err, "the public key should remain the same") newPubKey.Equal(oldPubKey) - decrypted, err := actorNew.Decrypt(K, C) + decrypted, err := actorNew.Decrypt(K, Cs) require.NoError(t, err, "decryption was not successful") require.Equal(t, message, decrypted, "the new committee should be able "+ "to decrypt the messages encrypted by the old committee") @@ -372,7 +372,7 @@ func TestResharingTwice(t *testing.T) { // Encrypt a message with the old committee public key. the new committee // should be able to decrypt it successfully message := []byte(testMessage) - K, C, err := actors1[0].Encrypt(message) + K, Cs, err := actors1[0].Encrypt(message) require.NoError(t, err, "encrypting the message was not successful") // Setting up the second dkg nCommon is the number of nodes that are common @@ -445,7 +445,7 @@ func TestResharingTwice(t *testing.T) { // The public key should remain the same require.NoError(t, err, "the public key should remain the same") newPubKey.Equal(oldPubKey) - decrypted, err := actorNew.Decrypt(K, C) + decrypted, err := actorNew.Decrypt(K, Cs) require.NoError(t, err, "decryption was not successful") require.Equal(t, message, decrypted, "the new committee should be able "+ "to decrypt the messages encrypted by the old committee") @@ -521,7 +521,7 @@ func TestResharingTwice(t *testing.T) { // The public key should remain the same require.NoError(t, err, "the public key should remain the same") newPubKey.Equal(oldPubKey) - decrypted, err := actorNew.Decrypt(K, C) + decrypted, err := actorNew.Decrypt(K, Cs) require.NoError(t, err, "decryption was not successful") require.Equal(t, message, decrypted, "the new committee should be able "+ "to decrypt the messages encrypted by the old committee") diff --git a/dkg/pedersen/types/messages.go b/dkg/pedersen/types/messages.go index 082309459..e4ca1fc6d 100644 --- a/dkg/pedersen/types/messages.go +++ b/dkg/pedersen/types/messages.go @@ -444,12 +444,11 @@ func (req DecryptRequest) Serialize(ctx serde.Context) ([]byte, error) { return data, nil } -// ReencryptRequest share sent to a node in order to -// reencrypt a secret with the given public key +// ReencryptRequest share is sent to a node in order to reencrypt a secret +// using the original randomness K from the write request +// and the public key PubK of the reader type ReencryptRequest struct { - // K is the point from the writer - K kyber.Point - // PubK is the public key of the reader + K kyber.Point PubK kyber.Point } From 86be3a62085df29a15810f2bbc0b9b4de70b3106 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Mon, 26 Jun 2023 15:37:06 +0200 Subject: [PATCH 26/34] more changes after review --- dkg/dkg.go | 2 +- dkg/pedersen/controller/action.go | 49 +++++++++++++++---------------- dkg/pedersen/json/json.go | 15 ++++++---- dkg/pedersen/types/messages.go | 2 +- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/dkg/dkg.go b/dkg/dkg.go index 493387fe8..1d570fadf 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -34,7 +34,7 @@ type Actor interface { // Decrypt decrypts a ciphertext (composed of a K and an array of C's) // into the original message using the DKG internal private key // where K is the ephemeral DH (Diffie-Hellman) public key - // and Cs is the encrypted message + // and Cs is the encrypted points Decrypt(K kyber.Point, Cs []kyber.Point) ([]byte, error) // Reencrypt reencrypts generate a temporary key from the public key diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index 123da7b07..19ab5778c 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -315,43 +315,42 @@ func encodeEncrypted(k kyber.Point, cs []kyber.Point) (string, error) { return encoded, nil } -func decodeEncrypted(str string) (k kyber.Point, cs []kyber.Point, err error) { +func decodeEncrypted(str string) (kyber.Point, []kyber.Point, error) { parts := strings.Split(str, separator) if len(parts) < 2 { return nil, nil, xerrors.Errorf("malformed encoded: %s", str) } - for i, p := range parts { - if i == 0 { - // Decode K - kbuff, err := hex.DecodeString(p) - if err != nil { - return nil, nil, xerrors.Errorf("failed to decode k point: %v", err) - } + // Decode K + kbuff, err := hex.DecodeString(parts[0]) + if err != nil { + return nil, nil, xerrors.Errorf("failed to decode k point: %v", err) + } - k = suite.Point() + k := suite.Point() - err = k.UnmarshalBinary(kbuff) - if err != nil { - return nil, nil, xerrors.Errorf("failed to unmarshal k point: %v", err) - } + err = k.UnmarshalBinary(kbuff) + if err != nil { + return nil, nil, xerrors.Errorf("failed to unmarshal k point: %v", err) + } - } else { - // Decode C - cbuff, err := hex.DecodeString(p) - if err != nil { - return nil, nil, xerrors.Errorf("failed to decode c point: %v", err) - } + // Decode Cs + cs := make([]kyber.Point, 0, len(parts)-1) - c := suite.Point() + for _, p := range parts[1:] { + cbuff, err := hex.DecodeString(p) + if err != nil { + return nil, nil, xerrors.Errorf("failed to decode c point: %v", err) + } - err = c.UnmarshalBinary(cbuff) - if err != nil { - return nil, nil, xerrors.Errorf("failed to unmarshal c point: %v", err) - } + c := suite.Point() - cs = append(cs, c) + err = c.UnmarshalBinary(cbuff) + if err != nil { + return nil, nil, xerrors.Errorf("failed to unmarshal c point: %v", err) } + + cs = append(cs, c) } return k, cs, nil diff --git a/dkg/pedersen/json/json.go b/dkg/pedersen/json/json.go index 28771c9e7..ce6ba7e0a 100644 --- a/dkg/pedersen/json/json.go +++ b/dkg/pedersen/json/json.go @@ -10,6 +10,9 @@ import ( "golang.org/x/xerrors" ) +const ERROR_MARSHAL_K = "couldn't marshal K: %v" +const ERROR_UNMARSHAL_K = "couldn't unmarshal K: %v" + func init() { types.RegisterMessageFormat(serde.FormatJSON, newMsgFormat()) } @@ -530,7 +533,7 @@ func (f msgFormat) decodeStartDone(ctx serde.Context, msg *StartDone) (serde.Mes func encodeDecryptRequest(msg types.DecryptRequest) (Message, error) { k, err := msg.GetK().MarshalBinary() if err != nil { - return Message{}, xerrors.Errorf("couldn't marshal K: %v", err) + return Message{}, xerrors.Errorf(ERROR_MARSHAL_K, err) } c, err := msg.GetC().MarshalBinary() @@ -550,7 +553,7 @@ func (f msgFormat) decodeDecryptRequest(ctx serde.Context, msg *DecryptRequest) k := f.suite.Point() err := k.UnmarshalBinary(msg.K) if err != nil { - return nil, xerrors.Errorf("couldn't unmarshal K: %v", err) + return nil, xerrors.Errorf(ERROR_UNMARSHAL_K, err) } c := f.suite.Point() @@ -567,7 +570,7 @@ func (f msgFormat) decodeDecryptRequest(ctx serde.Context, msg *DecryptRequest) func encodeReencryptRequest(msg types.ReencryptRequest) (Message, error) { k, err := msg.K.MarshalBinary() if err != nil { - return Message{}, xerrors.Errorf("couldn't marshal K: %v", err) + return Message{}, xerrors.Errorf(ERROR_MARSHAL_K, err) } pubk, err := msg.PubK.MarshalBinary() @@ -624,7 +627,7 @@ func encodeVerifiableDecryptRequest(msg types.VerifiableDecryptRequest) (Message for _, cp := range ciphertexts { K, err := cp.K.MarshalBinary() if err != nil { - return Message{}, xerrors.Errorf("couldn't marshal K: %v", err) + return Message{}, xerrors.Errorf(ERROR_MARSHAL_K, err) } C, err := cp.C.MarshalBinary() @@ -681,7 +684,7 @@ func (f msgFormat) decodeVerifiableDecryptRequest(ctx serde.Context, K := f.suite.Point() err := K.UnmarshalBinary(cp.K) if err != nil { - return nil, xerrors.Errorf("couldn't unmarshal K: %v", err) + return nil, xerrors.Errorf(ERROR_UNMARSHAL_K, err) } C := f.suite.Point() @@ -862,7 +865,7 @@ func (f msgFormat) decodeReencryptRequest(ctx serde.Context, request *ReencryptR k := f.suite.Point() err := k.UnmarshalBinary(request.K) if err != nil { - return nil, xerrors.Errorf("couldn't unmarshal K: %v", err) + return nil, xerrors.Errorf(ERROR_UNMARSHAL_K, err) } pubk := f.suite.Point() diff --git a/dkg/pedersen/types/messages.go b/dkg/pedersen/types/messages.go index e4ca1fc6d..0e729dfe2 100644 --- a/dkg/pedersen/types/messages.go +++ b/dkg/pedersen/types/messages.go @@ -446,7 +446,7 @@ func (req DecryptRequest) Serialize(ctx serde.Context) ([]byte, error) { // ReencryptRequest share is sent to a node in order to reencrypt a secret // using the original randomness K from the write request -// and the public key PubK of the reader +// and the public key PubK from the reader type ReencryptRequest struct { K kyber.Point PubK kyber.Point From 127857ebb0450924d29d71b60c199af49b0e095f Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Tue, 27 Jun 2023 17:15:16 +0200 Subject: [PATCH 27/34] improved coverage --- dkg/pedersen/controller/action.go | 2 +- dkg/pedersen/controller/action_test.go | 118 ++++++++++++++++++++++++- dkg/pedersen/types/messages.go | 13 ++- dkg/pedersen/types/messages_test.go | 20 ++++- 4 files changed, 145 insertions(+), 8 deletions(-) diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index 19ab5778c..8f6b46b1a 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -283,7 +283,7 @@ func encodeReencrypted(xhatenc kyber.Point) (string, error) { func decodePublicKey(str string) (pk kyber.Point, err error) { pkbuff, err := hex.DecodeString(str) if err != nil { - return nil, xerrors.Errorf("failed to decode public key: %v", err) + return nil, xerrors.Errorf("malformed encoded: %s", str) } pk = suite.Point() diff --git a/dkg/pedersen/controller/action_test.go b/dkg/pedersen/controller/action_test.go index 3dc449e42..f85815da2 100644 --- a/dkg/pedersen/controller/action_test.go +++ b/dkg/pedersen/controller/action_test.go @@ -473,7 +473,7 @@ func TestDecryptAction_decryptFail(t *testing.T) { require.EqualError(t, err, fake.Err("failed to decrypt")) } -func TestDecryptAction_decryptOK(t *testing.T) { +func TestDecryptAction_OK(t *testing.T) { encrypted := "abea449f0ab86029c529f541cdd7f48aee3102b9c1ea2999b5d39c2cc49a4c23:ae29dd65cb4ceaaf7830008b9544625a05b6dbbcd421cf8475aedbef8e8d1da9" message := "fake" @@ -504,6 +504,119 @@ func TestDecryptAction_decryptOK(t *testing.T) { require.Equal(t, expected, out.String()) } +func TestReencryptAction_noActor(t *testing.T) { + a := reencryptAction{} + + inj := node.NewInjector() + + ctx := node.Context{ + Injector: inj, + } + + err := a.Execute(ctx) + require.EqualError(t, err, "failed to resolve actor, did you call listen?:"+ + " couldn't find dependency for 'dkg.Actor'") +} + +func TestReencryptAction_decodeEncryptedFail(t *testing.T) { + a := reencryptAction{} + + inj := node.NewInjector() + inj.Inject(fakeActor{}) + + flags := node.FlagSet{ + "encrypted": "not hex", + "pubk": "aabbcdd65cb4ceaaf7830008b9544625a05b6dbbcd421cf8475aedbef8e8d1da9", + } + + ctx := node.Context{ + Injector: inj, + Flags: flags, + } + + err := a.Execute(ctx) + require.EqualError(t, err, "failed to decode encrypted str: malformed encoded: not hex") +} + +func TestReencryptAction_decodePubkFail(t *testing.T) { + a := reencryptAction{} + + inj := node.NewInjector() + inj.Inject(fakeActor{}) + + flags := node.FlagSet{ + "encrypted": "abea449f0ab86029c529f541cdd7f48aee3102b9c1ea2999b5d39c2cc49a4c23:ae29dd65cb4ceaaf7830008b9544625a05b6dbbcd421cf8475aedbef8e8d1da9", + "pubk": "not hex", + } + + ctx := node.Context{ + Injector: inj, + Flags: flags, + } + + err := a.Execute(ctx) + require.EqualError(t, err, "failed to decode public key str: malformed encoded: not hex") +} + +func TestReencryptAction_reencryptFail(t *testing.T) { + encrypted := "abea449f0ab86029c529f541cdd7f48aee3102b9c1ea2999b5d39c2cc49a4c23:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + pubk := "ae29dd65cb4ceaaf7830008b9544625a05b6dbbcd421cf8475aedbef8e8d1da9" + + a := reencryptAction{} + + inj := node.NewInjector() + inj.Inject(fakeActor{ + reencryptErr: fake.GetError(), + }) + + flags := node.FlagSet{ + "encrypted": encrypted, + "pubk": pubk, + } + + ctx := node.Context{ + Injector: inj, + Flags: flags, + } + + err := a.Execute(ctx) + require.EqualError(t, err, fake.Err("failed to reencrypt")) +} + +func TestReencryptAction_OK(t *testing.T) { + encrypted := "abea449f0ab86029c529f541cdd7f48aee3102b9c1ea2999b5d39c2cc49a4c23:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + pubk := "ae29dd65cb4ceaaf7830008b9544625a05b6dbbcd421cf8475aedbef8e8d1da9" + + sk := suite.Scalar().Pick(suite.RandomStream()) + pk := suite.Point().Mul(sk, nil) // we just need a Ed25519 valid point + expected, err := pk.MarshalBinary() + require.NoError(t, err, "unable to initialise the point") + + inj := node.NewInjector() + inj.Inject(fakeActor{ + xhatenc: pk, + }) + + flags := node.FlagSet{ + "encrypted": encrypted, + "pubk": pubk, + } + + out := &bytes.Buffer{} + + ctx := node.Context{ + Injector: inj, + Flags: flags, + Out: out, + } + + a := reencryptAction{} + err = a.Execute(ctx) + require.NoError(t, err) + + require.Equal(t, hex.EncodeToString(expected), out.String()) +} + func TestEncodeEncrypted_marshalKFail(t *testing.T) { fakeK := badPoint{err: fake.GetError()} fakeCs := make([]kyber.Point, 0, 1) @@ -1400,6 +1513,7 @@ type fakeActor struct { cs []kyber.Point decryptData []byte + xhatenc kyber.Point ct types.Ciphertext vdecryptData [][]byte } @@ -1417,7 +1531,7 @@ func (f fakeActor) Decrypt(K kyber.Point, CS []kyber.Point) ([]byte, error) { } func (f fakeActor) Reencrypt(K kyber.Point, PK kyber.Point) (XhatEnc kyber.Point, err error) { - return nil, f.reencryptErr + return f.xhatenc, f.reencryptErr } func (f fakeActor) VerifiableEncrypt(message []byte, GBar kyber.Point) (ciphertext types.Ciphertext, remainder []byte, err error) { diff --git a/dkg/pedersen/types/messages.go b/dkg/pedersen/types/messages.go index 0e729dfe2..2e0b58eca 100644 --- a/dkg/pedersen/types/messages.go +++ b/dkg/pedersen/types/messages.go @@ -13,6 +13,14 @@ import ( // encoded const couldntEncodeDecryptRequest = "couldn't encode decrypt request: %v" +// couldntEncodeReencryptRequest indicates that a reencrypt request couldn't be +// encoded +const couldntEncodeReencryptRequest = "couldn't encode reencrypt request: %v" + +// couldntEncodeReencryptReply indicates that a reencrypt reply couldn't be +// encoded +const couldntEncodeReencryptReply = "couldn't encode reencrypt reply: %v" + // Ciphertext provides the verifiable encryption function. A description can be // found in https://arxiv.org/pdf/2205.08529.pdf. The equivalent of each // parameter in the paper is written in front of it. @@ -38,7 +46,6 @@ type ShareAndProof struct { Ei kyber.Scalar // e_i Fi kyber.Scalar // f_i Hi kyber.Point // h_i - } var msgFormats = registry.NewSimpleRegistry() @@ -466,7 +473,7 @@ func (req ReencryptRequest) Serialize(ctx serde.Context) ([]byte, error) { data, err := format.Encode(ctx, req) if err != nil { - return nil, xerrors.Errorf(couldntEncodeDecryptRequest, err) + return nil, xerrors.Errorf(couldntEncodeReencryptRequest, err) } return data, nil @@ -496,7 +503,7 @@ func (reply ReencryptReply) Serialize(ctx serde.Context) ([]byte, error) { data, err := format.Encode(ctx, reply) if err != nil { - return nil, xerrors.Errorf(couldntEncodeDecryptRequest, err) + return nil, xerrors.Errorf(couldntEncodeReencryptReply, err) } return data, nil diff --git a/dkg/pedersen/types/messages_test.go b/dkg/pedersen/types/messages_test.go index cf96d64c9..336d02c91 100644 --- a/dkg/pedersen/types/messages_test.go +++ b/dkg/pedersen/types/messages_test.go @@ -2,6 +2,7 @@ package types import ( "bytes" + "go.dedis.ch/kyber/v3/share" "testing" "testing/quick" @@ -261,14 +262,15 @@ func TestDecryptRequest_Serialize(t *testing.T) { } func TestReencryptRequest_Serialize(t *testing.T) { - req := ReencryptRequest{} + var fakePoint kyber.Point + req := NewReencryptRequest(fakePoint, fakePoint) data, err := req.Serialize(fake.NewContext()) require.NoError(t, err) require.Equal(t, fake.GetFakeFormatValue(), data) _, err = req.Serialize(fake.NewBadContext()) - require.EqualError(t, err, fake.Err("couldn't encode decrypt request")) + require.ErrorContains(t, err, fake.Err("couldn't encode reencrypt request")) } func TestVerifiableDecryptRequest_Get(t *testing.T) { @@ -311,6 +313,20 @@ func TestDecryptReply_Serialize(t *testing.T) { require.EqualError(t, err, fake.Err("couldn't encode decrypt reply")) } +func TestReencryptReply_Serialize(t *testing.T) { + var fpoint kyber.Point + var fscalar kyber.Scalar + var fshare share.PubShare + resp := NewReencryptReply(fpoint, &fshare, fscalar, fscalar) + + data, err := resp.Serialize(fake.NewContext()) + require.NoError(t, err) + require.Equal(t, fake.GetFakeFormatValue(), data) + + _, err = resp.Serialize(fake.NewBadContext()) + require.EqualError(t, err, fake.Err("couldn't encode reencrypt reply")) +} + func TestVerifiableDecryptReply_Get(t *testing.T) { req := NewVerifiableDecryptReply([]ShareAndProof{{}, {}}) From be71904079ba88da5d441e3cb4c2a1ad2a963c57 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 28 Jun 2023 08:33:11 +0200 Subject: [PATCH 28/34] reduce code smell --- dkg/pedersen/controller/action.go | 7 ++++--- test/testcreatekey.sh | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index 8f6b46b1a..f28fcb664 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -26,6 +26,7 @@ var suite = suites.MustFind("Ed25519") const separator = ":" const authconfig = "dkgauthority" const resolveActorFailed = "failed to resolve actor, did you call listen?: %v" +const malformedEncoded = "malformed encoded: %s" type setupAction struct{} @@ -283,7 +284,7 @@ func encodeReencrypted(xhatenc kyber.Point) (string, error) { func decodePublicKey(str string) (pk kyber.Point, err error) { pkbuff, err := hex.DecodeString(str) if err != nil { - return nil, xerrors.Errorf("malformed encoded: %s", str) + return nil, xerrors.Errorf(malformedEncoded, str) } pk = suite.Point() @@ -318,7 +319,7 @@ func encodeEncrypted(k kyber.Point, cs []kyber.Point) (string, error) { func decodeEncrypted(str string) (kyber.Point, []kyber.Point, error) { parts := strings.Split(str, separator) if len(parts) < 2 { - return nil, nil, xerrors.Errorf("malformed encoded: %s", str) + return nil, nil, xerrors.Errorf(malformedEncoded, str) } // Decode K @@ -467,7 +468,7 @@ func (a verifiableDecryptAction) Execute(ctx node.Context) error { parts := strings.Split(ciphertextString, separator) if len(parts)%5 != 0 { - return xerrors.Errorf("malformed encoded: %s", ciphertextString) + return xerrors.Errorf(MalformedEncoded, ciphertextString) } batchSize := len(parts) / 5 diff --git a/test/testcreatekey.sh b/test/testcreatekey.sh index beba279c8..9eb7e4812 100755 --- a/test/testcreatekey.sh +++ b/test/testcreatekey.sh @@ -8,3 +8,4 @@ NC='\033[0m' # No Color echo -e "${GREEN}[PK]${NC} create a private key for the manual test" crypto bls signer new --save private.key crypto bls signer read --path private.key --format BASE64 +crypto bls signer read --path private.key --format BASE64_PUBKEY From 50ca841428858374cb69f7859abb5b584f645cfa Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 28 Jun 2023 08:36:21 +0200 Subject: [PATCH 29/34] typo --- dkg/pedersen/controller/action.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index f28fcb664..ed4987b20 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -468,7 +468,7 @@ func (a verifiableDecryptAction) Execute(ctx node.Context) error { parts := strings.Split(ciphertextString, separator) if len(parts)%5 != 0 { - return xerrors.Errorf(MalformedEncoded, ciphertextString) + return xerrors.Errorf(malformedEncoded, ciphertextString) } batchSize := len(parts) / 5 From 8372319ab9e1f8aaef173b4b33f5dd72c92fbbec Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Tue, 18 Jul 2023 15:15:31 +0200 Subject: [PATCH 30/34] Test threshold at DKG setup --- dkg/pedersen/controller/action.go | 3 +++ dkg/pedersen/pedersen.go | 4 ++++ dkg/pedersen/pedersen_test.go | 5 +++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index ed4987b20..204b03a39 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -44,6 +44,9 @@ func (a setupAction) Execute(ctx node.Context) error { } t := ctx.Flags.Int("threshold") + if t < 2 || t > co.Len() { + return xerrors.Errorf("thresold (%d) needs to be between 2 and %d", t, co.Len()) + } pubkey, err := actor.Setup(co, t) if err != nil { diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 92f5c6bab..2b20c2154 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -118,6 +118,10 @@ func (a *Actor) Setup(coAuth crypto.CollectiveAuthority, threshold int) (kyber.P return nil, xerrors.Errorf("startRes is already done, only one setup call is allowed") } + if threshold <= 1 { + return nil, xerrors.Errorf("DKG threshold needs to be > 1") + } + ctx, cancel := context.WithTimeout(context.Background(), setupTimeout) defer cancel() ctx = context.WithValue(ctx, tracing.ProtocolKey, protocolNameSetup) diff --git a/dkg/pedersen/pedersen_test.go b/dkg/pedersen/pedersen_test.go index afd32251b..656c77aac 100644 --- a/dkg/pedersen/pedersen_test.go +++ b/dkg/pedersen/pedersen_test.go @@ -482,9 +482,10 @@ func (s fakeSigner) GetPublicKey() crypto.PublicKey { // decryptReencrypted helps to decrypt a reencrypted message. func decryptReencrypted(Cs []kyber.Point, XhatEnc kyber.Point, dkgPk kyber.Point, Sk kyber.Scalar) (msg []byte, err error) { - dela.Logger.Debug().Msgf("DKG pubK:%v", dkgPk) + dela.Logger.Debug().Msgf("XhatEnc:%v", XhatEnc) - dela.Logger.Debug().Msgf("xc:%v", Sk) + dela.Logger.Debug().Msgf("DKG pubK:%v", dkgPk) + dela.Logger.Debug().Msgf("Sk:%v", Sk) xcInv := suite.Scalar().Neg(Sk) dela.Logger.Debug().Msgf("xcInv:%v", xcInv) From aefac529c56449f3ac530fe3800b3d4c22ca5d5a Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Tue, 18 Jul 2023 15:46:44 +0200 Subject: [PATCH 31/34] Refactor Reencrypt status --- dkg/pedersen/reencrypt.go | 49 ++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/dkg/pedersen/reencrypt.go b/dkg/pedersen/reencrypt.go index e5988550a..9a1a31db5 100644 --- a/dkg/pedersen/reencrypt.go +++ b/dkg/pedersen/reencrypt.go @@ -12,7 +12,7 @@ import ( "golang.org/x/xerrors" ) -type onChainSecret struct { +type reencryptStatus struct { K kyber.Point // K is the random part of the encrypted secret pubk kyber.Point // The client's public key @@ -24,14 +24,6 @@ type onChainSecret struct { Uis []*share.PubShare // re-encrypted shares } -// newOCS creates a new on-chain secret structure. -func newOCS(K kyber.Point, pubk kyber.Point) *onChainSecret { - return &onChainSecret{ - K: K, - pubk: pubk, - } -} - // Reencrypt implements dkg.Actor. func (a *Actor) Reencrypt(K kyber.Point, pubk kyber.Point) (XhatEnc kyber.Point, err error) { if !a.startRes.Done() { @@ -63,11 +55,14 @@ func (a *Actor) Reencrypt(K kyber.Point, pubk kyber.Point) (XhatEnc kyber.Point, return nil, xerrors.Errorf("failed to send reencrypt request: %v", err) } - ocs := newOCS(K, pubk) - ocs.nbnodes = len(addrs) - ocs.threshold = a.startRes.getThreshold() + status := &reencryptStatus{ + K: K, + pubk: pubk, + } + status.nbnodes = len(addrs) + status.threshold = a.startRes.getThreshold() - for i := 0; i < ocs.nbnodes; i++ { + for i := 0; i < status.nbnodes; i++ { src, rxMsg, err := receiver.Recv(ctx) if err != nil { return nil, xerrors.Errorf(unexpectedStreamStop, err) @@ -80,11 +75,11 @@ func (a *Actor) Reencrypt(K kyber.Point, pubk kyber.Point) (XhatEnc kyber.Point, return nil, xerrors.Errorf(unexpectedReply, reply, rxMsg) } - err = processReencryptReply(ocs, &reply) + err = status.processReencryptReply(&reply) if err == nil { - dela.Logger.Debug().Msgf("Reencryption Uis: %v", ocs.Uis) + dela.Logger.Debug().Msgf("Reencryption Uis: %v", status.Uis) - XhatEnc, err := share.RecoverCommit(suites.MustFind("Ed25519"), ocs.Uis, ocs.threshold, ocs.nbnodes) + XhatEnc, err := share.RecoverCommit(suites.MustFind("Ed25519"), status.Uis, status.threshold, status.nbnodes) if err != nil { return nil, xerrors.Errorf("Reencryption failed: %v", err) } @@ -97,33 +92,33 @@ func (a *Actor) Reencrypt(K kyber.Point, pubk kyber.Point) (XhatEnc kyber.Point, return nil, xerrors.Errorf("Reencryption failed: %v", err) } -func processReencryptReply(ocs *onChainSecret, reply *types.ReencryptReply) (err error) { +func (s *reencryptStatus) processReencryptReply(reply *types.ReencryptReply) (err error) { if reply.Ui == nil { err = xerrors.Errorf("Received empty reply") dela.Logger.Warn().Msg("Empty reply received") - ocs.nbfailures++ - if ocs.nbfailures > ocs.nbnodes-ocs.threshold { + s.nbfailures++ + if s.nbfailures > s.nbnodes-s.threshold { err = xerrors.Errorf("couldn't get enough shares") dela.Logger.Warn().Msg(err.Error()) } return err } - ocs.replies = append(ocs.replies, *reply) + s.replies = append(s.replies, *reply) - if len(ocs.replies) >= ocs.threshold { - ocs.Uis = make([]*share.PubShare, 0, ocs.nbnodes) + if len(s.replies) >= s.threshold { + s.Uis = make([]*share.PubShare, 0, s.nbnodes) - for _, r := range ocs.replies { + for _, r := range s.replies { /* // Verify proofs - ufi := suite.Point().Mul(r.Fi, suite.Point().Add(ocs.U, ocs.pubk)) + ufi := suite.Point().Mul(r.Fi, suite.Point().Add(s.U, s.pubk)) uiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), r.Ui.V) uiHat := suite.Point().Add(ufi, uiei) gfi := suite.Point().Mul(r.Fi, nil) - gxi := ocs.poly.Eval(r.Ui.I).V + gxi := s.poly.Eval(r.Ui.I).V hiei := suite.Point().Mul(suite.Scalar().Neg(r.Ei), gxi) hiHat := suite.Point().Add(gfi, hiei) hash := sha256.New() @@ -134,13 +129,13 @@ func processReencryptReply(ocs *onChainSecret, reply *types.ReencryptReply) (err if e.Equal(r.Ei) { */ - ocs.Uis = append(ocs.Uis, r.Ui) + s.Uis = append(s.Uis, r.Ui) /* } else { dela.Logger.Warn().Msgf("Received invalid share from node: %v", r.Ui.I) - ocs.nbfailures++ + s.nbfailures++ } */ } From 96596fdc17bcee51d57623e8a0f70c96eecdef46 Mon Sep 17 00:00:00 2001 From: jbsv <90860471+jbsv@users.noreply.github.com> Date: Wed, 19 Jul 2023 10:04:59 +0200 Subject: [PATCH 32/34] Update threshold condition Co-authored-by: pierluca --- dkg/pedersen/pedersen.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 2b20c2154..2efd6af5d 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -118,8 +118,8 @@ func (a *Actor) Setup(coAuth crypto.CollectiveAuthority, threshold int) (kyber.P return nil, xerrors.Errorf("startRes is already done, only one setup call is allowed") } - if threshold <= 1 { - return nil, xerrors.Errorf("DKG threshold needs to be > 1") + if threshold < 2 || threshold > coAuth.Len() { + return nil, xerrors.Errorf("DKG thresold (%d) needs to be between 2 and %d", threshold, coAuth.Len())``` } ctx, cancel := context.WithTimeout(context.Background(), setupTimeout) From 6c8bc186a39b3c00df501fb72d8bc075a2f4af04 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 19 Jul 2023 10:17:32 +0200 Subject: [PATCH 33/34] clean up after review --- dkg/pedersen/controller/action.go | 3 --- dkg/pedersen/pedersen.go | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/dkg/pedersen/controller/action.go b/dkg/pedersen/controller/action.go index 204b03a39..ed4987b20 100644 --- a/dkg/pedersen/controller/action.go +++ b/dkg/pedersen/controller/action.go @@ -44,9 +44,6 @@ func (a setupAction) Execute(ctx node.Context) error { } t := ctx.Flags.Int("threshold") - if t < 2 || t > co.Len() { - return xerrors.Errorf("thresold (%d) needs to be between 2 and %d", t, co.Len()) - } pubkey, err := actor.Setup(co, t) if err != nil { diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index 2efd6af5d..aa72fd555 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -119,7 +119,7 @@ func (a *Actor) Setup(coAuth crypto.CollectiveAuthority, threshold int) (kyber.P } if threshold < 2 || threshold > coAuth.Len() { - return nil, xerrors.Errorf("DKG thresold (%d) needs to be between 2 and %d", threshold, coAuth.Len())``` + return nil, xerrors.Errorf("DKG threshold (%d) needs to be between 2 and %d", threshold, coAuth.Len()) } ctx, cancel := context.WithTimeout(context.Background(), setupTimeout) From 0f1fd03bee39ebcfdc07fc151564d8e1a9ae1d51 Mon Sep 17 00:00:00 2001 From: Jean Viaene Date: Wed, 19 Jul 2023 10:50:50 +0200 Subject: [PATCH 34/34] tidy up threshold --- dkg/pedersen/pedersen.go | 15 +++++++++++++-- dkg/pedersen/pedersen_test.go | 20 +++++++++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/dkg/pedersen/pedersen.go b/dkg/pedersen/pedersen.go index aa72fd555..6b6e2a087 100644 --- a/dkg/pedersen/pedersen.go +++ b/dkg/pedersen/pedersen.go @@ -118,8 +118,19 @@ func (a *Actor) Setup(coAuth crypto.CollectiveAuthority, threshold int) (kyber.P return nil, xerrors.Errorf("startRes is already done, only one setup call is allowed") } - if threshold < 2 || threshold > coAuth.Len() { - return nil, xerrors.Errorf("DKG threshold (%d) needs to be between 2 and %d", threshold, coAuth.Len()) + nbNodes := coAuth.Len() + if nbNodes == 0 { + return nil, xerrors.Errorf("number of nodes cannot be zero") + } + + thresholdMin := 2 + if nbNodes < 2 { + thresholdMin = 1 + } + + if threshold < thresholdMin || threshold > nbNodes { + return nil, xerrors.Errorf("DKG threshold (%d) needs to be between %d and %d", + threshold, thresholdMin, nbNodes) } ctx, cancel := context.WithTimeout(context.Background(), setupTimeout) diff --git a/dkg/pedersen/pedersen_test.go b/dkg/pedersen/pedersen_test.go index 656c77aac..60a0bfdcf 100644 --- a/dkg/pedersen/pedersen_test.go +++ b/dkg/pedersen/pedersen_test.go @@ -37,33 +37,39 @@ func TestPedersen_Setup(t *testing.T) { startRes: &state{}, } - fakeAuthority := fake.NewAuthority(1, fake.NewSigner) + fakeAuthority := fake.NewAuthority(0, fake.NewSigner) + _, err := actor.Setup(fakeAuthority, 1) + require.EqualError(t, err, "number of nodes cannot be zero") - _, err := actor.Setup(fakeAuthority, 0) + fakeAuthority = fake.NewAuthority(1, fake.NewSigner) + _, err = actor.Setup(fakeAuthority, 0) + require.ErrorContains(t, err, "DKG threshold (0) needs to be between") + + _, err = actor.Setup(fakeAuthority, 1) require.EqualError(t, err, fake.Err("failed to stream")) rpc := fake.NewStreamRPC(fake.NewReceiver(), fake.NewBadSender()) actor.rpc = rpc - _, err = actor.Setup(fakeAuthority, 0) + _, err = actor.Setup(fakeAuthority, 1) require.EqualError(t, err, "expected ed25519.PublicKey, got 'fake.PublicKey'") fakeAuthority = fake.NewAuthority(2, ed25519.NewSigner) - _, err = actor.Setup(fakeAuthority, 1) + _, err = actor.Setup(fakeAuthority, 2) require.EqualError(t, err, fake.Err("failed to send start")) rpc = fake.NewStreamRPC(fake.NewBadReceiver(), fake.Sender{}) actor.rpc = rpc - _, err = actor.Setup(fakeAuthority, 1) + _, err = actor.Setup(fakeAuthority, 2) require.EqualError(t, err, fake.Err("got an error from '%!s()' while receiving")) recv := fake.NewReceiver(fake.NewRecvMsg(fake.NewAddress(0), nil)) actor.rpc = fake.NewStreamRPC(recv, fake.Sender{}) - _, err = actor.Setup(fakeAuthority, 1) + _, err = actor.Setup(fakeAuthority, 2) require.EqualError(t, err, "expected to receive a Done message, but go the following: ") rpc = fake.NewStreamRPC(fake.NewReceiver( @@ -72,7 +78,7 @@ func TestPedersen_Setup(t *testing.T) { ), fake.Sender{}) actor.rpc = rpc - _, err = actor.Setup(fakeAuthority, 1) + _, err = actor.Setup(fakeAuthority, 2) require.Error(t, err) require.Regexp(t, "^the public keys does not match:", err) }