Adding identification of aborts per section 4.1 of the paper. A pair of ECDSA keys is created in round 1 for player authentication. It signs the Paillier public key first. It then signs the shares in round 2. In case the Feldman check fails in round 3, evidence is broadcasted. Round 4 is now split into normal logic and handling an abort. When handling the abort, an independent player (not the plaintiff, not the accused one) will re-verify the signature of the share and re-check the Feldman shares. The outcome of the abort identification may indeed blame the accused party if the Feldman check fails, or else it may blame the plaintiff for trying to frame the accused party.

This commit is contained in:
Gustavo Frederico
2020-12-11 12:52:24 -05:00
parent 3c6c33b14f
commit 09bd254909
35 changed files with 1068 additions and 235 deletions

View File

@@ -43,8 +43,8 @@ type KGRound1Message struct {
PaillierN []byte `protobuf:"bytes,2,opt,name=paillier_n,json=paillierN,proto3" json:"paillier_n,omitempty"`
AuthenticationEcdsaPublicKeyX []byte `protobuf:"bytes,3,opt,name=authentication_ecdsa_public_key_x,json=authenticationEcdsaPublicKeyX,proto3" json:"authentication_ecdsa_public_key_x,omitempty"`
AuthenticationEcdsaPublicKeyY []byte `protobuf:"bytes,4,opt,name=authentication_ecdsa_public_key_y,json=authenticationEcdsaPublicKeyY,proto3" json:"authentication_ecdsa_public_key_y,omitempty"`
AuthenticationEcdsaSigR []byte `protobuf:"bytes,5,opt,name=authentication_ecdsa_sig_r,json=authenticationEcdsaSigR,proto3" json:"authentication_ecdsa_sig_r,omitempty"`
AuthenticationEcdsaSigS []byte `protobuf:"bytes,6,opt,name=authentication_ecdsa_sig_s,json=authenticationEcdsaSigS,proto3" json:"authentication_ecdsa_sig_s,omitempty"`
AuthenticationPaillierSigR []byte `protobuf:"bytes,5,opt,name=authentication_paillier_sig_r,json=authenticationPaillierSigR,proto3" json:"authentication_paillier_sig_r,omitempty"`
AuthenticationPaillierSigS []byte `protobuf:"bytes,6,opt,name=authentication_paillier_sig_s,json=authenticationPaillierSigS,proto3" json:"authentication_paillier_sig_s,omitempty"`
NTilde []byte `protobuf:"bytes,7,opt,name=n_tilde,json=nTilde,proto3" json:"n_tilde,omitempty"`
H1 []byte `protobuf:"bytes,8,opt,name=h1,proto3" json:"h1,omitempty"`
H2 []byte `protobuf:"bytes,9,opt,name=h2,proto3" json:"h2,omitempty"`
@@ -114,16 +114,16 @@ func (x *KGRound1Message) GetAuthenticationEcdsaPublicKeyY() []byte {
return nil
}
func (x *KGRound1Message) GetAuthenticationEcdsaSigR() []byte {
func (x *KGRound1Message) GetAuthenticationPaillierSigR() []byte {
if x != nil {
return x.AuthenticationEcdsaSigR
return x.AuthenticationPaillierSigR
}
return nil
}
func (x *KGRound1Message) GetAuthenticationEcdsaSigS() []byte {
func (x *KGRound1Message) GetAuthenticationPaillierSigS() []byte {
if x != nil {
return x.AuthenticationEcdsaSigS
return x.AuthenticationPaillierSigS
}
return nil
}
@@ -356,13 +356,174 @@ func (x *KGRound3Message) GetProofXiT() []byte {
return nil
}
type VSSShareWithAuthSigMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
VssThreshold uint32 `protobuf:"varint,1,opt,name=vss_threshold,json=vssThreshold,proto3" json:"vss_threshold,omitempty"`
VssId []byte `protobuf:"bytes,2,opt,name=vss_id,json=vssId,proto3" json:"vss_id,omitempty"`
VssSigma []byte `protobuf:"bytes,3,opt,name=vss_sigma,json=vssSigma,proto3" json:"vss_sigma,omitempty"`
AccusedParty uint32 `protobuf:"varint,4,opt,name=accused_party,json=accusedParty,proto3" json:"accused_party,omitempty"`
AuthSigPk *common.ECPoint `protobuf:"bytes,5,opt,name=auth_sig_pk,json=authSigPk,proto3" json:"auth_sig_pk,omitempty"`
AuthEcdsaSignatureR []byte `protobuf:"bytes,6,opt,name=authEcdsaSignature_r,json=authEcdsaSignatureR,proto3" json:"authEcdsaSignature_r,omitempty"`
AuthEcdsaSignatureS []byte `protobuf:"bytes,7,opt,name=authEcdsaSignature_s,json=authEcdsaSignatureS,proto3" json:"authEcdsaSignature_s,omitempty"`
KGDj [][]byte `protobuf:"bytes,8,rep,name=KGDj,proto3" json:"KGDj,omitempty"`
}
func (x *VSSShareWithAuthSigMessage) Reset() {
*x = VSSShareWithAuthSigMessage{}
if protoimpl.UnsafeEnabled {
mi := &file_protob_ecdsa_keygen_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *VSSShareWithAuthSigMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VSSShareWithAuthSigMessage) ProtoMessage() {}
func (x *VSSShareWithAuthSigMessage) ProtoReflect() protoreflect.Message {
mi := &file_protob_ecdsa_keygen_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 VSSShareWithAuthSigMessage.ProtoReflect.Descriptor instead.
func (*VSSShareWithAuthSigMessage) Descriptor() ([]byte, []int) {
return file_protob_ecdsa_keygen_proto_rawDescGZIP(), []int{4}
}
func (x *VSSShareWithAuthSigMessage) GetVssThreshold() uint32 {
if x != nil {
return x.VssThreshold
}
return 0
}
func (x *VSSShareWithAuthSigMessage) GetVssId() []byte {
if x != nil {
return x.VssId
}
return nil
}
func (x *VSSShareWithAuthSigMessage) GetVssSigma() []byte {
if x != nil {
return x.VssSigma
}
return nil
}
func (x *VSSShareWithAuthSigMessage) GetAccusedParty() uint32 {
if x != nil {
return x.AccusedParty
}
return 0
}
func (x *VSSShareWithAuthSigMessage) GetAuthSigPk() *common.ECPoint {
if x != nil {
return x.AuthSigPk
}
return nil
}
func (x *VSSShareWithAuthSigMessage) GetAuthEcdsaSignatureR() []byte {
if x != nil {
return x.AuthEcdsaSignatureR
}
return nil
}
func (x *VSSShareWithAuthSigMessage) GetAuthEcdsaSignatureS() []byte {
if x != nil {
return x.AuthEcdsaSignatureS
}
return nil
}
func (x *VSSShareWithAuthSigMessage) GetKGDj() [][]byte {
if x != nil {
return x.KGDj
}
return nil
}
//
// Represents a BROADCAST message sent to each party during Round 3 of the ECDSA TSS keygen protocol
// when in abort mode.
type KGRound3MessageAbortMode struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PlaintiffParty uint32 `protobuf:"varint,1,opt,name=plaintiff_party,json=plaintiffParty,proto3" json:"plaintiff_party,omitempty"`
SuspiciousVsss []*VSSShareWithAuthSigMessage `protobuf:"bytes,2,rep,name=suspicious_vsss,json=suspiciousVsss,proto3" json:"suspicious_vsss,omitempty"`
}
func (x *KGRound3MessageAbortMode) Reset() {
*x = KGRound3MessageAbortMode{}
if protoimpl.UnsafeEnabled {
mi := &file_protob_ecdsa_keygen_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *KGRound3MessageAbortMode) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*KGRound3MessageAbortMode) ProtoMessage() {}
func (x *KGRound3MessageAbortMode) ProtoReflect() protoreflect.Message {
mi := &file_protob_ecdsa_keygen_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 KGRound3MessageAbortMode.ProtoReflect.Descriptor instead.
func (*KGRound3MessageAbortMode) Descriptor() ([]byte, []int) {
return file_protob_ecdsa_keygen_proto_rawDescGZIP(), []int{5}
}
func (x *KGRound3MessageAbortMode) GetPlaintiffParty() uint32 {
if x != nil {
return x.PlaintiffParty
}
return 0
}
func (x *KGRound3MessageAbortMode) GetSuspiciousVsss() []*VSSShareWithAuthSigMessage {
if x != nil {
return x.SuspiciousVsss
}
return nil
}
var File_protob_ecdsa_keygen_proto protoreflect.FileDescriptor
var file_protob_ecdsa_keygen_proto_rawDesc = []byte{
0x0a, 0x19, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x2f, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x6b,
0x65, 0x79, 0x67, 0x65, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0xc3, 0x04, 0x0a, 0x0f, 0x4b, 0x47, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x31, 0x4d, 0x65, 0x73,
0x22, 0xcf, 0x04, 0x0a, 0x0f, 0x4b, 0x47, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x31, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65,
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x69, 0x6c, 0x6c, 0x69, 0x65, 0x72,
@@ -376,55 +537,84 @@ var file_protob_ecdsa_keygen_proto_rawDesc = []byte{
0x65, 0x63, 0x64, 0x73, 0x61, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79,
0x5f, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,
0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x63, 0x64, 0x73, 0x61, 0x50, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x59, 0x12, 0x3b, 0x0a, 0x1a, 0x61, 0x75, 0x74, 0x68, 0x65,
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x63, 0x64, 0x73, 0x61, 0x5f,
0x73, 0x69, 0x67, 0x5f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x61, 0x75, 0x74,
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x63, 0x64, 0x73, 0x61,
0x53, 0x69, 0x67, 0x52, 0x12, 0x3b, 0x0a, 0x1a, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x63, 0x64, 0x73, 0x61, 0x5f, 0x73, 0x69, 0x67,
0x5f, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,
0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x63, 0x64, 0x73, 0x61, 0x53, 0x69, 0x67,
0x53, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x5f, 0x74, 0x69, 0x6c, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x06, 0x6e, 0x54, 0x69, 0x6c, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x68, 0x31,
0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x68, 0x31, 0x12, 0x0e, 0x0a, 0x02, 0x68, 0x32,
0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x68, 0x32, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x6c,
0x6e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x31, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09,
0x64, 0x6c, 0x6e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x31, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x6c, 0x6e,
0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x32, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x64,
0x6c, 0x6e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x32, 0x12, 0x2d, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x6f,
0x66, 0x5f, 0x6e, 0x5f, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x18,
0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x53, 0x71, 0x75,
0x61, 0x72, 0x65, 0x46, 0x72, 0x65, 0x65, 0x12, 0x3d, 0x0a, 0x1c, 0x72, 0x61, 0x6e, 0x64, 0x5f,
0x69, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x6e, 0x5f, 0x73, 0x71, 0x75, 0x61,
0x72, 0x65, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x72,
0x61, 0x6e, 0x64, 0x49, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x53, 0x71, 0x75, 0x61,
0x72, 0x65, 0x46, 0x72, 0x65, 0x65, 0x22, 0xa2, 0x01, 0x0a, 0x10, 0x4b, 0x47, 0x52, 0x6f, 0x75,
0x6e, 0x64, 0x32, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x12, 0x14, 0x0a, 0x05, 0x73,
0x68, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72,
0x65, 0x12, 0x3b, 0x0a, 0x1a, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x63, 0x64, 0x73, 0x61, 0x5f, 0x73, 0x69, 0x67, 0x5f, 0x72, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x63, 0x64, 0x73, 0x61, 0x53, 0x69, 0x67, 0x52, 0x12, 0x3b,
0x0a, 0x1a, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x5f, 0x65, 0x63, 0x64, 0x73, 0x61, 0x5f, 0x73, 0x69, 0x67, 0x5f, 0x73, 0x18, 0x03, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x17, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x45, 0x63, 0x64, 0x73, 0x61, 0x53, 0x69, 0x67, 0x53, 0x22, 0x37, 0x0a, 0x10, 0x4b,
0x47, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x32, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x12,
0x23, 0x0a, 0x0d, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
0x6d, 0x65, 0x6e, 0x74, 0x22, 0x86, 0x01, 0x0a, 0x0f, 0x4b, 0x47, 0x52, 0x6f, 0x75, 0x6e, 0x64,
0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x69, 0x6c,
0x6c, 0x69, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c,
0x52, 0x0d, 0x70, 0x61, 0x69, 0x6c, 0x6c, 0x69, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12,
0x2e, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x78, 0x69, 0x5f, 0x61, 0x6c, 0x70, 0x68,
0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x45, 0x43, 0x50, 0x6f, 0x69, 0x6e,
0x74, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x58, 0x69, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x12,
0x1c, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x78, 0x69, 0x5f, 0x74, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x58, 0x69, 0x54, 0x42, 0x2f, 0x5a,
0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x61,
0x6e, 0x63, 0x65, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x74, 0x73, 0x73, 0x2d, 0x6c, 0x69,
0x62, 0x2f, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2f, 0x6b, 0x65, 0x79, 0x67, 0x65, 0x6e, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x59, 0x12, 0x41, 0x0a, 0x1d, 0x61, 0x75, 0x74, 0x68, 0x65,
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x69, 0x6c, 0x6c, 0x69,
0x65, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x5f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1a,
0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61,
0x69, 0x6c, 0x6c, 0x69, 0x65, 0x72, 0x53, 0x69, 0x67, 0x52, 0x12, 0x41, 0x0a, 0x1d, 0x61, 0x75,
0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x69,
0x6c, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x5f, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x1a, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x50, 0x61, 0x69, 0x6c, 0x6c, 0x69, 0x65, 0x72, 0x53, 0x69, 0x67, 0x53, 0x12, 0x17, 0x0a,
0x07, 0x6e, 0x5f, 0x74, 0x69, 0x6c, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06,
0x6e, 0x54, 0x69, 0x6c, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x68, 0x31, 0x18, 0x08, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x02, 0x68, 0x31, 0x12, 0x0e, 0x0a, 0x02, 0x68, 0x32, 0x18, 0x09, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x02, 0x68, 0x32, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x6c, 0x6e, 0x70, 0x72, 0x6f,
0x6f, 0x66, 0x5f, 0x31, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x64, 0x6c, 0x6e, 0x70,
0x72, 0x6f, 0x6f, 0x66, 0x31, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x6c, 0x6e, 0x70, 0x72, 0x6f, 0x6f,
0x66, 0x5f, 0x32, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x64, 0x6c, 0x6e, 0x70, 0x72,
0x6f, 0x6f, 0x66, 0x32, 0x12, 0x2d, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x6e, 0x5f,
0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x46,
0x72, 0x65, 0x65, 0x12, 0x3d, 0x0a, 0x1c, 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x5f,
0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x6e, 0x5f, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x5f, 0x66,
0x72, 0x65, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x72, 0x61, 0x6e, 0x64, 0x49,
0x6e, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x4e, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x46, 0x72,
0x65, 0x65, 0x22, 0xa2, 0x01, 0x0a, 0x10, 0x4b, 0x47, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x32, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x65, 0x12, 0x3b, 0x0a,
0x1a, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
0x65, 0x63, 0x64, 0x73, 0x61, 0x5f, 0x73, 0x69, 0x67, 0x5f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x17, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x45, 0x63, 0x64, 0x73, 0x61, 0x53, 0x69, 0x67, 0x52, 0x12, 0x3b, 0x0a, 0x1a, 0x61, 0x75,
0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x63, 0x64,
0x73, 0x61, 0x5f, 0x73, 0x69, 0x67, 0x5f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17,
0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x63,
0x64, 0x73, 0x61, 0x53, 0x69, 0x67, 0x53, 0x22, 0x37, 0x0a, 0x10, 0x4b, 0x47, 0x52, 0x6f, 0x75,
0x6e, 0x64, 0x32, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x12, 0x23, 0x0a, 0x0d, 0x64,
0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03,
0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74,
0x22, 0x86, 0x01, 0x0a, 0x0f, 0x4b, 0x47, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x33, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x69, 0x6c, 0x6c, 0x69, 0x65, 0x72,
0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0d, 0x70, 0x61,
0x69, 0x6c, 0x6c, 0x69, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x2e, 0x0a, 0x0e, 0x70,
0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x78, 0x69, 0x5f, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x45, 0x43, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0c, 0x70,
0x72, 0x6f, 0x6f, 0x66, 0x58, 0x69, 0x41, 0x6c, 0x70, 0x68, 0x61, 0x12, 0x1c, 0x0a, 0x0a, 0x70,
0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x78, 0x69, 0x5f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x08, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x58, 0x69, 0x54, 0x22, 0xbe, 0x02, 0x0a, 0x1a, 0x56, 0x53,
0x53, 0x53, 0x68, 0x61, 0x72, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x75, 0x74, 0x68, 0x53, 0x69,
0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x76, 0x73, 0x73, 0x5f,
0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x0c, 0x76, 0x73, 0x73, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x15, 0x0a,
0x06, 0x76, 0x73, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76,
0x73, 0x73, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x73, 0x73, 0x5f, 0x73, 0x69, 0x67, 0x6d,
0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x76, 0x73, 0x73, 0x53, 0x69, 0x67, 0x6d,
0x61, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x72,
0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x75, 0x73, 0x65,
0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x12, 0x28, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x73,
0x69, 0x67, 0x5f, 0x70, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x45, 0x43,
0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x53, 0x69, 0x67, 0x50, 0x6b,
0x12, 0x31, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x68, 0x45, 0x63, 0x64, 0x73, 0x61, 0x53, 0x69, 0x67,
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13,
0x61, 0x75, 0x74, 0x68, 0x45, 0x63, 0x64, 0x73, 0x61, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
0x72, 0x65, 0x52, 0x12, 0x31, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x68, 0x45, 0x63, 0x64, 0x73, 0x61,
0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x13, 0x61, 0x75, 0x74, 0x68, 0x45, 0x63, 0x64, 0x73, 0x61, 0x53, 0x69, 0x67, 0x6e,
0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x12, 0x12, 0x0a, 0x04, 0x4b, 0x47, 0x44, 0x6a, 0x18, 0x08,
0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x4b, 0x47, 0x44, 0x6a, 0x22, 0x89, 0x01, 0x0a, 0x18, 0x4b,
0x47, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x33, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x41, 0x62,
0x6f, 0x72, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x6c, 0x61, 0x69, 0x6e,
0x74, 0x69, 0x66, 0x66, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x0e, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x69, 0x66, 0x66, 0x50, 0x61, 0x72, 0x74, 0x79,
0x12, 0x44, 0x0a, 0x0f, 0x73, 0x75, 0x73, 0x70, 0x69, 0x63, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x76,
0x73, 0x73, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x56, 0x53, 0x53, 0x53,
0x68, 0x61, 0x72, 0x65, 0x57, 0x69, 0x74, 0x68, 0x41, 0x75, 0x74, 0x68, 0x53, 0x69, 0x67, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0e, 0x73, 0x75, 0x73, 0x70, 0x69, 0x63, 0x69, 0x6f,
0x75, 0x73, 0x56, 0x73, 0x73, 0x73, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x63, 0x68, 0x61,
0x69, 0x6e, 0x2f, 0x74, 0x73, 0x73, 0x2d, 0x6c, 0x69, 0x62, 0x2f, 0x65, 0x63, 0x64, 0x73, 0x61,
0x2f, 0x6b, 0x65, 0x79, 0x67, 0x65, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -439,21 +629,25 @@ func file_protob_ecdsa_keygen_proto_rawDescGZIP() []byte {
return file_protob_ecdsa_keygen_proto_rawDescData
}
var file_protob_ecdsa_keygen_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_protob_ecdsa_keygen_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_protob_ecdsa_keygen_proto_goTypes = []interface{}{
(*KGRound1Message)(nil), // 0: KGRound1Message
(*KGRound2Message1)(nil), // 1: KGRound2Message1
(*KGRound2Message2)(nil), // 2: KGRound2Message2
(*KGRound3Message)(nil), // 3: KGRound3Message
(*common.ECPoint)(nil), // 4: ECPoint
(*KGRound1Message)(nil), // 0: KGRound1Message
(*KGRound2Message1)(nil), // 1: KGRound2Message1
(*KGRound2Message2)(nil), // 2: KGRound2Message2
(*KGRound3Message)(nil), // 3: KGRound3Message
(*VSSShareWithAuthSigMessage)(nil), // 4: VSSShareWithAuthSigMessage
(*KGRound3MessageAbortMode)(nil), // 5: KGRound3MessageAbortMode
(*common.ECPoint)(nil), // 6: ECPoint
}
var file_protob_ecdsa_keygen_proto_depIdxs = []int32{
4, // 0: KGRound3Message.proof_xi_alpha:type_name -> ECPoint
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
6, // 0: KGRound3Message.proof_xi_alpha:type_name -> ECPoint
6, // 1: VSSShareWithAuthSigMessage.auth_sig_pk:type_name -> ECPoint
4, // 2: KGRound3MessageAbortMode.suspicious_vsss:type_name -> VSSShareWithAuthSigMessage
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_protob_ecdsa_keygen_proto_init() }
@@ -510,6 +704,30 @@ func file_protob_ecdsa_keygen_proto_init() {
return nil
}
}
file_protob_ecdsa_keygen_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*VSSShareWithAuthSigMessage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_protob_ecdsa_keygen_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*KGRound3MessageAbortMode); 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{
@@ -517,7 +735,7 @@ func file_protob_ecdsa_keygen_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_protob_ecdsa_keygen_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},

View File

@@ -51,9 +51,16 @@ type (
vs vss.Vs
shares vss.Shares
deCommitPolyG cmt.HashDeCommitment
abortTriggers []AbortTrigger
}
)
type AbortTrigger int
const (
FeldmanCheckFailure AbortTrigger = iota
)
// Exported, used in `tss` client
func NewLocalParty(
params *tss.Parameters,
@@ -141,6 +148,8 @@ func (p *LocalParty) StoreMessage(msg tss.ParsedMessage) (bool, *tss.Error) {
p.temp.kgRound2Message2s[fromPIdx] = msg
case *KGRound3Message:
p.temp.kgRound3Messages[fromPIdx] = msg
case *KGRound3MessageAbortMode:
p.temp.kgRound3Messages[fromPIdx] = msg
default: // unrecognised message, just ignore!
common.Logger.Warnf("unrecognised message ignored: %v", msg)
return false, nil

View File

@@ -14,9 +14,12 @@ import (
"math/big"
"os"
"runtime"
"strings"
"sync/atomic"
"testing"
"time"
"github.com/hashicorp/go-multierror"
"github.com/ipfs/go-log"
"github.com/stretchr/testify/assert"
@@ -168,6 +171,184 @@ func TestBadMessageCulprits(t *testing.T) {
err2.Error())
}
// The function will change the Feldman shares at the end of round 1
// making party 1 send a bad share to party 0
func SharedPartyUpdaterInjectingFeldmanError(party tss.Party, msg tss.Message, errCh chan<- *tss.Error) {
// do not send a message from this party back to itself
if party.PartyID() == msg.GetFrom() {
return
}
bz, _, err := msg.WireBytes()
if err != nil {
errCh <- party.WrapError(err)
return
}
pMsg, err := tss.ParseWireMessage(bz, msg.GetFrom(), msg.IsBroadcast())
if err != nil {
errCh <- party.WrapError(err)
return
}
// Intercepting a round 1 broadcast message and changing a share
// Making party 1 send bad share to party 0 in round 2
if "KGRound1Message" == msg.Type() && party.PartyID().Index == 1 {
if msg.GetFrom().Index != 1 && msg.IsBroadcast() {
common.Logger.Debugf("current party: %v", party.PartyID())
round := party.FirstRound().(*round1)
retries := 0
for (round.temp.shares == nil || len(round.temp.shares) < 1) && retries < 10 {
common.Logger.Debug("waiting for parties to start...")
time.Sleep(2 * time.Second)
retries++
}
// injecting a (probably) incorrect share
round.temp.shares[0].Share = new(big.Int).Add(round.temp.shares[0].Share, big.NewInt(1))
}
}
if _, err := party.Update(pMsg); err != nil {
errCh <- err
}
}
func TestIdentifiableAbortFeldmanShareFail(t *testing.T) {
setUp("info")
threshold := testThreshold
fixtures, pIDs, err := LoadKeygenTestFixtures(testParticipants)
if err != nil {
common.Logger.Info("No test fixtures were found, so the safe primes will be generated from scratch. This may take a while...",
err)
pIDs = tss.GenerateTestPartyIDs(testParticipants)
}
p2pCtx := tss.NewPeerContext(pIDs)
parties := make([]*LocalParty, 0, len(pIDs))
errCh := make(chan *tss.Error, len(pIDs))
outCh := make(chan tss.Message, len(pIDs))
endCh := make(chan LocalPartySaveData, len(pIDs))
updater := SharedPartyUpdaterInjectingFeldmanError
parties, errCh = initTheParties(pIDs, p2pCtx, threshold, fixtures, outCh, endCh, parties, errCh)
// PHASE: keygen
keygen:
for {
fmt.Printf("ACTIVE GOROUTINES: %d\n", runtime.NumGoroutine())
select {
case err := <-errCh:
// We expect an error
assert.Error(t, err, "should have thrown an abort identification error")
msg := err.Cause().Error()
assert.Truef(t, strings.Contains(msg, "abort identification - error in the Feldman share verification"),
"the error detected should have been for abort identification")
mError := err.Cause().(*multierror.Error)
assert.Greaterf(t, len(mError.Errors), 0, "too few errors returned", len(mError.Errors))
vc := (mError.Errors[0]).(*tss.VictimAndCulprit)
assert.Truef(t, vc.Victim != nil && vc.Victim.Index == 0,
"the victim should have been 0 but it was %v instead", vc.Victim.Index)
assert.Truef(t, vc.Culprit != nil && vc.Culprit.Index == 1,
"the culprit should have been 1 but it was %v instead", vc.Culprit.Index)
break keygen
case msg := <-outCh:
if handleMessage(t, msg, parties, updater, errCh) {
return
}
case _ = <-endCh:
assert.FailNow(t, "the end channel should not have returned")
break keygen
}
}
}
// When a round 2 broadcast is detected, set an abort flag to trigger
// a false Feldman check failure.
func SharedPartyUpdaterInjectingFramingError(party tss.Party, msg tss.Message, errCh chan<- *tss.Error) {
// do not send a message from this party back to itself
if party.PartyID() == msg.GetFrom() {
return
}
bz, _, err := msg.WireBytes()
if err != nil {
errCh <- party.WrapError(err)
return
}
pMsg, err := tss.ParseWireMessage(bz, msg.GetFrom(), msg.IsBroadcast())
if err != nil {
errCh <- party.WrapError(err)
return
}
// Intercepting a round 2 broadcast message
if msg.Type() == "KGRound2Message2" && msg.IsBroadcast() && msg.GetFrom().Index == 0 && party.PartyID().Index == 1 {
common.Logger.Debugf("party %s at round 2 - msg %s from %s", party.PartyID(), msg.Type(), msg.GetFrom())
tlp := party.(*LocalParty)
tlp.temp.abortTriggers = []AbortTrigger{FeldmanCheckFailure}
}
if _, err := party.Update(pMsg); err != nil {
errCh <- err
}
}
// The test will trigger a false Feldman check failure.
// The abort identification will label the case as the plaintiff trying to frame the accused player.
func TestIdentifiableAbortTryToFrame(t *testing.T) {
setUp("info")
threshold := testThreshold
fixtures, pIDs, err := LoadKeygenTestFixtures(testParticipants)
if err != nil {
common.Logger.Info("No test fixtures were found, so the safe primes will be generated from scratch. This may take a while...",
err)
pIDs = tss.GenerateTestPartyIDs(testParticipants)
}
p2pCtx := tss.NewPeerContext(pIDs)
parties := make([]*LocalParty, 0, len(pIDs))
errCh := make(chan *tss.Error, len(pIDs))
outCh := make(chan tss.Message, len(pIDs))
endCh := make(chan LocalPartySaveData, len(pIDs))
updater := SharedPartyUpdaterInjectingFramingError
parties, errCh = initTheParties(pIDs, p2pCtx, threshold, fixtures, outCh, endCh, parties, errCh)
// PHASE: keygen
keygen:
for {
fmt.Printf("ACTIVE GOROUTINES: %d\n", runtime.NumGoroutine())
select {
case err := <-errCh:
// We expect an error
assert.Error(t, err, "should have thrown an abort identification error")
msg := err.Cause().Error()
assert.Truef(t, strings.Contains(msg, "abort identification - the plaintiff party tried to frame the accused one"),
"the error detected should have been a framing case in abort identification")
mError := err.Cause().(*multierror.Error)
assert.Greaterf(t, len(mError.Errors), 0, "too few errors returned", len(mError.Errors))
vc := (mError.Errors[0]).(*tss.VictimAndCulprit)
assert.EqualValues(t, vc.Culprit.Index, 1,
"the 1st culprit should have been 1 but it was %d instead", vc.Culprit.Index)
break keygen
case msg := <-outCh:
if handleMessage(t, msg, parties, updater, errCh) {
return
}
case _ = <-endCh:
assert.FailNow(t, "the end channel should not have returned")
break keygen
}
}
}
func TestE2EConcurrentAndSaveFixtures(t *testing.T) {
setUp("info")
@@ -176,7 +357,8 @@ func TestE2EConcurrentAndSaveFixtures(t *testing.T) {
threshold := testThreshold
fixtures, pIDs, err := LoadKeygenTestFixtures(testParticipants)
if err != nil {
common.Logger.Info("No test fixtures were found, so the safe primes will be generated from scratch. This may take a while...")
common.Logger.Info("No test fixtures were found, so the safe primes will be generated from scratch. This may take a while...",
err)
pIDs = tss.GenerateTestPartyIDs(testParticipants)
}
@@ -191,22 +373,7 @@ func TestE2EConcurrentAndSaveFixtures(t *testing.T) {
startGR := runtime.NumGoroutine()
// init the parties
for i := 0; i < len(pIDs); i++ {
var P *LocalParty
params := tss.NewParameters(p2pCtx, pIDs[i], len(pIDs), threshold)
if i < len(fixtures) {
P = NewLocalParty(params, outCh, endCh, fixtures[i].LocalPreParams).(*LocalParty)
} else {
P = NewLocalParty(params, outCh, endCh).(*LocalParty)
}
parties = append(parties, P)
go func(P *LocalParty) {
if err := P.Start(); err != nil {
errCh <- err
}
}(P)
}
parties, errCh = initTheParties(pIDs, p2pCtx, threshold, fixtures, outCh, endCh, parties, errCh)
// PHASE: keygen
var ended int32
@@ -220,20 +387,8 @@ keygen:
break keygen
case msg := <-outCh:
dest := msg.GetTo()
if dest == nil { // broadcast!
for _, P := range parties {
if P.PartyID().Index == msg.GetFrom().Index {
continue
}
go updater(P, msg, errCh)
}
} else { // point-to-point!
if dest[0].Index == msg.GetFrom().Index {
t.Fatalf("party %d tried to send a message to itself (%d)", dest[0].Index, msg.GetFrom().Index)
return
}
go updater(parties[dest[0].Index], msg, errCh)
if handleMessage(t, msg, parties, updater, errCh) {
return
}
case save := <-endCh:
@@ -339,6 +494,45 @@ keygen:
}
}
func handleMessage(t *testing.T, msg tss.Message, parties []*LocalParty, updater func(party tss.Party, msg tss.Message, errCh chan<- *tss.Error), errCh chan *tss.Error) bool {
dest := msg.GetTo()
if dest == nil { // broadcast!
for _, P := range parties {
if P.PartyID().Index == msg.GetFrom().Index {
continue
}
go updater(P, msg, errCh)
}
} else { // point-to-point!
if dest[0].Index == msg.GetFrom().Index {
t.Fatalf("party %d tried to send a message to itself (%d)", dest[0].Index, msg.GetFrom().Index)
return true
}
go updater(parties[dest[0].Index], msg, errCh)
}
return false
}
func initTheParties(pIDs tss.SortedPartyIDs, p2pCtx *tss.PeerContext, threshold int, fixtures []LocalPartySaveData, outCh chan tss.Message, endCh chan LocalPartySaveData, parties []*LocalParty, errCh chan *tss.Error) ([]*LocalParty, chan *tss.Error) {
// init the parties
for i := 0; i < len(pIDs); i++ {
var P *LocalParty
params := tss.NewParameters(p2pCtx, pIDs[i], len(pIDs), threshold)
if i < len(fixtures) {
P = NewLocalParty(params, outCh, endCh, fixtures[i].LocalPreParams).(*LocalParty)
} else {
P = NewLocalParty(params, outCh, endCh).(*LocalParty)
}
parties = append(parties, P)
go func(P *LocalParty) {
if err := P.Start(); err != nil {
errCh <- err
}
}(P)
}
return parties, errCh
}
func tryWriteTestFixtureFile(t *testing.T, index int, data LocalPartySaveData) {
fixtureFileName := makeTestFixtureFilePath(index)

View File

@@ -29,6 +29,7 @@ var (
(*KGRound2Message1)(nil),
(*KGRound2Message2)(nil),
(*KGRound3Message)(nil),
(*KGRound3MessageAbortMode)(nil),
}
)
@@ -39,7 +40,7 @@ func NewKGRound1Message(
ct cmt.HashCommitment,
paillierPK *paillier.PublicKey,
authEcdsaPK *ecdsa.PublicKey,
authEcdsaSignature *ECDSASignature,
authPaillierSignature *ECDSASignature,
nTildeI, h1I, h2I, proofNSquareFree, randIntProofNSquareFree *big.Int,
dlnProof1, dlnProof2 *dlnp.Proof,
) (tss.ParsedMessage, error) {
@@ -67,8 +68,8 @@ func NewKGRound1Message(
RandIntProofNSquareFree: randIntProofNSquareFree.Bytes(),
AuthenticationEcdsaPublicKeyX: authEcdsaPK.X.Bytes(),
AuthenticationEcdsaPublicKeyY: authEcdsaPK.Y.Bytes(),
AuthenticationEcdsaSigR: authEcdsaSignature.r.Bytes(),
AuthenticationEcdsaSigS: authEcdsaSignature.s.Bytes(),
AuthenticationPaillierSigR: authPaillierSignature.r.Bytes(),
AuthenticationPaillierSigS: authPaillierSignature.s.Bytes(),
}
msg := tss.NewMessageWrapper(meta, content)
return tss.NewMessage(meta, content, msg), nil
@@ -103,9 +104,9 @@ func (m *KGRound1Message) UnmarshalAuthEcdsaPK() *ecdsa.PublicKey {
}
}
func (m *KGRound1Message) UnmarshalAuthEcdsaSignature() *ECDSASignature {
return NewECDSASignature(new(big.Int).SetBytes(m.AuthenticationEcdsaSigR),
new(big.Int).SetBytes(m.AuthenticationEcdsaSigS))
func (m *KGRound1Message) UnmarshalAuthPaillierSignature() *ECDSASignature {
return NewECDSASignature(new(big.Int).SetBytes(m.GetAuthenticationPaillierSigR()),
new(big.Int).SetBytes(m.GetAuthenticationPaillierSigS()))
}
func (m *KGRound1Message) UnmarshalNTilde() *big.Int {
@@ -251,3 +252,62 @@ func (m *KGRound3Message) UnmarshalXiProof() (*zkp.DLogProof, error) {
T: new(big.Int).SetBytes(m.GetProofXiT()),
}, nil
}
// ----- //
func NewKGRound3MessageAbortMode(
from *tss.PartyID,
suspiciousVssShareWithAuthSigMessages []*VSSShareWithAuthSigMessage,
) tss.ParsedMessage {
meta := tss.MessageRouting{
From: from,
IsBroadcast: true,
}
content := &KGRound3MessageAbortMode{SuspiciousVsss: suspiciousVssShareWithAuthSigMessages,
PlaintiffParty: uint32(from.Index)}
msg := tss.NewMessageWrapper(meta, content)
return tss.NewMessage(meta, content, msg)
}
func (m *KGRound3MessageAbortMode) ValidateBasic() bool {
if m == nil {
return false
}
for _, b := range m.GetSuspiciousVsss() {
ok := common.NonEmptyBytes(b.GetAuthSigPk().X) &&
common.NonEmptyBytes(b.GetAuthSigPk().Y) &&
common.NonEmptyBytes(b.GetVssId()) &&
common.NonEmptyBytes(b.GetVssSigma())
if !ok {
return false
}
}
return true
}
func (m *KGRound3MessageAbortMode) UnmarshalFeldmanCheckFailureEvidence() ([]*FeldmanCheckFailureEvidence, int) {
suspiciousVsss := m.GetSuspiciousVsss()
feldmanCheckFailures := make([]*FeldmanCheckFailureEvidence, len(suspiciousVsss))
for n, vsss := range suspiciousVsss {
share := vss.Share{Share: new(big.Int).SetBytes(vsss.GetVssSigma()),
ID: new(big.Int).SetBytes(vsss.GetVssId()),
Threshold: int(vsss.GetVssThreshold()),
}
pk := ecdsa.PublicKey{X: new(big.Int).SetBytes(vsss.GetAuthSigPk().GetX()),
Y: new(big.Int).SetBytes(vsss.GetAuthSigPk().GetY()),
Curve: tss.EC()}
authEcdsaSignature := ECDSASignature{r: new(big.Int).SetBytes(vsss.GetAuthEcdsaSignatureR()),
s: new(big.Int).SetBytes(vsss.GetAuthEcdsaSignatureS())}
var KGDj = make([]*big.Int, len(vsss.GetKGDj()))
for a, k := range vsss.GetKGDj() {
KGDj[a] = new(big.Int).SetBytes(k)
}
e := FeldmanCheckFailureEvidence{sigmaji: &share, authSignaturePkj: pk,
accusedPartyj: vsss.GetAccusedParty(),
KGDj: KGDj,
authEcdsaSignature: &authEcdsaSignature}
feldmanCheckFailures[n] = &e
}
return feldmanCheckFailures, int(m.GetPlaintiffParty())
}

View File

@@ -145,7 +145,7 @@ consumer:
preParams := &LocalPreParams{
PaillierSK: paiSK,
AuthEcdsaPrivateKey: authEcdsaKey,
AuthEcdsaPrivateKey: (*MarshallableEcdsaPrivateKey)(authEcdsaKey),
NTildei: NTildei,
H1i: h1i,
H2i: h2i,

View File

@@ -83,11 +83,12 @@ func (round *round1) Start() *tss.Error {
}
// Sign the Paillier PK
r, s, err := ecdsa.Sign(rand.Reader, preParams.AuthEcdsaPrivateKey, HashPaillierKey(&preParams.PaillierSK.PublicKey))
r, s, err := ecdsa.Sign(rand.Reader, (*ecdsa.PrivateKey)(preParams.AuthEcdsaPrivateKey),
HashPaillierKey(&preParams.PaillierSK.PublicKey))
if err != nil {
return round.WrapError(errors.New("ecdsa signature for authentication failed"), Pi)
}
authEcdsaSignature := NewECDSASignature(r, s)
authPaillierSignaturei := NewECDSASignature(r, s)
round.save.LocalPreParams = *preParams
round.save.NTildej[i] = preParams.NTildei
round.save.H1j[i], round.save.H2j[i] = preParams.H1i, preParams.H2i
@@ -130,8 +131,9 @@ func (round *round1) Start() *tss.Error {
// BROADCAST commitments, paillier pk + proof; round 1 message
{
msg, err := NewKGRound1Message(
round.PartyID(), cmt.C, &preParams.PaillierSK.PublicKey, &preParams.AuthEcdsaPrivateKey.PublicKey,
authEcdsaSignature,
round.PartyID(), cmt.C, &preParams.PaillierSK.PublicKey,
&preParams.AuthEcdsaPrivateKey.PublicKey,
authPaillierSignaturei,
preParams.NTildei, preParams.H1i, preParams.H2i,
proofNSquareFree, randIntProofNSquareFreei, dlnProof1, dlnProof2)
if err != nil {

View File

@@ -40,12 +40,14 @@ func (round *round2) Start() *tss.Error {
wg := new(sync.WaitGroup)
for j, msg := range round.temp.kgRound1Messages {
r1msg := msg.Content().(*KGRound1Message)
H1j, H2j, NTildej, authEcdsaPKj, authEcdsaSigj :=
paillierPKj, H1j, H2j, NTildej, authEcdsaPKj, authPaillierSigj :=
r1msg.UnmarshalPaillierPK(),
r1msg.UnmarshalH1(),
r1msg.UnmarshalH2(),
r1msg.UnmarshalNTilde(),
r1msg.UnmarshalAuthEcdsaPK(),
r1msg.UnmarshalAuthEcdsaSignature()
r1msg.UnmarshalAuthPaillierSignature()
if H1j.Cmp(H2j) == 0 {
return round.WrapError(errors.New("h1j and h2j were equal for this party"), msg.GetFrom())
}
@@ -85,14 +87,14 @@ func (round *round2) Start() *tss.Error {
wg.Done()
}(j, msg, r1msg, NTildej)
// Signing the share
// Verify the Paillier PK with the authentication PK and sign the share
go func(j int, msg tss.ParsedMessage) {
hash := HashPaillierKey(round.save.PaillierPKs[j])
verifies := ecdsa.Verify(authEcdsaPKj, hash, authEcdsaSigj.r, authEcdsaSigj.s)
verifies := ecdsa.Verify(authEcdsaPKj, HashPaillierKey(paillierPKj), authPaillierSigj.r, authPaillierSigj.s)
if !verifies {
authSignaturesFailCulprits[j] = msg.GetFrom()
} else {
r, s, err := ecdsa.Sign(rand.Reader, round.save.AuthEcdsaPrivateKey, HashShare(round.temp.shares[j]))
r, s, err := ecdsa.Sign(rand.Reader, (*ecdsa.PrivateKey)(round.save.AuthEcdsaPrivateKey),
HashShare(round.temp.shares[j]))
authSignatures[j] = NewECDSASignature(r, s)
if err != nil {
authSignaturesFailCulprits[j] = msg.GetFrom()
@@ -141,7 +143,7 @@ func (round *round2) Start() *tss.Error {
r1msg.UnmarshalNTilde(),
r1msg.UnmarshalCommitment()
round.save.PaillierPKs[j] = paillierPK // used in round 4
round.save.AuthenticationPKs[j] = authEcdsaPKj
round.save.AuthenticationPKs[j] = (*MarshallableEcdsaPublicKey)(authEcdsaPKj)
round.save.NTildej[j] = NTildej
round.save.H1j[j], round.save.H2j[j] = H1j, H2j
round.temp.KGCs[j] = KGC

View File

@@ -22,6 +22,16 @@ import (
"github.com/binance-chain/tss-lib/tss"
)
// The evidence of an eventual Feldman check failure will be evaluated
// during the abort identification in round 4.
type FeldmanCheckFailureEvidence struct {
sigmaji *vss.Share
authSignaturePkj ecdsa.PublicKey
accusedPartyj uint32
KGDj []*big.Int
authEcdsaSignature *ECDSASignature
}
func (round *round3) Start() *tss.Error {
if round.started {
return round.WrapError(errors.New("round already started"))
@@ -41,8 +51,9 @@ func (round *round3) Start() *tss.Error {
// 4-11.
type vssOut struct {
unWrappedErr error
pjVs vss.Vs
unWrappedErr error
pjVs vss.Vs
feldmanCheckFailureArgs *FeldmanCheckFailureEvidence
}
chs := make([]chan vssOut, len(Ps))
for i := range chs {
@@ -64,12 +75,13 @@ func (round *round3) Start() *tss.Error {
cmtDeCmt := commitments.HashCommitDecommit{C: KGCj, D: KGDj}
ok, flatPolyGs := cmtDeCmt.DeCommit()
if !ok || flatPolyGs == nil {
ch <- vssOut{errors.New("de-commitment verify failed"), nil}
ch <- vssOut{errors.New("de-commitment verify failed"), nil,
nil}
return
}
PjVs, err := crypto.UnFlattenECPoints(tss.EC(), flatPolyGs)
if err != nil {
ch <- vssOut{err, nil}
ch <- vssOut{err, nil, nil}
return
}
r2msg1 := round.temp.kgRound2Message1s[j].Content().(*KGRound2Message1)
@@ -80,19 +92,34 @@ func (round *round3) Start() *tss.Error {
}
authEcdsaSignature := r2msg1.UnmarshalAuthEcdsaSignature()
authEcdsaSignatureOk := ecdsa.Verify(round.save.AuthenticationPKs[j], HashShare(&PjShare),
authEcdsaSignatureOk := ecdsa.Verify((*ecdsa.PublicKey)(round.save.AuthenticationPKs[j]),
HashShare(&PjShare),
authEcdsaSignature.r, authEcdsaSignature.s)
if !authEcdsaSignatureOk {
ch <- vssOut{errors.New("ecdsa signature of VSS share for authentication failed"),
nil}
nil, nil}
return
}
if ok = PjShare.Verify(round.Threshold(), PjVs); !ok {
ch <- vssOut{errors.New("vss verify failed"), nil}
if ok = PjShare.Verify(round.Threshold(), PjVs) && !round.shouldTriggerAbortInFeldmanCheck(); !ok {
// Prepare evidence to be verified during the abort identification
evidence := FeldmanCheckFailureEvidence{
sigmaji: &PjShare,
authSignaturePkj: ecdsa.PublicKey{
Curve: tss.EC(),
X: round.save.AuthenticationPKs[j].X,
Y: round.save.AuthenticationPKs[j].Y},
accusedPartyj: uint32(j),
KGDj: KGDj,
authEcdsaSignature: authEcdsaSignature,
}
ch <- vssOut{errors.New("vss verify failed"), nil,
&evidence}
return
}
// (9) handled above
ch <- vssOut{nil, PjVs}
ch <- vssOut{nil, PjVs, nil}
}(j, chs[j])
}
@@ -113,6 +140,7 @@ func (round *round3) Start() *tss.Error {
vssResults := make([]vssOut, len(Ps))
{
culprits := make([]*tss.PartyID, 0, len(Ps)) // who caused the error(s)
feldmanCheckFailures := make([]*FeldmanCheckFailureEvidence, 0)
for j, Pj := range Ps {
if j == PIdx {
continue
@@ -121,8 +149,20 @@ func (round *round3) Start() *tss.Error {
// collect culprits to error out with
if err := vssResults[j].unWrappedErr; err != nil {
culprits = append(culprits, Pj)
if vssResults[j].feldmanCheckFailureArgs != nil {
feldmanCheckFailures = append(feldmanCheckFailures, vssResults[j].feldmanCheckFailureArgs)
}
}
}
if len(feldmanCheckFailures) > 0 {
vssShareWithAuthSigMessages := prepareShareWithAuthSigMessages(feldmanCheckFailures, round.PartyID())
// BROADCAST the failed sigma and the authentication signature for the abort identification
r3msg := NewKGRound3MessageAbortMode(round.PartyID(), vssShareWithAuthSigMessages)
round.temp.kgRound3Messages[PIdx] = r3msg
round.out <- r3msg
return nil
}
var multiErr error
if len(culprits) > 0 {
for _, vssResult := range vssResults {
@@ -206,10 +246,39 @@ func (round *round3) Start() *tss.Error {
return nil
}
func prepareShareWithAuthSigMessages(feldmanCheckFailures []*FeldmanCheckFailureEvidence, partyID *tss.PartyID) []*VSSShareWithAuthSigMessage {
vssShareWithAuthSigMessages := make([]*VSSShareWithAuthSigMessage, len(feldmanCheckFailures))
for a, evidence := range feldmanCheckFailures {
ecPoint := common.ECPoint{X: evidence.authSignaturePkj.X.Bytes(), Y: evidence.authSignaturePkj.Y.Bytes()}
KGDjmsg := make([][]byte, len(evidence.KGDj))
for b, k := range evidence.KGDj {
KGDjmsg[b] = k.Bytes()
}
msg := VSSShareWithAuthSigMessage{
VssThreshold: uint32(evidence.sigmaji.Threshold),
VssId: evidence.sigmaji.ID.Bytes(),
VssSigma: evidence.sigmaji.Share.Bytes(),
AccusedParty: evidence.accusedPartyj,
AuthSigPk: &ecPoint,
KGDj: KGDjmsg,
AuthEcdsaSignatureR: evidence.authEcdsaSignature.r.Bytes(),
AuthEcdsaSignatureS: evidence.authEcdsaSignature.s.Bytes()}
vssShareWithAuthSigMessages[a] = &msg
common.Logger.Warnf("party %v is the plaintiff triggering an abort identification"+
" accusing party %v",
partyID, evidence.accusedPartyj)
}
return vssShareWithAuthSigMessages
}
func (round *round3) CanAccept(msg tss.ParsedMessage) bool {
if _, ok := msg.Content().(*KGRound3Message); ok {
return msg.IsBroadcast()
}
if _, ok := msg.Content().(*KGRound3MessageAbortMode); ok {
return msg.IsBroadcast()
}
return false
}
@@ -231,3 +300,7 @@ func (round *round3) NextRound() tss.Round {
round.started = false
return &round4{round}
}
func (round *round3) shouldTriggerAbortInFeldmanCheck() bool {
return round.shouldTriggerAbort(FeldmanCheckFailure)
}

View File

@@ -8,13 +8,7 @@ package keygen
import (
"errors"
"fmt"
"github.com/hashicorp/go-multierror"
"github.com/binance-chain/tss-lib/common"
"github.com/binance-chain/tss-lib/crypto/paillier"
"github.com/binance-chain/tss-lib/crypto/zkp"
"github.com/binance-chain/tss-lib/tss"
)
@@ -26,86 +20,24 @@ func (round *round4) Start() *tss.Error {
round.started = true
round.resetOK()
i := round.PartyID().Index
Ps := round.Parties().IDs()
PIDs := Ps.Keys()
ecdsaPub := round.save.ECDSAPub
// 1-3. (concurrent)
// r3 messages are assumed to be available and != nil in this function
r3msgs := round.temp.kgRound3Messages
type channelOut struct {
unWrappedErr error
ok bool
}
chs := make([]chan channelOut, len(r3msgs))
for i := range chs {
chs[i] = make(chan channelOut)
}
for j, msg := range round.temp.kgRound3Messages {
if j == i {
continue
}
r3msg := msg.Content().(*KGRound3Message)
go func(prf paillier.Proof, j int, ch chan<- channelOut) {
ppk := round.save.PaillierPKs[j]
ok, err := prf.Verify(ppk.N, PIDs[j], ecdsaPub)
if err != nil {
common.Logger.Error(round.WrapError(err, Ps[j]).Error())
ch <- channelOut{err, false}
return
}
ch <- channelOut{nil, ok}
}(r3msg.UnmarshalProofInts(), j, chs[j])
if zkProofxi, err := r3msg.UnmarshalXiProof(); err != nil {
common.Logger.Error("error unmarshalling the xj ZK proof for party %v", Ps[j])
return round.WrapError(fmt.Errorf("error unmarshalling the xj ZK proof for party %v", Ps[j]))
} else {
go func(prf *zkp.DLogProof, j int, ch chan<- channelOut) {
bigXj := round.save.BigXj[j]
ok := prf.Verify(bigXj)
if !ok {
err := fmt.Errorf("error in the verification the xj ZK proof for party %v", Ps[j])
common.Logger.Error(err)
ch <- channelOut{err, false}
return
}
ch <- channelOut{nil, ok}
}(zkProofxi, j, chs[j])
abortr3msgs := make([]tss.ParsedMessage, 0)
for _, m := range r3msgs {
if m.Type() == "KGRound3MessageAbortMode" {
abortr3msgs = append(abortr3msgs, m)
}
}
outResults := make([]channelOut, len(Ps))
culprits := make([]*tss.PartyID, 0, len(Ps)) // who caused the error(s)
// consume unbuffered channels (end the goroutines)
for j, ch := range chs {
if j == i {
round.ok[j] = true
continue
}
outResults[j] = <-ch
if err := outResults[j].unWrappedErr; err != nil && j < len(Ps) {
culprits = append(culprits, Ps[j])
}
round.ok[j] = outResults[j].ok
i := round.PartyID().Index
Ps := round.Parties().IDs()
if len(abortr3msgs) > 0 {
return round.startInAbortMode(i, Ps, abortr3msgs)
} else {
PIDs := Ps.Keys()
ecdsaPub := round.save.ECDSAPub
return round.startNormal(i, Ps, PIDs, ecdsaPub, r3msgs)
}
{
var multiErr error
if len(culprits) > 0 {
for _, vssResult := range outResults {
if vssResult.unWrappedErr == nil {
continue
}
multiErr = multierror.Append(multiErr, vssResult.unWrappedErr)
}
return round.WrapError(multiErr, culprits...)
}
}
round.end <- *round.save
return nil
}
func (round *round4) CanAccept(msg tss.ParsedMessage) bool {

View File

@@ -0,0 +1,127 @@
// Copyright © 2020 Swingby
//
package keygen
import (
"crypto/ecdsa"
"github.com/hashicorp/go-multierror"
"github.com/binance-chain/tss-lib/common"
"github.com/binance-chain/tss-lib/crypto"
"github.com/binance-chain/tss-lib/crypto/commitments"
"github.com/binance-chain/tss-lib/tss"
)
type FeldmanError int
// Possible errors
const (
NoError FeldmanError = iota
DecommitError
UnFlattenError
ShareVerificationError
PlaintiffTryingToFrameAccusedParty
)
func (round *round4) feldmanCheck(feldmanCheckFailureEvidence *FeldmanCheckFailureEvidence) (bool, FeldmanError) {
KGCj := round.temp.KGCs[feldmanCheckFailureEvidence.accusedPartyj]
cmtDeCmt := commitments.HashCommitDecommit{C: KGCj, D: feldmanCheckFailureEvidence.KGDj}
ok, flatPolyGs := cmtDeCmt.DeCommit()
if !ok || flatPolyGs == nil {
return false, DecommitError
}
PjVs, err := crypto.UnFlattenECPoints(tss.EC(), flatPolyGs)
if err != nil {
return false, UnFlattenError
}
var PjShare = feldmanCheckFailureEvidence.sigmaji
if ok = PjShare.Verify(round.Threshold(), PjVs); !ok {
return false, ShareVerificationError
}
return true, NoError
}
func (round *round4) startInAbortMode(i int, Ps tss.SortedPartyIDs, abortr3msgs []tss.ParsedMessage) *tss.Error {
var errorMap = map[FeldmanError]string{
DecommitError: "abort identification - error opening de-commitment",
UnFlattenError: "abort identification - error unflattening EC points from de-commitment",
ShareVerificationError: "abort identification - error in the Feldman share verification",
PlaintiffTryingToFrameAccusedParty: "abort identification - the plaintiff party tried to frame the accused one"}
type attributionOfBlame struct {
partyToBlame *tss.PartyID
victim uint32
feldmanError FeldmanError
}
common.Logger.Debugf("party %v is starting the abort identification", Ps[i])
culprits := make([]attributionOfBlame, 0)
culpritSet := make(map[*tss.PartyID]struct{})
for _, msg := range abortr3msgs {
r3msg := msg.Content().(*KGRound3MessageAbortMode)
feldmanCheckFailureEvidences, plaintiffParty := r3msg.UnmarshalFeldmanCheckFailureEvidence()
if i == plaintiffParty {
common.Logger.Debugf("party %v is the plaintiff and is excusing itself from the attribution of blame",
Ps[i])
continue
}
for _, evidence := range feldmanCheckFailureEvidences {
if i == int(evidence.accusedPartyj) {
common.Logger.Debugf("the current party %v is being accused and is excusing itself from the attribution of blame",
Ps[i])
continue
}
common.Logger.Debugf("party %v round 4 plaintiff party: %v, accused party: %v", round.PartyID(),
plaintiffParty, evidence.accusedPartyj)
authSignaturesAreEqual := len(round.save.AuthenticationPKs) > int(evidence.accusedPartyj) &&
evidence.authSignaturePkj.Equal((*ecdsa.PublicKey)(round.save.AuthenticationPKs[int(evidence.accusedPartyj)]))
authEcdsaSignatureOk := ecdsa.Verify(&evidence.authSignaturePkj, HashShare(evidence.sigmaji),
evidence.authEcdsaSignature.r, evidence.authEcdsaSignature.s)
var partyToBlame *tss.PartyID
if !authEcdsaSignatureOk || !authSignaturesAreEqual {
partyToBlame = round.Parties().IDs()[plaintiffParty]
culprits = append(culprits, attributionOfBlame{partyToBlame: partyToBlame, victim: evidence.accusedPartyj,
feldmanError: PlaintiffTryingToFrameAccusedParty})
} else {
ok, feldmanError := round.feldmanCheck(evidence)
if !ok {
partyToBlame = round.Parties().IDs()[evidence.accusedPartyj]
culprits = append(culprits, attributionOfBlame{partyToBlame: partyToBlame,
victim: uint32(plaintiffParty),
feldmanError: feldmanError})
} else {
partyToBlame = round.Parties().IDs()[plaintiffParty]
culprits = append(culprits, attributionOfBlame{partyToBlame: partyToBlame,
feldmanError: PlaintiffTryingToFrameAccusedParty})
}
}
common.Logger.Debugf("party %v, party to blame: %v", round.PartyID(), partyToBlame)
culpritSet[partyToBlame] = struct{}{}
}
}
uniqueCulprits := make([]*tss.PartyID, 0, len(culpritSet))
for aCulprit := range culpritSet {
uniqueCulprits = append(uniqueCulprits, aCulprit)
}
var multiErr error
for _, culprit := range culprits {
vc := &tss.VictimAndCulprit{Victim: Ps[culprit.victim], Culprit: culprit.partyToBlame,
Message: errorMap[culprit.feldmanError]}
multiErr = multierror.Append(multiErr, vc)
}
if len(culprits) > 0 {
return round.WrapMultiError(multiErr, Ps[culprits[0].victim], uniqueCulprits...)
} else {
return nil
}
}

View File

@@ -0,0 +1,97 @@
// Copyright © 2019 Binance
//
// This file is part of Binance. The full Binance copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.
package keygen
import (
"fmt"
"math/big"
"github.com/hashicorp/go-multierror"
"github.com/binance-chain/tss-lib/common"
"github.com/binance-chain/tss-lib/crypto"
"github.com/binance-chain/tss-lib/crypto/paillier"
"github.com/binance-chain/tss-lib/crypto/zkp"
"github.com/binance-chain/tss-lib/tss"
)
func (round *round4) startNormal(i int, Ps tss.SortedPartyIDs, PIDs []*big.Int, ecdsaPub *crypto.ECPoint,
r3msgs []tss.ParsedMessage) *tss.Error {
type channelOut struct {
unWrappedErr error
ok bool
}
chs := make([]chan channelOut, len(r3msgs))
for i := range chs {
chs[i] = make(chan channelOut)
}
for j, msg := range round.temp.kgRound3Messages {
if j == i {
continue
}
r3msg := msg.Content().(*KGRound3Message)
go func(prf paillier.Proof, j int, ch chan<- channelOut) {
ppk := round.save.PaillierPKs[j]
ok, err := prf.Verify(ppk.N, PIDs[j], ecdsaPub)
if err != nil {
common.Logger.Error(round.WrapError(err, Ps[j]).Error())
ch <- channelOut{err, false}
return
}
ch <- channelOut{nil, ok}
}(r3msg.UnmarshalProofInts(), j, chs[j])
if zkProofxi, err := r3msg.UnmarshalXiProof(); err != nil {
common.Logger.Error("error unmarshalling the xj ZK proof for party %v", Ps[j])
return round.WrapError(fmt.Errorf("error unmarshalling the xj ZK proof for party %v", Ps[j]))
} else {
go func(prf *zkp.DLogProof, j int, ch chan<- channelOut) {
bigXj := round.save.BigXj[j]
ok := prf.Verify(bigXj)
if !ok {
err := fmt.Errorf("error in the verification the xj ZK proof for party %v", Ps[j])
common.Logger.Error(err)
ch <- channelOut{err, false}
return
}
ch <- channelOut{nil, ok}
}(zkProofxi, j, chs[j])
}
}
outResults := make([]channelOut, len(Ps))
culprits := make([]*tss.PartyID, 0, len(Ps)) // who caused the error(s)
// consume unbuffered channels (end the goroutines)
for j, ch := range chs {
if j == i {
round.ok[j] = true
continue
}
outResults[j] = <-ch
if err := outResults[j].unWrappedErr; err != nil && j < len(Ps) {
culprits = append(culprits, Ps[j])
}
round.ok[j] = outResults[j].ok
}
{
var multiErr error
if len(culprits) > 0 {
for _, vssResult := range outResults {
if vssResult.unWrappedErr == nil {
continue
}
multiErr = multierror.Append(multiErr, vssResult.unWrappedErr)
}
return round.WrapError(multiErr, culprits...)
}
}
round.end <- *round.save
return nil
}

View File

@@ -86,6 +86,10 @@ func (round *base) WrapError(err error, culprits ...*tss.PartyID) *tss.Error {
return tss.NewError(err, TaskName, round.number, round.PartyID(), culprits...)
}
func (round *base) WrapMultiError(err error, victim *tss.PartyID, culprits ...*tss.PartyID) *tss.Error {
return tss.NewError(err, TaskName, round.number, victim, culprits...)
}
// ----- //
// `ok` tracks parties which have been verified by Update()
@@ -94,3 +98,15 @@ func (round *base) resetOK() {
round.ok[j] = false
}
}
func (round *base) shouldTriggerAbort(trigger AbortTrigger) bool {
if len(round.temp.abortTriggers) == 0 {
return false
}
for _, t := range round.temp.abortTriggers {
if trigger == t {
return true
}
}
return false
}

View File

@@ -9,6 +9,7 @@ package keygen
import (
"crypto/ecdsa"
"encoding/hex"
"encoding/json"
"math/big"
"github.com/binance-chain/tss-lib/common"
@@ -18,9 +19,16 @@ import (
)
type (
// We will customize the Json serialization of the public key
// used for party authentication.
// The serialization of the Koblitz curve showed problems,
// as the type does not expose a number of attributes.
MarshallableEcdsaPrivateKey ecdsa.PrivateKey
MarshallableEcdsaPublicKey ecdsa.PublicKey
LocalPreParams struct {
PaillierSK *paillier.PrivateKey // ski
AuthEcdsaPrivateKey *ecdsa.PrivateKey
AuthEcdsaPrivateKey *MarshallableEcdsaPrivateKey
NTildei,
H1i, H2i,
Alpha, Beta,
@@ -44,9 +52,9 @@ type (
NTildej, H1j, H2j []*big.Int
// public keys (Xj = uj*G for each Pj)
BigXj []*crypto.ECPoint // Xj
PaillierPKs []*paillier.PublicKey // pkj
AuthenticationPKs []*ecdsa.PublicKey // auth_yj
BigXj []*crypto.ECPoint // Xj
PaillierPKs []*paillier.PublicKey // pkj
AuthenticationPKs []*MarshallableEcdsaPublicKey // auth_yj
// the ECDSA public key
ECDSAPub *crypto.ECPoint // y
@@ -59,11 +67,13 @@ func NewLocalPartySaveData(partyCount int) (saveData LocalPartySaveData) {
saveData.H1j, saveData.H2j = make([]*big.Int, partyCount), make([]*big.Int, partyCount)
saveData.BigXj = make([]*crypto.ECPoint, partyCount)
saveData.PaillierPKs = make([]*paillier.PublicKey, partyCount)
saveData.AuthenticationPKs = make([]*MarshallableEcdsaPublicKey, partyCount)
return
}
func (preParams LocalPreParams) Validate() bool {
return preParams.PaillierSK != nil &&
preParams.AuthEcdsaPrivateKey != nil &&
preParams.NTildei != nil &&
preParams.H1i != nil &&
preParams.H2i != nil
@@ -98,6 +108,55 @@ func BuildLocalSaveDataSubset(sourceData LocalPartySaveData, sortedIDs tss.Sorte
newData.H2j[j] = sourceData.H2j[savedIdx]
newData.BigXj[j] = sourceData.BigXj[savedIdx]
newData.PaillierPKs[j] = sourceData.PaillierPKs[savedIdx]
newData.AuthenticationPKs[j] = sourceData.AuthenticationPKs[savedIdx]
}
return newData
}
func (k MarshallableEcdsaPrivateKey) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
PublicKey MarshallableEcdsaPublicKey
D *big.Int
}{
PublicKey: (MarshallableEcdsaPublicKey)(k.PublicKey),
D: k.D,
})
}
func (k *MarshallableEcdsaPrivateKey) UnmarshalJSON(b []byte) error {
// PrivateKey represents an ECDSA private key.
newKey := new(struct {
PublicKey MarshallableEcdsaPublicKey
D *big.Int
})
if err := json.Unmarshal(b, &newKey); err != nil {
return err
}
k.D = newKey.D
k.PublicKey = (ecdsa.PublicKey)(newKey.PublicKey)
return nil
}
func (k MarshallableEcdsaPublicKey) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
X, Y *big.Int
}{
X: k.X,
Y: k.Y,
})
}
func (k *MarshallableEcdsaPublicKey) UnmarshalJSON(b []byte) error {
newKey := new(struct {
X, Y *big.Int
})
if err := json.Unmarshal(b, &newKey); err != nil {
return err
}
k.X = newKey.X
k.Y = newKey.Y
k.Curve = tss.EC()
return nil
}

View File

@@ -18,8 +18,8 @@ message KGRound1Message {
bytes paillier_n = 2;
bytes authentication_ecdsa_public_key_x = 3;
bytes authentication_ecdsa_public_key_y = 4;
bytes authentication_ecdsa_sig_r = 5;
bytes authentication_ecdsa_sig_s = 6;
bytes authentication_paillier_sig_r = 5;
bytes authentication_paillier_sig_s = 6;
bytes n_tilde = 7;
bytes h1 = 8;
bytes h2 = 9;
@@ -54,3 +54,23 @@ message KGRound3Message {
ECPoint proof_xi_alpha = 2;
bytes proof_xi_t = 3;
}
message VSSShareWithAuthSigMessage {
uint32 vss_threshold = 1;
bytes vss_id = 2;
bytes vss_sigma = 3;
uint32 accused_party = 4;
ECPoint auth_sig_pk = 5;
bytes authEcdsaSignature_r = 6;
bytes authEcdsaSignature_s = 7;
repeated bytes KGDj = 8;
}
/*
* Represents a BROADCAST message sent to each party during Round 3 of the ECDSA TSS keygen protocol
* when in abort mode.
*/
message KGRound3MessageAbortMode {
uint32 plaintiff_party = 1;
repeated VSSShareWithAuthSigMessage suspicious_vsss = 2;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -19,6 +19,12 @@ type Error struct {
culprits []*PartyID
}
type VictimAndCulprit struct {
Victim *PartyID
Culprit *PartyID
Message string
}
func NewError(err error, task string, round int, victim *PartyID, culprits ...*PartyID) *Error {
return &Error{cause: err, task: task, round: round, victim: victim, culprits: culprits}
}
@@ -47,6 +53,24 @@ func (err *Error) Error() string {
return fmt.Sprintf("task %s, party %v, round %d, culprits %s: %s",
err.task, err.victim, err.round, err.culprits, err.cause.Error())
}
return fmt.Sprintf("task %s, party %v, round %d: %s",
err.task, err.victim, err.round, err.cause.Error())
if err.victim != nil {
return fmt.Sprintf("task %s, party %v, round %d: %s",
err.task, err.victim, err.round, err.cause.Error())
}
return fmt.Sprintf("task %s, round %d: %s",
err.task, err.round, err.cause.Error())
}
func (vc *VictimAndCulprit) Error() string {
message := ""
if vc.Culprit != nil {
message = fmt.Sprintf("culprit party: %s", vc.Culprit)
}
if vc.Victim != nil {
message = message + fmt.Sprintf(" victim party: %s", vc.Victim)
}
if len(vc.Message) > 0 {
message = message + " " + vc.Message
}
return message
}