diff --git a/dkg/dkg.go b/dkg/dkg.go index 2d7db3d94..3d20f512a 100644 --- a/dkg/dkg.go +++ b/dkg/dkg.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" "github.com/obolnetwork/charon/app/errors" "github.com/obolnetwork/charon/app/log" @@ -70,20 +71,38 @@ func Run(ctx context.Context, conf Config) error { if err != nil { return errors.Wrap(err, "hash definition") } - - tp := p2pTransport{ - tcpNode: tcpNode, - peers: peers, - clusterID: fmt.Sprintf("%x", defHash[:]), - } + clusterID := fmt.Sprintf("%x", defHash[:]) var shares []share switch def.DKGAlgorithm { case "default", "keycast": + tp := keycastP2P{ + tcpNode: tcpNode, + peers: peers, + clusterID: clusterID, + } + shares, err = runKeyCast(ctx, def, tp, nodeIdx.PeerIdx, crand.Reader) if err != nil { return err } + case "frost": + // Construct peer map + peerMap := make(map[uint32]peer.ID) + for _, p := range peers { + nodeIdx, err := def.NodeIdx(p.ID) + if err != nil { + return err + } + peerMap[uint32(nodeIdx.ShareIdx)] = p.ID + } + tp := newFrostP2P(ctx, tcpNode, peerMap, clusterID) + + shares, err = runFrostParallel(ctx, tp, uint32(def.NumValidators), uint32(len(peerMap)), + uint32(def.Threshold), uint32(nodeIdx.ShareIdx), clusterID) + if err != nil { + return err + } default: return errors.New("unsupported dkg algorithm") } @@ -102,7 +121,7 @@ func Run(ctx context.Context, conf Config) error { Validators: dvs, } - aggsig, err := aggSignLockHash(ctx, tp, lock) + aggsig, err := aggSignLockHash(ctx, nil, lock) if err != nil { return err } diff --git a/dkg/dkgpb/v1/frost.pb.go b/dkg/dkgpb/v1/frost.pb.go new file mode 100644 index 000000000..780c5cb8e --- /dev/null +++ b/dkg/dkgpb/v1/frost.pb.go @@ -0,0 +1,569 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc (unknown) +// source: dkg/dkgpb/v1/frost.proto + +package v1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type FrostMsgKey struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ValIdx uint32 `protobuf:"varint,1,opt,name=val_idx,json=valIdx,proto3" json:"val_idx,omitempty"` + SourceId uint32 `protobuf:"varint,2,opt,name=source_id,json=sourceId,proto3" json:"source_id,omitempty"` + TargetId uint32 `protobuf:"varint,3,opt,name=target_id,json=targetId,proto3" json:"target_id,omitempty"` +} + +func (x *FrostMsgKey) Reset() { + *x = FrostMsgKey{} + if protoimpl.UnsafeEnabled { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FrostMsgKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FrostMsgKey) ProtoMessage() {} + +func (x *FrostMsgKey) ProtoReflect() protoreflect.Message { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FrostMsgKey.ProtoReflect.Descriptor instead. +func (*FrostMsgKey) Descriptor() ([]byte, []int) { + return file_dkg_dkgpb_v1_frost_proto_rawDescGZIP(), []int{0} +} + +func (x *FrostMsgKey) GetValIdx() uint32 { + if x != nil { + return x.ValIdx + } + return 0 +} + +func (x *FrostMsgKey) GetSourceId() uint32 { + if x != nil { + return x.SourceId + } + return 0 +} + +func (x *FrostMsgKey) GetTargetId() uint32 { + if x != nil { + return x.TargetId + } + return 0 +} + +type FrostRound1Cast struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key *FrostMsgKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Wi []byte `protobuf:"bytes,2,opt,name=wi,proto3" json:"wi,omitempty"` + Ci []byte `protobuf:"bytes,3,opt,name=ci,proto3" json:"ci,omitempty"` + Commitments [][]byte `protobuf:"bytes,4,rep,name=commitments,proto3" json:"commitments,omitempty"` +} + +func (x *FrostRound1Cast) Reset() { + *x = FrostRound1Cast{} + if protoimpl.UnsafeEnabled { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FrostRound1Cast) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FrostRound1Cast) ProtoMessage() {} + +func (x *FrostRound1Cast) ProtoReflect() protoreflect.Message { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FrostRound1Cast.ProtoReflect.Descriptor instead. +func (*FrostRound1Cast) Descriptor() ([]byte, []int) { + return file_dkg_dkgpb_v1_frost_proto_rawDescGZIP(), []int{1} +} + +func (x *FrostRound1Cast) GetKey() *FrostMsgKey { + if x != nil { + return x.Key + } + return nil +} + +func (x *FrostRound1Cast) GetWi() []byte { + if x != nil { + return x.Wi + } + return nil +} + +func (x *FrostRound1Cast) GetCi() []byte { + if x != nil { + return x.Ci + } + return nil +} + +func (x *FrostRound1Cast) GetCommitments() [][]byte { + if x != nil { + return x.Commitments + } + return nil +} + +type ShamirShare struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key *FrostMsgKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Id uint32 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` + Value []byte `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *ShamirShare) Reset() { + *x = ShamirShare{} + if protoimpl.UnsafeEnabled { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ShamirShare) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ShamirShare) ProtoMessage() {} + +func (x *ShamirShare) ProtoReflect() protoreflect.Message { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ShamirShare.ProtoReflect.Descriptor instead. +func (*ShamirShare) Descriptor() ([]byte, []int) { + return file_dkg_dkgpb_v1_frost_proto_rawDescGZIP(), []int{2} +} + +func (x *ShamirShare) GetKey() *FrostMsgKey { + if x != nil { + return x.Key + } + return nil +} + +func (x *ShamirShare) GetId() uint32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *ShamirShare) GetValue() []byte { + if x != nil { + return x.Value + } + return nil +} + +type FrostRound1Msg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Casts []*FrostRound1Cast `protobuf:"bytes,1,rep,name=casts,proto3" json:"casts,omitempty"` + P2Ps []*ShamirShare `protobuf:"bytes,2,rep,name=p2ps,proto3" json:"p2ps,omitempty"` +} + +func (x *FrostRound1Msg) Reset() { + *x = FrostRound1Msg{} + if protoimpl.UnsafeEnabled { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FrostRound1Msg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FrostRound1Msg) ProtoMessage() {} + +func (x *FrostRound1Msg) ProtoReflect() protoreflect.Message { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FrostRound1Msg.ProtoReflect.Descriptor instead. +func (*FrostRound1Msg) Descriptor() ([]byte, []int) { + return file_dkg_dkgpb_v1_frost_proto_rawDescGZIP(), []int{3} +} + +func (x *FrostRound1Msg) GetCasts() []*FrostRound1Cast { + if x != nil { + return x.Casts + } + return nil +} + +func (x *FrostRound1Msg) GetP2Ps() []*ShamirShare { + if x != nil { + return x.P2Ps + } + return nil +} + +type FrostRound2Cast struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key *FrostMsgKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + VerificationKey []byte `protobuf:"bytes,2,opt,name=verification_key,json=verificationKey,proto3" json:"verification_key,omitempty"` + VkShare []byte `protobuf:"bytes,3,opt,name=vk_share,json=vkShare,proto3" json:"vk_share,omitempty"` +} + +func (x *FrostRound2Cast) Reset() { + *x = FrostRound2Cast{} + if protoimpl.UnsafeEnabled { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FrostRound2Cast) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FrostRound2Cast) ProtoMessage() {} + +func (x *FrostRound2Cast) ProtoReflect() protoreflect.Message { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FrostRound2Cast.ProtoReflect.Descriptor instead. +func (*FrostRound2Cast) Descriptor() ([]byte, []int) { + return file_dkg_dkgpb_v1_frost_proto_rawDescGZIP(), []int{4} +} + +func (x *FrostRound2Cast) GetKey() *FrostMsgKey { + if x != nil { + return x.Key + } + return nil +} + +func (x *FrostRound2Cast) GetVerificationKey() []byte { + if x != nil { + return x.VerificationKey + } + return nil +} + +func (x *FrostRound2Cast) GetVkShare() []byte { + if x != nil { + return x.VkShare + } + return nil +} + +type FrostRound2Msg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Casts []*FrostRound2Cast `protobuf:"bytes,1,rep,name=casts,proto3" json:"casts,omitempty"` +} + +func (x *FrostRound2Msg) Reset() { + *x = FrostRound2Msg{} + if protoimpl.UnsafeEnabled { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FrostRound2Msg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FrostRound2Msg) ProtoMessage() {} + +func (x *FrostRound2Msg) ProtoReflect() protoreflect.Message { + mi := &file_dkg_dkgpb_v1_frost_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FrostRound2Msg.ProtoReflect.Descriptor instead. +func (*FrostRound2Msg) Descriptor() ([]byte, []int) { + return file_dkg_dkgpb_v1_frost_proto_rawDescGZIP(), []int{5} +} + +func (x *FrostRound2Msg) GetCasts() []*FrostRound2Cast { + if x != nil { + return x.Casts + } + return nil +} + +var File_dkg_dkgpb_v1_frost_proto protoreflect.FileDescriptor + +var file_dkg_dkgpb_v1_frost_proto_rawDesc = []byte{ + 0x0a, 0x18, 0x64, 0x6b, 0x67, 0x2f, 0x64, 0x6b, 0x67, 0x70, 0x62, 0x2f, 0x76, 0x31, 0x2f, 0x66, + 0x72, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x64, 0x6b, 0x67, 0x2e, + 0x64, 0x6b, 0x67, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x22, 0x60, 0x0a, 0x0b, 0x46, 0x72, 0x6f, 0x73, + 0x74, 0x4d, 0x73, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x76, 0x61, 0x6c, 0x5f, 0x69, + 0x64, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x49, 0x64, 0x78, + 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, + 0x09, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x08, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x64, 0x22, 0x80, 0x01, 0x0a, 0x0f, 0x46, + 0x72, 0x6f, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x31, 0x43, 0x61, 0x73, 0x74, 0x12, 0x2b, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x64, 0x6b, + 0x67, 0x2e, 0x64, 0x6b, 0x67, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x72, 0x6f, 0x73, 0x74, + 0x4d, 0x73, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x77, + 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x77, 0x69, 0x12, 0x0e, 0x0a, 0x02, 0x63, + 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x63, 0x69, 0x12, 0x20, 0x0a, 0x0b, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, + 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x60, 0x0a, + 0x0b, 0x53, 0x68, 0x61, 0x6d, 0x69, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x12, 0x2b, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x64, 0x6b, 0x67, 0x2e, + 0x64, 0x6b, 0x67, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x72, 0x6f, 0x73, 0x74, 0x4d, 0x73, + 0x67, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x74, 0x0a, 0x0e, 0x46, 0x72, 0x6f, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x31, 0x4d, 0x73, + 0x67, 0x12, 0x33, 0x0a, 0x05, 0x63, 0x61, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x64, 0x6b, 0x67, 0x2e, 0x64, 0x6b, 0x67, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, + 0x46, 0x72, 0x6f, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x31, 0x43, 0x61, 0x73, 0x74, 0x52, + 0x05, 0x63, 0x61, 0x73, 0x74, 0x73, 0x12, 0x2d, 0x0a, 0x04, 0x70, 0x32, 0x70, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x64, 0x6b, 0x67, 0x2e, 0x64, 0x6b, 0x67, 0x70, 0x62, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x68, 0x61, 0x6d, 0x69, 0x72, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, + 0x04, 0x70, 0x32, 0x70, 0x73, 0x22, 0x84, 0x01, 0x0a, 0x0f, 0x46, 0x72, 0x6f, 0x73, 0x74, 0x52, + 0x6f, 0x75, 0x6e, 0x64, 0x32, 0x43, 0x61, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x64, 0x6b, 0x67, 0x2e, 0x64, 0x6b, 0x67, + 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x72, 0x6f, 0x73, 0x74, 0x4d, 0x73, 0x67, 0x4b, 0x65, + 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, + 0x79, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x6b, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x76, 0x6b, 0x53, 0x68, 0x61, 0x72, 0x65, 0x22, 0x45, 0x0a, 0x0e, + 0x46, 0x72, 0x6f, 0x73, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x32, 0x4d, 0x73, 0x67, 0x12, 0x33, + 0x0a, 0x05, 0x63, 0x61, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x64, 0x6b, 0x67, 0x2e, 0x64, 0x6b, 0x67, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x72, 0x6f, + 0x73, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x32, 0x43, 0x61, 0x73, 0x74, 0x52, 0x05, 0x63, 0x61, + 0x73, 0x74, 0x73, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x6f, 0x62, 0x6f, 0x6c, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x63, 0x68, + 0x61, 0x72, 0x6f, 0x6e, 0x2f, 0x64, 0x6b, 0x67, 0x2f, 0x64, 0x6b, 0x67, 0x70, 0x62, 0x2f, 0x76, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_dkg_dkgpb_v1_frost_proto_rawDescOnce sync.Once + file_dkg_dkgpb_v1_frost_proto_rawDescData = file_dkg_dkgpb_v1_frost_proto_rawDesc +) + +func file_dkg_dkgpb_v1_frost_proto_rawDescGZIP() []byte { + file_dkg_dkgpb_v1_frost_proto_rawDescOnce.Do(func() { + file_dkg_dkgpb_v1_frost_proto_rawDescData = protoimpl.X.CompressGZIP(file_dkg_dkgpb_v1_frost_proto_rawDescData) + }) + return file_dkg_dkgpb_v1_frost_proto_rawDescData +} + +var file_dkg_dkgpb_v1_frost_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_dkg_dkgpb_v1_frost_proto_goTypes = []interface{}{ + (*FrostMsgKey)(nil), // 0: dkg.dkgpb.v1.FrostMsgKey + (*FrostRound1Cast)(nil), // 1: dkg.dkgpb.v1.FrostRound1Cast + (*ShamirShare)(nil), // 2: dkg.dkgpb.v1.ShamirShare + (*FrostRound1Msg)(nil), // 3: dkg.dkgpb.v1.FrostRound1Msg + (*FrostRound2Cast)(nil), // 4: dkg.dkgpb.v1.FrostRound2Cast + (*FrostRound2Msg)(nil), // 5: dkg.dkgpb.v1.FrostRound2Msg +} +var file_dkg_dkgpb_v1_frost_proto_depIdxs = []int32{ + 0, // 0: dkg.dkgpb.v1.FrostRound1Cast.key:type_name -> dkg.dkgpb.v1.FrostMsgKey + 0, // 1: dkg.dkgpb.v1.ShamirShare.key:type_name -> dkg.dkgpb.v1.FrostMsgKey + 1, // 2: dkg.dkgpb.v1.FrostRound1Msg.casts:type_name -> dkg.dkgpb.v1.FrostRound1Cast + 2, // 3: dkg.dkgpb.v1.FrostRound1Msg.p2ps:type_name -> dkg.dkgpb.v1.ShamirShare + 0, // 4: dkg.dkgpb.v1.FrostRound2Cast.key:type_name -> dkg.dkgpb.v1.FrostMsgKey + 4, // 5: dkg.dkgpb.v1.FrostRound2Msg.casts:type_name -> dkg.dkgpb.v1.FrostRound2Cast + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_dkg_dkgpb_v1_frost_proto_init() } +func file_dkg_dkgpb_v1_frost_proto_init() { + if File_dkg_dkgpb_v1_frost_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_dkg_dkgpb_v1_frost_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FrostMsgKey); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dkg_dkgpb_v1_frost_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FrostRound1Cast); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dkg_dkgpb_v1_frost_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ShamirShare); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dkg_dkgpb_v1_frost_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FrostRound1Msg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dkg_dkgpb_v1_frost_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FrostRound2Cast); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dkg_dkgpb_v1_frost_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FrostRound2Msg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_dkg_dkgpb_v1_frost_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_dkg_dkgpb_v1_frost_proto_goTypes, + DependencyIndexes: file_dkg_dkgpb_v1_frost_proto_depIdxs, + MessageInfos: file_dkg_dkgpb_v1_frost_proto_msgTypes, + }.Build() + File_dkg_dkgpb_v1_frost_proto = out.File + file_dkg_dkgpb_v1_frost_proto_rawDesc = nil + file_dkg_dkgpb_v1_frost_proto_goTypes = nil + file_dkg_dkgpb_v1_frost_proto_depIdxs = nil +} diff --git a/dkg/dkgpb/v1/frost.proto b/dkg/dkgpb/v1/frost.proto new file mode 100644 index 000000000..151a44d32 --- /dev/null +++ b/dkg/dkgpb/v1/frost.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; + +package dkg.dkgpb.v1; + +option go_package = "github.com/obolnetwork/charon/dkg/dkgpb/v1"; + +message FrostMsgKey { // dkg.msgKey + uint32 val_idx = 1; + uint32 source_id = 2; + uint32 target_id = 3; +} + +message FrostRound1Cast { + FrostMsgKey key = 1; + bytes wi = 2; + bytes ci = 3; + repeated bytes commitments = 4; +} + +message ShamirShare { + FrostMsgKey key = 1; + uint32 id = 2; + bytes value = 3; +} + +message FrostRound1Msg { + repeated FrostRound1Cast casts = 1; + repeated ShamirShare p2ps = 2; +} + +message FrostRound2Cast { + FrostMsgKey key = 1; + bytes verification_key = 2; + bytes vk_share = 3; +} + +message FrostRound2Msg { + repeated FrostRound2Cast casts = 1; +} diff --git a/dkg/frost.go b/dkg/frost.go index 09a48e456..6af7563f9 100644 --- a/dkg/frost.go +++ b/dkg/frost.go @@ -26,9 +26,12 @@ import ( "github.com/obolnetwork/charon/app/errors" ) +var curve = curves.BLS12381G1() + // msgKey identifies the source and target nodes and validator index the message belongs to. type msgKey struct { // ValIdx identifies the distributed validator (Ith parallel participant) the message belongs to. + // It is 0-indexed. ValIdx uint32 // SourceID identifies the source node/participant ID of the message. @@ -54,7 +57,6 @@ type fTransport interface { // runFrostParallel runs numValidators Frost DKG processes in parallel (sharing transport rounds) // and returns a list of shares (one for each distributed validator). - func runFrostParallel(ctx context.Context, tp fTransport, numValidators, numNodes, threshold, shareIdx uint32, dgkCtx string) ([]share, error) { validators, err := newFrostParticipants(numValidators, numNodes, threshold, shareIdx, dgkCtx) if err != nil { @@ -81,7 +83,7 @@ func runFrostParallel(ctx context.Context, tp fTransport, numValidators, numNode return nil, errors.Wrap(err, "transport round 2") } - return makeShares(validators, castR2Result) + return makeShares(validators, castR2Result, shareIdx) } // newFrostParticipant returns multiple frost dkg participants (one for each parallel validator). @@ -95,18 +97,18 @@ func newFrostParticipants(numValidators, numNodes, threshold, shareIdx uint32, d } resp := make(map[uint32]*frost.DkgParticipant) - for i := uint32(0); i < numValidators; i++ { + for vIdx := uint32(0); vIdx < numValidators; vIdx++ { p, err := frost.NewDkgParticipant( shareIdx, threshold, dgkCtx, - curves.BLS12381G1(), + curve, otherIDs...) if err != nil { return nil, errors.Wrap(err, "new participant") } - resp[i] = p + resp[vIdx] = p } return resp, nil @@ -152,33 +154,7 @@ func round2( ) (map[msgKey]frost.Round2Bcast, error) { castResults := make(map[msgKey]frost.Round2Bcast) for vIdx, v := range validators { - // Extract vIdx'th validator round 2 inputs. - var ( - castMap = make(map[uint32]*frost.Round1Bcast) - shareMap = make(map[uint32]*sharing.ShamirShare) - ) - for key, cast := range castR1 { - if key.ValIdx != vIdx { - continue - } - if key.TargetID != v.Id { - continue - } - cast := cast // Copy loop variable - castMap[key.SourceID] = &cast - } - for key, share := range p2pR1 { - if key.ValIdx != vIdx { - continue - } - if key.TargetID != v.Id { - continue - } - share := share // Copy loop variable - shareMap[key.SourceID] = &share - } - - castR2, err := v.Round2(castMap, shareMap) + castR2, err := v.Round2(getRound2Inputs(castR1, p2pR1, vIdx, v.Id)) if err != nil { return nil, errors.Wrap(err, "exec round 2") } @@ -193,15 +169,50 @@ func round2( return castResults, nil } -// makeShares returns a slice of shares (one for each validator) from the DKG participants and round 2 results. -func makeShares(validators map[uint32]*frost.DkgParticipant, r2Result map[msgKey]frost.Round2Bcast) ([]share, error) { - // Get our ID from any validator (they all have our ID). - targetID := validators[0].Id +// getRound2Inputs returns the round 2 inputs of the vIdx'th validator. +func getRound2Inputs( + castR1 map[msgKey]frost.Round1Bcast, + p2pR1 map[msgKey]sharing.ShamirShare, + vIdx, targetID uint32, +) (map[uint32]*frost.Round1Bcast, map[uint32]*sharing.ShamirShare) { + castMap := make(map[uint32]*frost.Round1Bcast) + for key, cast := range castR1 { + if key.ValIdx != vIdx { + continue + } + if key.TargetID != targetID { + continue + } + cast := cast // Copy loop variable + castMap[key.SourceID] = &cast + } + shareMap := make(map[uint32]*sharing.ShamirShare) + for key, share := range p2pR1 { + if key.ValIdx != vIdx { + continue + } + if key.TargetID != targetID { + continue + } + share := share // Copy loop variable + shareMap[key.SourceID] = &share + } + + return castMap, shareMap +} + +// makeShares returns a slice of shares (one for each validator) from the DKG participants and round 2 results. +func makeShares( + validators map[uint32]*frost.DkgParticipant, + r2Result map[msgKey]frost.Round2Bcast, + targetID uint32, +) ([]share, error) { // Get set of public shares for each validator. pubShares := make(map[uint32]map[uint32]*bls_sig.PublicKey) // map[ValIdx]map[SourceID]*bls_sig.PublicKey for key, result := range r2Result { if key.TargetID != targetID { + // Not for us. continue } pubShare, err := pointToPubKey(result.VkShare) @@ -217,6 +228,7 @@ func makeShares(validators map[uint32]*frost.DkgParticipant, r2Result map[msgKey m[key.SourceID] = pubShare } + // Construct DKG result shares. var shares []share for vIdx, v := range validators { pubkey, err := pointToPubKey(v.VerificationKey) @@ -229,19 +241,17 @@ func makeShares(validators map[uint32]*frost.DkgParticipant, r2Result map[msgKey return nil, err } - vIdx := vIdx // Copy loop variable - share := share{ + shares = append(shares, share{ PubKey: pubkey, Share: secretShare, PublicShares: pubShares[vIdx], - } - - shares = append(shares, share) + }) } return shares, nil } +// pointToPubKey returns the point as a public key. func pointToPubKey(point curves.Point) (*bls_sig.PublicKey, error) { pk := new(bls_sig.PublicKey) err := pk.UnmarshalBinary(point.ToAffineCompressed()) diff --git a/dkg/frostp2p.go b/dkg/frostp2p.go new file mode 100644 index 000000000..1bbd51a8e --- /dev/null +++ b/dkg/frostp2p.go @@ -0,0 +1,398 @@ +// Copyright © 2022 Obol Labs Inc. +// +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program. If not, see . + +package dkg + +import ( + "context" + "fmt" + "io" + + "github.com/coinbase/kryptology/pkg/core/curves" + "github.com/coinbase/kryptology/pkg/dkg/frost" + "github.com/coinbase/kryptology/pkg/sharing" + "github.com/golang/protobuf/proto" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/protocol" + + "github.com/obolnetwork/charon/app/errors" + "github.com/obolnetwork/charon/app/log" + "github.com/obolnetwork/charon/app/z" + pb "github.com/obolnetwork/charon/dkg/dkgpb/v1" + "github.com/obolnetwork/charon/p2p" +) + +// newFrostP2P returns a p2p frost transport implementation. +func newFrostP2P(ctx context.Context, tcpNode host.Host, peers map[uint32]peer.ID, clusterID string) *frostP2P { + var ( + round1Recv = make(chan *pb.FrostRound1Msg, len(peers)) + round2Recv = make(chan *pb.FrostRound2Msg, len(peers)) + dedupRound1 = make(map[peer.ID]bool) + dedupRound2 = make(map[peer.ID]bool) + knownPeers = make(map[peer.ID]bool) + ) + + for _, id := range peers { + knownPeers[id] = true + } + + tcpNode.SetStreamHandler(round1Protocol(clusterID), func(s network.Stream) { + defer s.Close() + + b, err := io.ReadAll(s) + if err != nil { + log.Error(ctx, "Read round 1 wire", err) + return + } + msg := new(pb.FrostRound1Msg) + if err := proto.Unmarshal(b, msg); err != nil { + log.Error(ctx, "Unmarshal round 1 proto", err) + return + } + + pID := s.Conn().RemotePeer() + if !knownPeers[pID] { + log.Warn(ctx, "Ignoring unknown round 1 peer", nil, z.Any("peer", p2p.ShortID(pID))) + return + } else if dedupRound1[pID] { + log.Debug(ctx, "Ignoring duplicate round 1 message", z.Any("peer", p2p.ShortID(pID))) + return + } + dedupRound1[pID] = true + + round1Recv <- msg + }) + + tcpNode.SetStreamHandler(round2Protocol(clusterID), func(s network.Stream) { + defer s.Close() + + b, err := io.ReadAll(s) + if err != nil { + log.Error(ctx, "Read round 2 wire", err) + return + } + msg := new(pb.FrostRound2Msg) + if err := proto.Unmarshal(b, msg); err != nil { + log.Error(ctx, "Unmarshal round 2 proto", err) + return + } + + pID := s.Conn().RemotePeer() + if !knownPeers[pID] { + log.Warn(ctx, "Ignoring unknown round 2 peer", nil, z.Any("peer", p2p.ShortID(pID))) + return + } else if dedupRound2[pID] { + log.Debug(ctx, "Ignoring duplicate round 2 message", z.Any("peer", p2p.ShortID(pID))) + return + } + dedupRound2[pID] = true + + round2Recv <- msg + }) + + return &frostP2P{ + tcpNode: tcpNode, + peers: peers, + clusterID: clusterID, + round1Recv: round1Recv, + round2Recv: round2Recv, + } +} + +// frostP2P implements frost transport. +type frostP2P struct { + tcpNode host.Host + peers map[uint32]peer.ID + clusterID string + round1Recv chan *pb.FrostRound1Msg + round2Recv chan *pb.FrostRound2Msg +} + +// Round1 returns results of all round 1 communication; the received round 1 broadcasts from all other nodes +// and the round 1 P2P sends to this node. +func (f *frostP2P) Round1(ctx context.Context, castR1 map[msgKey]frost.Round1Bcast, p2pR1 map[msgKey]sharing.ShamirShare, +) (map[msgKey]frost.Round1Bcast, map[msgKey]sharing.ShamirShare, error) { + // Build peer messages + peerMsgs := make(map[peer.ID]*pb.FrostRound1Msg) + + // Append broadcast to all peers + for key, cast := range castR1 { + for targetID, pID := range f.peers { + key := key + key.TargetID = targetID + msgpb := round1CastToProto(key, cast) + + msg, ok := peerMsgs[pID] + if !ok { + msg = new(pb.FrostRound1Msg) + } + msg.Casts = append(msg.Casts, msgpb) + peerMsgs[pID] = msg + } + } + + // Append p2p to specific peers + for key, share := range p2pR1 { + msgpb := shamirShareToProto(key, share) + pID, ok := f.peers[key.TargetID] + if !ok { + return nil, nil, errors.New("unknown target") + } + msg := peerMsgs[pID] + msg.P2Ps = append(msg.P2Ps, msgpb) + peerMsgs[pID] = msg + } + + // Send messages to all peers + for id, msg := range peerMsgs { + if id == f.tcpNode.ID() { + // Send to self + f.round1Recv <- msg + continue + } + err := f.send(ctx, id, round1Protocol(f.clusterID), msg) + if err != nil { + return nil, nil, err + } + } + + // Wait for all incoming messages + var recvs []*pb.FrostRound1Msg + for len(recvs) < len(f.peers) { + select { + case <-ctx.Done(): + return nil, nil, ctx.Err() + case msg := <-f.round1Recv: + recvs = append(recvs, msg) + } + } + + return makeRound1Response(recvs) +} + +// Round2 returns results of all round 2 communication; the received round 2 broadcasts from all other nodes. +func (f *frostP2P) Round2(ctx context.Context, castR2 map[msgKey]frost.Round2Bcast) (map[msgKey]frost.Round2Bcast, error) { + // Build peer messages + peerMsgs := make(map[peer.ID]*pb.FrostRound2Msg) + + // Append broadcast to all peers + for key, cast := range castR2 { + for targetID, pID := range f.peers { + key := key + key.TargetID = targetID + msgpb := round2CastToProto(key, cast) + + msg, ok := peerMsgs[pID] + if !ok { + msg = new(pb.FrostRound2Msg) + } + msg.Casts = append(msg.Casts, msgpb) + peerMsgs[pID] = msg + } + } + + // Send messages to all peers + for id, msg := range peerMsgs { + if id == f.tcpNode.ID() { + // Send to self + f.round2Recv <- msg + continue + } + err := f.send(ctx, id, round2Protocol(f.clusterID), msg) + if err != nil { + return nil, err + } + } + + // Wait for all incoming messages + var recvs []*pb.FrostRound2Msg + for len(recvs) < len(f.peers) { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case msg := <-f.round2Recv: + recvs = append(recvs, msg) + } + } + + return makeRound2Response(recvs) +} + +// send sends the proto msg to the peer using the protocol id. +func (f *frostP2P) send(ctx context.Context, p peer.ID, id protocol.ID, msg proto.Message) error { + s, err := f.tcpNode.NewStream(ctx, p, id) + if err != nil { + return errors.Wrap(err, "new stream") + } + defer s.Close() + + b, err := proto.Marshal(msg) + if err != nil { + return errors.Wrap(err, "marshal proto") + } + + if _, err = s.Write(b); err != nil { + return errors.Wrap(err, "marshal proto") + } + + return nil +} + +// makeRound1Response returns the round 1 response from the list of received messages. +func makeRound1Response(msgs []*pb.FrostRound1Msg) (map[msgKey]frost.Round1Bcast, map[msgKey]sharing.ShamirShare, error) { + var ( + castMap = make(map[msgKey]frost.Round1Bcast) + p2pMap = make(map[msgKey]sharing.ShamirShare) + ) + for _, msg := range msgs { + for _, castPB := range msg.Casts { + key, cast, err := round1CastFromProto(castPB) + if err != nil { + return nil, nil, err + } + castMap[key] = cast + } + for _, sharePB := range msg.P2Ps { + key, share := shamirShareFromProto(sharePB) + p2pMap[key] = share + } + } + + return castMap, p2pMap, nil +} + +// makeRound2Response returns the round 2 response from the list of received messages. +func makeRound2Response(msgs []*pb.FrostRound2Msg) (map[msgKey]frost.Round2Bcast, error) { + castMap := make(map[msgKey]frost.Round2Bcast) + for _, msg := range msgs { + for _, castPB := range msg.Casts { + key, cast, err := round2CastFromProto(castPB) + if err != nil { + return nil, err + } + castMap[key] = cast + } + } + + return castMap, nil +} + +func shamirShareToProto(key msgKey, shamir sharing.ShamirShare) *pb.ShamirShare { + return &pb.ShamirShare{ + Key: keyToProto(key), + Id: shamir.Id, + Value: shamir.Value, + } +} + +func shamirShareFromProto(shamir *pb.ShamirShare) (msgKey, sharing.ShamirShare) { + return keyFromProto(shamir.Key), sharing.ShamirShare{ + Id: shamir.Id, + Value: shamir.Value, + } +} + +func round1CastToProto(key msgKey, cast frost.Round1Bcast) *pb.FrostRound1Cast { + var commBytes [][]byte + for _, comm := range cast.Verifiers.Commitments { + commBytes = append(commBytes, comm.ToAffineCompressed()) + } + + return &pb.FrostRound1Cast{ + Key: keyToProto(key), + Wi: cast.Wi.Bytes(), + Ci: cast.Ci.Bytes(), + Commitments: commBytes, + } +} + +func round1CastFromProto(cast *pb.FrostRound1Cast) (msgKey, frost.Round1Bcast, error) { + wi, err := curve.Scalar.SetBytes(cast.Wi) + if err != nil { + return msgKey{}, frost.Round1Bcast{}, errors.Wrap(err, "decode wi scalar") + } + ci, err := curve.Scalar.SetBytes(cast.Ci) + if err != nil { + return msgKey{}, frost.Round1Bcast{}, errors.Wrap(err, "decode c1 scalar") + } + + var comms []curves.Point + for _, comm := range cast.Commitments { + c, err := curve.Point.FromAffineCompressed(comm) + if err != nil { + return msgKey{}, frost.Round1Bcast{}, errors.Wrap(err, "decode commitment") + } + + comms = append(comms, c) + } + + return keyFromProto(cast.Key), frost.Round1Bcast{ + Wi: wi, + Ci: ci, + Verifiers: &sharing.FeldmanVerifier{Commitments: comms}, + }, nil +} + +func round2CastToProto(key msgKey, cast frost.Round2Bcast) *pb.FrostRound2Cast { + return &pb.FrostRound2Cast{ + Key: keyToProto(key), + VerificationKey: cast.VerificationKey.ToAffineCompressed(), + VkShare: cast.VkShare.ToAffineCompressed(), + } +} + +func round2CastFromProto(cast *pb.FrostRound2Cast) (msgKey, frost.Round2Bcast, error) { + verificationKey, err := curve.Point.FromAffineCompressed(cast.VerificationKey) + if err != nil { + return msgKey{}, frost.Round2Bcast{}, errors.Wrap(err, "decode verification key scalar") + } + vkShare, err := curve.Point.FromAffineCompressed(cast.VkShare) + if err != nil { + return msgKey{}, frost.Round2Bcast{}, errors.Wrap(err, "decode c1 scalar") + } + + return keyFromProto(cast.Key), frost.Round2Bcast{ + VerificationKey: verificationKey, + VkShare: vkShare, + }, nil +} + +func keyToProto(key msgKey) *pb.FrostMsgKey { + return &pb.FrostMsgKey{ + ValIdx: key.ValIdx, + SourceId: key.SourceID, + TargetId: key.TargetID, + } +} + +func keyFromProto(key *pb.FrostMsgKey) msgKey { + return msgKey{ + ValIdx: key.ValIdx, + SourceID: key.SourceId, + TargetID: key.TargetId, + } +} + +// round1Protocol returns the frost round 1 protocol ID including the cluster ID. +func round1Protocol(clusterID string) protocol.ID { + return protocol.ID(fmt.Sprintf("/charon/dkg/frost/round1/1.0.0/%s", clusterID)) +} + +// round2Protocol returns the frost round 2 protocol ID including the cluster ID. +func round2Protocol(clusterID string) protocol.ID { + return protocol.ID(fmt.Sprintf("/charon/dkg/frost/round2/1.0.0/%s", clusterID)) +} diff --git a/dkg/transport.go b/dkg/transport.go index ce7eafa89..dcccf6f62 100644 --- a/dkg/transport.go +++ b/dkg/transport.go @@ -32,14 +32,14 @@ import ( "github.com/obolnetwork/charon/p2p" ) -type p2pTransport struct { +type keycastP2P struct { tcpNode host.Host peers []p2p.Peer clusterID string } // ServeShares serves the dealer shares to other nodes on request. It returns when the context is closed. -func (t p2pTransport) ServeShares(ctx context.Context, handler func(nodeIdx int) (msg []byte, err error)) { +func (t keycastP2P) ServeShares(ctx context.Context, handler func(nodeIdx int) (msg []byte, err error)) { t.tcpNode.SetStreamHandler(getProtocol(t.clusterID), func(s network.Stream) { defer s.Close() @@ -76,7 +76,7 @@ func (t p2pTransport) ServeShares(ctx context.Context, handler func(nodeIdx int) } // GetShares returns the shares requested from the dealer or a context error. It retries all other errors. -func (t p2pTransport) GetShares(ctx context.Context, _ int) ([]byte, error) { +func (t keycastP2P) GetShares(ctx context.Context, _ int) ([]byte, error) { for { resp, err := getSharesOnce(ctx, t.tcpNode, t.peers[0].ID, t.clusterID) if ctx.Err() != nil { @@ -110,5 +110,5 @@ func getSharesOnce(ctx context.Context, tcpNode host.Host, dealer peer.ID, clust // getProtocol returns the protocol ID including the cluster ID. func getProtocol(clusterID string) protocol.ID { - return protocol.ID(fmt.Sprintf("/charon/dealer_dkg/1.0.0/%s", clusterID)) + return protocol.ID(fmt.Sprintf("/charon/dkg/keycast/1.0.0/%s", clusterID)) }